spring与事务管理

时间:2021-02-21 20:29:21

就我接触到的事务,使用最多的事务管理器是JDBC事务管理器。现在就记录下在spring中是如何使用JDBC事务管理器

1)在spring中配置事务管理器

<!--  JDBC事务  -->
     < bean  id ="jdbcTransactionManager"  class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
         < property  name ="dataSource"  ref ="datasource" ></ property >
     </ bean >

 为啥要为DataSourceTransactionManager类装配dataSource Bean? 这是因为DataSourceTransactionManager是调用java.sql.Connection来管理事务的。Connection是通过DataSource获取到的。通过调用Connection.commit()来提交事务;调用Connection.rollback()来回滚事务。所以需要装配DataSource这个Bean.

 

2)了解事务的五边形:传播行为、隔离级别、只读、事务超时、事务规则

声明事务的时候,需要指明方法是否要在事务环境中运行,事务的隔离级别等等,要先了解事务的五边形:

                                  spring与事务管理

 以下是事务的五边形整理:

传播行为

Propagation_mandatory

表示方法必须在事务中运行,若事务不存在,则抛出一个异常

Propagation_nested

若当前存在一个事务,则方法会在嵌套事务中运行,如果不存在,则与propagation_required一样

Propagation_never

方法不运行在事务环境中,若存在当前事务,则抛出异常

Propagation_not_supports

方法不应该运行在事务中,若存在当前事务,方法运行时,当前事务将被挂起

Propagation_required

方法必须运行在事务中,若没有事务,则会启动一个新的事务

Propagation_required_new

方法必须运行在它自己事务中,方法运行时,若存在当前事务,事务被挂起,同时会启动一个新的事务

Propagation_supports

方法不需要事务上下文,但存在当前事务,会在事务中运行

隔离级别

Isolation_read_uncommitted

允许读取未提交的数据,会导致脏读,不可重复读,幻读

Isolation_read_committed

允许读取并发事务提交的数据。如:事务A在运行时,第一次读取到a,此时并发事务B更新了数据,然后事务A第二次读取到b,导致a与b不一样。因此可阻止脏读,可导致不可重复读,幻读

Isolation_repeatable_read

对同一字段的多次读取是一样的,除非数据是本事务修改。这样能够防止不可重复读出现;当事务A运行时,读取几行数据后,并发事务B此时插入了一些数据,此时事务A继续读取,这样A读取的数据多了一些原本不存在的记录。因此可阻止脏读,不可重复读,可导致幻读

Isolation_serializable

完全锁定事务相关表,可阻止脏读,不可重复读,幻读

只读

read_only

若对db只做读操作;可将事务声明为只读,这样db可进行只读优化;当事务启动时,若该事务声明为只读,会通知db实施只读优化;因此需要传播行为可能具有新启动事务才能有效

事务超时


超时时钟会在事务启动时开始,因此只有具备可能可动事务的传播行为才有效

回滚规则


默认情况下,事务在检查型异常时是不会回滚,只有在运行期异常才会回滚;通过设置回滚规则,可声明事务在遇到特定的异常不回滚,即使是在运行期。

 

 

 3)在xml中声明事务

① 使用<tx:advice> 声明一个事务性策略AOP通知

<!--  添加事务通知  -->
     < tx:advice  id ="txAdvice"  transaction-manager ="jdbcTransactionManager" >
         < tx:attributes >
             < tx:method  name ="save*"  propagation ="REQUIRED" />
             < tx:method  name ="*"  propagation ="SUPPORTS"  read-only ="true" />
         </ tx:attributes >
     </ tx:advice >

 以上通知表示:以save开头的方法必须运行在事务中。其他方法的运行不需要事务上下文存在,如果存在当前事务,则会在事务中运行。且声明为只读,这样当方法运行时启动一个新事务进行的是读操作, 可让db实施只读优化;

②现在只声明的是一个AOP通知,并没有指明哪些Bean是需要配置事务的。所以需要一个切点

<!--  定义AOP事务通知器,在哪些Bean上使用事务  -->
     < aop:config >
         < aop:advisor  advice-ref ="txAdvice"  pointcut ="execusion(* com.test.demo.dao.impl.*.*(..))" />
     </ aop:config >

 

4)使用注解驱动的事务

相比在xml中声明事务,使用注解驱动的事务更加简洁:

< tx:annotation-driven  transaction-manager ="jdbcTransactionManager" />

 <tx:annotation-driven>会告诉spring在spring上下文中查找使用了@Transctional注解的Bean,不管这注解是在类级别上还是方法上。对于每个使用了@Transactional注解的Bean,<tx:annotation-driven>会自动为它添加事务通知。

 

@Transactional(propagation=Propagation.SUPPORTS,readOnly= true)
public  class UserDaoAnn  implements UserDao {

    @Transactional(propagation=Propagation.REQUIRED,readOnly= false)
     public  void addUser(Monkey Monkey) {
         //  TODO Auto-generated method stub

    }

}

 类UserDaoAnn,类级别上使用了@Transactional(propagation=Propagation.SUPPORTS,readOnly=true),表示方法不需要运行在事务上下文中,并为事务声明为只读

 

方法级别上addUser,使用了@Transactional(propagation=Propagation.REQUIRED,readOnly=false),表示方法必须运行在事务中