Spring事务管理

Spring事务管理

事务

  • 含义:
    • 访问并可能更新数据库中各种数据项的一个程序执行单元(unit),是一个序列的对数据库的读/写的操作。
  • 目的:
    • 保证用户的每一次操作都是可靠的,即便出现了异常的访问情况,也不至于破坏后台数据的完整性。
    • 为数据库操作序列提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持一致性的方法。
    • 当多个应用程序在并发访问数据库时,可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰。
  • 特性:
    • 原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。
    • 一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束。
    • 隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行。
    • 持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中。

Spring事务管理

  • 方式
    • 编程式事务管理(精确控制事务边界)
    • 声明式事务管理(低耦合)
  • 事务管理器

    • DataSourceTransactionManager:用于Spring对JDBC抽象的支持,也可用于iBATIS进行持久化的场景。

      <!-- JDBC事务管理器 -->
      <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
          <!-- 属性为引用了一个id为dataSource的bean-->
          <property name="dataSource" ref="dataSource"/>
      </bean>
      

      DataSourceTransactionManager通过调用java.sql.Connection来管理事务,后者是通过DataSource获取的,通过调用连接的commit()方法来提交事务。事务失败,则调用其rollback()方法进行回滚。

    • HibernateTransactionManager:用于对Hibernate进行持久化





      sessionFactory需要装配一个Hibernate的SessionFactory。
    • JpaTransactionManager:用于对Java持久化API进行持久化
    • JtaTransactionManager:用于分布式事务,如:跨多个事务资源(一个以上数据库)

一个转账示例(伪代码)

业务层的转账方法代码

public void transferMoney(String from, String to, double money) {
    //调用持久层Dao类的相关方法
    //outMoney():转出方法   inMoney():转入方法
    accountDao.outMoney(from, money);
    accountDao.inMoney(to, money);
}   
@Test
public void testTransfer() {
    //调用业务层的转账方法
    accountService.transferMoney("lily", "lucy", 200d);
}

上边这个转账方法就必须进行事务管理,要么成功,要么失败。但是,如果

public void transferMoney(String from, String to, double money) {
    //调用持久层Dao类的相关方法
    //outMoney():转出方法   inMoney():转入方法
    accountDao.outMoney(from, money);
    int i = 10 / 0;//这里出现异常
    accountDao.inMoney(to, money);
}

转账期间出现异常时,转账失败,造成钱转出,对方却没收到的情况,so,交给事务吧!
+ 采用编程式事务管理
+ 首先,我们需要使用Spring的TransactionTemplate来添加事务边界,TransactionTemplate提供了一种回调机制。在配置文件中注入TransactionTemplate

            <!-- 配置c3p0连接池 -->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
            <property name="driverClass" value="${jdbc.driverClass}"/>
            <property name="jdbcUrl" value="${jdbc.url}"/>
            <property name="user" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
        </bean>
        <!-- 加载jdbc的属性文件 -->
        <context:property-placeholder location="classpath:db.properties"/>
        <!-- 配置Dao层类 -->
        <bean id="accountDao" class="com.mvbin.dao.AccountDaoImpl">
            <property name="dataSource" ref="dataSource"/>
        </bean>
        <!-- 配置业务层类 -->
        <bean id="accountService" class="com.mvbin.service.AccountServiceImpl">
            <property name="accountDao" ref="accountDao"/>
            <property name="transactionTemplate" ref="transactionTemplate"/>
        </bean>
        <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
            <!-- 需要注入transactionManager -->
            <property name="transactionManager" ref="transactionManager"/>
        </bean>
        <!-- JDBC事务管理器 -->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <!-- 属性为引用了一个id为dataSource的bean-->
            <property name="dataSource" ref="dataSource"/>
        </bean> 

+ 其次,修改`transferMoney()`

        public void transferMoney(final String from, final String to, final double money) {
            /*set注入transactionTemplate
             * 调用execut(),传入TransactionCallback<T>对象,匿名内部类
             * 
             */
            transactionTemplate.execute(new TransactionCallback<String>() {
                public String doInTransaction(TransactionStatus txStatus) {
                    try {
                        accountDao.outMoney(from, money);
                        int i = 10 / 0;//异常
                        accountDao.inMoney(to, money);
                    } catch (RuntimeException e) {
                        txStatus.setRollbackOnly();
                        throw e;
                    }
                    return "";
                }
            });
        }
这种就是编程式事务管理了,对程序有较大的侵入性

+ 采用声明式事务管理:通过事务属性进行定义,通过AOP框架进行实现。
+ 事务属性
+ 传播行为
+ 隔离级别
+ 回滚规则
+ 事务超时
+ 是否只读
+ 使用tx命名空间配置事务

            <!-- 配置事务:配置所需管理器,配置事务属性 -->
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <!-- 事务属性配置 -->
            <!-- 
                name: 方法名称,可用通配符进行匹配一系列方法
                isolation: 事务隔离级别
                propagation: 事务传播行为
                read-only: 事务是否只读
                timeout: 定义事务超时时间
                no-rollback-for:对于指定异常出现时不进行回滚
                rollback-for: 对于指定异常出现时进行回滚
             -->
            <tx:attributes>
                <!-- 以 transfer开头的方法需要在事务中运行-->
                <tx:method name="transfer*" propagation="REQUIRED"/>
                <!-- 其他方法,如果存在当前事务,就在事务中运行,否则不运行 -->
                <tx:method name="*" propagation="SUPPORTS"/>
            </tx:attributes>
        </tx:advice>
        <!-- 定义一个通知器 -->
        <aop:config>
            <!-- 
                advice-ref:应用一个通知
                pointcut:定义一个切面,以AspectJ切入点表达式来声明通知器适用于com.mvbin.service.AccountService接口中的所有方法
             -->
            <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.mvbin.service.AccountService.*(..))"/>
        </aop:config>

+ 通过注解驱动配置事务

            <!-- 
            配置这样一句话即可,注解驱动会检查Spring上下文中所有的Bean,并找出使用@Transactional注解
            的Bean,不管这个注解是在类上还是方法上,<tx:annotation-driven>会自动为其添加事务通知。
            通知事务的属性通过@Transactional注解的参数来定义的。
         -->
        <tx:annotation-driven transaction-manager="transactionManager"/>
业务类代码
            @Transactional(propagation=Propagation.SUPPORTS, readOnly=true)
        public class AccountServiceImpl implements AccountService {

            private AccountDaoImpl accountDao;
            private TransactionTemplate transactionTemplate;

            @Transactional(propagation=Propagation.REQUIRED, readOnly=false)
            public void transferMoney(final String from, final String to, final double money) {
            //此处省略一万行代码。。。。
            }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值