Spring事务详解

Spring事务配置:
1.在Spring配置文件引入tx

"http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/aop 
           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
           http://www.springframework.org/schema/tx
           http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd">

2.配置基于注解的声明式事务管理
spring不负责事务的处理,把事务交给各事务处理器

  
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">  
    <property name="sessionFactory" ref="sessionFactory">property>  
bean>  
  
<tx:annotation-driven transaction-manager="txManager"/>

3.在要使用事务管理的类或者方法上增加代码@Transactional,Spring官方团队建议不要在接口使用。在类上使用@Transactional,类中的所有public方法都将使用事务

@Transactional
public class Txtest implements TestService { }

在public方法上使用@Transactional,则该方法使用事务;非public方法使用@Transactional不会报错,但也不会使用事务,相当于“白做”
如果在类上使用@Transactional,但是类中的某个方法不想使用事务,则可以使用

@Transactional
public class Txtest implements TestService {   

    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public List getAll() {
        return null;
    }   
} 
  

使用tx标签配置的拦截器
1.配置sessionFactory


<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="configLocation">
        <value>classpath:hibernate.cfg.xmlvalue>
    property>
bean>

2.配置事务管理器


<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
bean>

3.配置事务的传播性


<tx:advice id="TxAdvice" transaction-manager="transactionManager">
     <tx:attributes>
           <tx:method name="query*" read-only="true"/>
           <tx:method name="insert*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
           <tx:method name="update*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
           <tx:method name="delete*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
           <tx:method name="*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
    tx:attributes>
tx:advice>

4.AOP配置参与事务的类

<aop:config>
    <aop:pointcut id="allServiceMethod" expression="execution(* com.chillax.*.service.*.*(..))"/>
    <aop:advisor pointcut-ref="allServiceMethod" advice-ref="TxAdvice" />
aop:config>

事务的传播性
1)@Transactional(propagation=Propagation.REQUIRED):默认的spring事务传播级别,使用该级别的特点是,如果上下文中已经存在事务,那么就加入到事务中执行,如果当前上下文中不存在事务,则新建事务执行,所以这个级别通常能满足处理大多数的业务场景。
2)@Transactional(propagation=PROPAGATION_SUPPORTS):从字面意思就知道,supports(支持),该传播级别的特点是,如果上下文存在事务,则支持当前事务,加入到事务执行,如果没有事务,则使用非事务的方式执行。所以说,并非所有的包在transactionTemplate.execute中的代码都会有事务支持。这个通常是用来处理那些并非原子性的非核心业务逻辑操作,应用场景较少。
3)@Transactional(propagation=PROPAGATION_MANDATORY):该级别的事务要求上下文中必须要存在事务,否则就会抛出异常!配置该方式的传播级别是有效的控制上下文调用代码遗漏添加事务控制的保证手段。比如一段代码不能单独被调用执行,但是一旦被调用,就必须有事务包含的情况,就可以使用这个传播级别。
4)@Transactional(propagation=PROPAGATION_REQUIRES_NEW):从字面即可知道,每次都要一个新的事务,该传播级别的特点是,每次都会新建一个事务,并且同时将上下文中的事务挂起,当新建事务执行完成以后,上下文事务再恢复执行。
这是一个很有用的传播级别,举一个应用场景:现在有一个发送100个红包的操作,在发送之前,要做一些系统的初始化、验证、数据记录操作,然后发送100封红包,然后再记录发送日志,发送日志要求100%的准确,如果日志不准确,那么整个父事务逻辑需要回滚。
怎么处理整个业务需求呢?就是通过这个PROPAGATION_REQUIRES_NEW级别的事务传播控制就可以完成。发送红包的子事务不会直接影响到父事务的提交和回滚。
5)@Transactional(propagation=PROPAGATION_NOT_SUPPORTED):这个也可以从字面得知not supported(不支持),当前级别的特点是,如果上下文中存在事务,
则挂起事务,执行当前逻辑,结束后恢复上下文的事务。
这个级别有什么好处?可以帮助你将事务极可能的缩小。我们知道一个事务越大,它存在的风险也就越多。所以在处理事务的过程中,要保证尽可能的缩小范围。比如一段代码,是每次逻辑操作都必须调用的,比如循环1000次的某个非核心业务逻辑操作。这样的代码如果包在事务中,势必造成事务太大,导致出现一些难以考虑周全的异常情况。所以这个事务这个级别的传播级别就派上用场了,用当前级别的事务模板抱起来就可以了。
6)@Transactional(propagation=PROPAGATION_NEVER):该事务更严格,上面一个事务传播级别只是不支持而已,有事务就挂起,而PROPAGATION_NEVER传播级别要求上下文中不能存在事务,一旦有事务,就抛出runtime异常,强制停止执行!
7)@Transactional(propagation=PROPAGATION_NESTED):字面也可知道,nested,嵌套级别事务。该传播级别特征是,如果上下文中存在事务,则嵌套事务执行,如果不存在事务,则新建事务。

