欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

spring事务管理-事务传播与事务隔离

程序员文章站 2022-05-03 07:57:10
...
1.spring事务默认只在发生未被捕获的 runtimeexcetpion时才回滚。
如果用try catch捕获了异常,由于异常已经被捕获,不会事务回滚了。
想达到回滚的效果,解决办法有两种:
方法一:需要再catch块的最后一行加上throw new runtimeexcetpion();
     (throw new Excetpion()是不会回滚事务的,因为不是运行时异常,像空指针异常会回滚,因为是运行时异常类的子类,属于运行时异常)
方法二:或者在catch中加上TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
     手动回滚事务。

说明:事务异常回滚是可以设置的,比如在事务配置的异常回滚设置为java.lang.Exception,这时抛出java.lang.Exception异常,事务就会回滚了,不配置时默认为运行时异常:
<tx:method name="update*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
事务传播

2.事务挂起的含义: 事务挂起与事务恢复这段时间做的操作,都不会管理,commit不会提交这些改变。

3.   事务的几种传播特性


       REQUIRED:业务方法需要在一个容器里运行。如果方法运行时,已经处在一个事务中,那么加入到这个事务,否则自己新建一个新的事务。

       NOT_SUPPORTED:声明方法不需要事务。如果方法没有关联到一个事务,容器不会为他开启事务,如果方法在一个事务中被调用,该事务会被挂起,调用结束后,原先的事务会恢复执行。

       REQUIRES_NEW:不管是否存在事务,该方法总汇为自己发起一个新的事务。如果方法已经运行在一个事务中,则原有事务挂起,新的事务被创建。

       MANDATORY:该方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务。如果在没有事务的环境下被调用,容器抛出例外。

       SUPPORTS:该方法在事务中被调用,则方法成为该事务的一部分。如果方法在该事务范围外被调用,该方法就在没有事务的环境下执行。

       NEVER:该方法绝对不能在事务范围内执行。如果在就抛例外。只有该方法没有关联到任何事务,才正常执行。

       NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按REQUIRED属性执行。它使用了一个单独的事务,这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效。

       NESTED比较难理解,比如  public void a(){b();c();d();}  public void c(){} ,a方法是REQUIRED传播属性,c方法是NESTED传播属性,
                 直接调用c方法,c方法的事务相当于REQUIRED,如果调用a方法,c方法是被调用的,这时,c方法报错,只会导致c方法的改变不能提交,b d中的改变还是能提交,如果b报错 或者d方法报错,则b c d所做的改变都不能提交。



4.方法调用在service内与service之间事务创建上的区别:
   同一个service类中,方法之间的调用不会创建新的事务,即使被调用的是方法传播属性是REQUIRES_NEW,也不会创建新事务。
   不同service间方法的调用,是否创建新的事务,取决于方法的事务传播属性,比如:REQUIRED不会创建新的事务,REQUIRES_NEW会创建新的事务


5.如何保证service层间存在方法相互调用时,还能保证要么全成功,要么全失败。
解决办法:使service方法在相互调用的过程中,只有一个事务,所以将增删改都设置为REQUIRED,就不会有任何问题。配置如下

  <!-- 事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
  <property name="sessionFactory">
<ref bean="sessionFactory"></ref>
</property>
</bean>

<!--配置事务的传播特性 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*"   propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="*"  read-only="true" />
</tx:attributes>
</tx:advice> 

<!-- 那些类的哪些方法参与事务 -->
<aop:config>
<aop:pointcut id="allServiceMethod" expression="execution(* service.*.*(..))" />
<aop:advisor pointcut-ref="allServiceMethod" advice-ref="txAdvice" />
</aop:config>

事务隔离
Spring事务的隔离级别
      1. ISOLATION_DEFAULT: 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.
         另外四个与JDBC的隔离级别相对应
      2. ISOLATION_READ_UNCOMMITTED: 这是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据。
         这种隔离级别会产生脏读,不可重复读和幻像读。
     3. ISOLATION_READ_COMMITTED: 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据
     4. ISOLATION_REPEATABLE_READ: 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。
         它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
     5. ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。
        除了防止脏读,不可重复读外,还避免了幻像读。

  脏读: 指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据, 那么另外一 个事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。
不可重复读: 指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。 那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。
幻觉读: 指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及 到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样

配置示例:
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*"   propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="*"  read-only="true" isolation="READ_COMMITTED"/>
</tx:attributes>
</tx:advice>