14.spring基于编程式的事务控制【了解】

spring基于编程式的事务控制【了解】

DataSourceTransactionManager类中有个属性nestedTransactionAllowed ,表示允许【嵌套事务】,基于此原理,然后再基于切面编程(被代理方法前后增强),实现嵌套事务!

此种方式只是了解,因为这种方式写出来的事务,每个需要事务的切入点都需要这样配,通用性很不好!

一、基于编程的事务控制编写核心流程

1). 基本配置

2). 配置TransactionManager 进行事务操作的通知类

3). 配置事务模板对象

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 配置spring的ioc -->
    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
        <property name="transactionTemplate" ref="transactionTemplate"></property>
    </bean>

    <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
        <property name="queryRunner" ref="queryRunner"></property>
    </bean>

    <bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
        <constructor-arg name="ds" ref="dataSource"></constructor-arg>
    </bean>

    <!-- 配置数据源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql:///spring_01"></property>
        <property name="user" value="root"></property>
        <property name="password" value="abc123"></property>
    </bean>

    <!-- 配置TransactionManager 进行事务操作的通知类 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 配置事务模板对象 -->
    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="transactionManager"></property>
    </bean>

</beans>

4). 在需要事务的地方,使用TransactionTemplate将业务逻辑“包裹”起来

底层就是在被“包裹”的代码前后开启 嵌套事务,进行过程增强,比如取消自动提交事务、开启事务、提交事务、回滚事务,释放资源等!

package com.itheima.service.impl;

import com.itheima.dao.AccountDao;
import com.itheima.domain.Account;
import com.itheima.service.AccountService;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

import java.sql.SQLException;

public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao;
    private TransactionTemplate transactionTemplate;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
        this.transactionTemplate = transactionTemplate;
    }

    /** @事务
     * 转账业务 */
    @Override
    public boolean transfer(Integer fromId, Integer toId, Float money) throws Exception {
        // 编程式声明事务控制
        return (boolean) transactionTemplate.execute(new TransactionCallback<Object>() {
            @Override
            public Object doInTransaction(TransactionStatus transactionStatus) {
                // 1. 查询原账户余额
                Account fromMoney = null;
                try {
                    fromMoney = accountDao.queryMoney(fromId);
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }

                if (fromMoney.getMoney() < money) {
                    throw new RuntimeException("账户余额不足,无法完成转账");
                }

                // 2. 查询被转入账户的余额
                Account toMoney = null;
                try {
                    toMoney = accountDao.queryMoney(toId);
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }

                // 3. 扣除原账户的money
                try {
                    accountDao.updateMoney(fromId, fromMoney.getMoney() - money);
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }

                // 显示抛出一个异常。
                int a = 8 / 0;

                // 4. 添加被转入账户的余额
                try {
                    accountDao.updateMoney(toId, toMoney.getMoney() + money);
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
                return true;
            }
        });
    }
}

二、完整的项目代码

1). 项目结构


spring基于编程式的事务控制项目结构.png

2). domain

public class Account {
    private Integer id;
    private String name;
    private Float money;
    ... get/set/toString...

3). dao持久层

import com.itheima.domain.Account;
import java.sql.SQLException;
public interface AccountDao {

    /** 根据id查询账户的余额 */
    public Account queryMoney(Integer id) throws SQLException;

    /** 根据id更新账户的余额 */
    public int updateMoney(Integer id, Float money) throws SQLException;
}
import com.itheima.dao.AccountDao;
import com.itheima.domain.Account;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import java.sql.SQLException;
public class AccountDaoImpl implements AccountDao {

    private QueryRunner queryRunner;

    public void setQueryRunner(QueryRunner queryRunner) {
        this.queryRunner = queryRunner;
    }

    /** @事务
     * 根据id查询账户的余额,将异常显示抛出 */
    @Override
    public Account queryMoney(Integer id) throws SQLException {
        return queryRunner.query("select money from account where id = ?",
                new BeanHandler<Account>(Account.class), id);
    }

    /** @事务
     * 根据id更新账户的余额, 将异常显示抛出 */
    @Override
    public int updateMoney(Integer id, Float money) throws SQLException {
        return queryRunner.update("update account set money = ? where id = ?", money, id);
    }
}

4). service业务层

public interface AccountService {

    /** 转账业务 */
    public boolean transfer(Integer fromId, Integer toId, Float money) throws Exception;
}

实现类代码详见4). 在需要事务的地方,使用TransactionTemplate将业务逻辑“包裹”起来

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring 事务属性分析 事务管理对于企业应用而言至关重要。它保证了用户的每一次操作都是可靠的,即便出现了异常的...
    壹点零阅读 1,330评论 0 2
  • 1.数据库事务基础知识 1.1.何为数据库事务 数据库事务的4个特性 原子性:组成一个事务的多个数据库操作是一个不...
    小螺钉12138阅读 1,602评论 1 18
  • 事务管理对于企业应用来说是至关重要的,当出现异常情况时,它也可以保证数据的一致性。 Spring事务管理的两种方式...
    逐梦余生阅读 1,034评论 0 0
  • 这部分的参考文档涉及数据访问和数据访问层和业务或服务层之间的交互。 Spring的综合事务管理支持覆盖很多细节,然...
    竹天亮阅读 1,053评论 0 0
  • 对大多数Java开发者来说,Spring事务管理是Spring应用中最常用的功能,使用也比较简单。本文主要从三个方...
    sherlockyb阅读 3,238评论 0 18