事务的隔离级别
1)@Transactional(isolation = Isolation.SERIALIZABLE):最严格的级别,事务串行执行,资源消耗最大;
2)@Transactional(isolation = Isolation.REPEATABLE_READ):保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。避免了“脏读取”和“不可重复读取”的情况,但是带来了更多的性能损失。
3)@Transactional(isolation = Isolation.READ_COMMITTED):大多数主流数据库的默认事务等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读取”,该级别适用于大多数系统。
4)@Transactional(isolation = Isolation.READ_UNCOMMITTED):保证了读取过程中不会读取到非法数据。

1:Dirty reads—读脏数据。也就是说,比如事务A的未提交(还依然缓存)的数据被事务B读走,如果事务A失败回滚,会导致事务B所读取的的数据是错误的。
2:non-repeatable reads—不可重复读。比如事务A中两处读取数据-total-的值。在第一读的时候,total是100,然后事务B就把total的数据改成200,事务A再读一次,结果就发现,total竟然就变成200了,造成事务A数据混乱。
3:phantom reads—幻象读数据。这个和non-repeatable reads相似,也是同一个事务中多次读不一致的问题。但是non-repeatable reads的不一致是因为他所要取的数据集被改变了(比如total的数据),但是phantom reads所要读的数据的不一致却不是他所要读的数据集改变,而是他的条件数据集改变。比如Select account.id where account.name=”grace”,第一次读去了6个符合条件的id,第二次读取的时候,由于事务b把一个帐号的名字由”dd”改成”grace”,结果取出来了7个数据。
不可重复读的重点是修改:同样的条件, 你读取过的数据, 再次读取出来发现值不一样了。
幻读的重点在于新增或者删除:同样的条件, 第1次和第2次读出来的记录数不一样。

常用数据库默认事务隔离级别
MYSQL:默认为REPEATABLE_READ
SQLSERVER:默认为READ_COMMITTED
ORACLE:默认为READ_COMMITTED

@Transactional注解中常用参数说明
readOnly:该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。例如:@Transactional(readOnly=true)
rollbackFor:该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如:
指定单一异常类:@Transactional(rollbackFor=RuntimeException.class);
指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class})
rollbackForClassName:该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。例如:
指定单一异常类名称:@Transactional(rollbackForClassName=”RuntimeException”);
指定多个异常类名称:@Transactional(rollbackForClassName={“RuntimeException”,”Exception”})
noRollbackFor:该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。例如:
指定单一异常类:@Transactional(noRollbackFor=RuntimeException.class);
指定多个异常类:@Transactional(noRollbackFor={RuntimeException.class, Exception.class})
noRollbackForClassName:该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。例如:
指定单一异常类名称:@Transactional(noRollbackForClassName=”RuntimeException”);
指定多个异常类名:@Transactional(noRollbackForClassName={“RuntimeException”,”Exception”})
propagation:该属性用于设置事务的传播行为,具体取值可参考上文。例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)
isolation:该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置
timeout:该属性用于设置事务的超时秒数,默认值为-1表示永不超时

你可能感兴趣的:(Spring,spring,事务)