美文网首页
Spring事务管理

Spring事务管理

作者: 游牧族人 | 来源:发表于2018-05-18 09:09 被阅读83次

事务的四大特性(ACID)
1、原子性(Atomicity):
事务具有原子性的特征表现为:一个事务对数据库的操作,要么全部执行,要么全不执行。
2、一致性(Consistemcy):
事务具有一致性的特征表现为:事务提交前和提交后,数据库中数据的约束条件需要保持一致,数据库的状态保持不变。
3、隔离性(Isolation):
事务具有隔离性的特征表现为:并发执行的事务操作必须满足隔离性原则,一个事务不能影响另外的事务执行。
4、持久性(Durability):
事务具有持久性的特征表现为:事务一旦被提交,对数据库的影响是永久性的,即使数据库发生了故障,提交过的数据依然不会丢失。

事务并发可能存在的数据读取问题
丢失更新
例如:

事务A 事务B
开始事务 开始事务
查询记录,x=100 查询记录,x=100
修改记录,x=70
提交事务
修改记录,x=30
回滚事务,x=100

最后事务B对数据的修改记录就丢失了。
解决方法:乐观锁 / 悲观锁
脏读
脏读属于无效数据读取。
当一个事务对数据库中的数据做了修改,但是还没提交,这时另外的事务开始读取第一个事务没有提交的数据。
这种情况属于脏读,这时读取的数据是无效的。
幻读
当第一个事务正在对数据库进行修改操作时,比如正在修改数据表中所有数据记录中的某个数据,这时另外的事务突然对数据表插入一条数据,并且提交了事务,那么第一个执行第一个事务的用户就会发现: 嗯?我记得我更新完所有数据了啊?怎么又多出来一条我没更新的?
这种情况就是幻读。
不可重复读
不可重复读是指一个事务在过程期间执行了多次相同的数据查询,但是在查询的间隙,另外的事务修改了数据,那么查询数据的事务就会发现,多次查询出的数据结果集是不相同的。
这种情况就是不可重复读。

事务隔离级别

隔离级别(级别由低到高) 可解决的并发数据读取问题
Read uncommitted (读未提交) nothing
Read committed (读已提交) 脏读
Repeatable read (可重复读) 脏读,不可重复读
Serializable (串行化) 脏读,幻读,不可重复读

最低的级别(Read uncommitted),一般不会用到,因为他并没什么用……
最高的级别(Serializable),也很少用到,因为对于串行化的事务查询,肯定能够避免所有的数据读取问题,但是他的性能很低。

大多数数据库的事务隔离级别默认是Read committed。
Mysql数据库的事务隔离级别默认是Repeatable read。

Spring事务管理
spring并不直接实现事务管理,它配置了一系列事务管理器,使得他们把事务管理的操作交给Hibernate等持久层框架来实现。
Spring事务管理的核心接口为PlatformTransactionManager ,其中只有三个抽象方法:
getTransaction(TransactionDefinition)
commit(TransactionState)
rollback(TransactionState)。
所有的事务管理实现类必须要实现该接口并实现这三个方法,因此我们发现spring的事务管理器就是负责获取事务,提交事务并且回滚事务的。
TransactionDefinition 接口用来定义事务的一系列属性信息并提供了获取这些信息的方法。
TransactionDefinition 定义的属性:
Spring事务隔离级别:

名称 含义
ISOLATION_DEFAULT -1 Spring默认事务隔离级别,与当前数据库默认事务隔离级别相同。
ISOLATION_READ_UNCOMMITTED 1 读未提交
ISOLATION_READ_COMMITTED 2 读已提交
ISOLATION_REPEATABLE_READ 3 重复读
ISOLATION_SERIALIZABLE 4 串行化事务

Spring事务传播属性:

名称 含义
PROPAGATION_REQUIRED 0 支持当前事务,如果当前没有事务,就新建一个事务。是Spring默认的事务传播方式。
PROPAGATION_SUPPORTS 1 支持当前事务,如果当前没有事务,以非事务方式执行。
PROPAGATION_MANDATORY 2 支持当前事务,如果当前没有事务,抛出异常。
PROPAGATION_REQUIRES_NEW 3 新建事务,如果当前存在事务,则挂起当前事务。
PROPAGATION_NOT_SUPPORTED 4 以非事务方式执行,如果当前存在事务,则挂起当前事务。
PROPAGATION_NEVER 5 以非事务方式执行,如果当前存在事务,抛出异常。
PROPAGATION_NESTED 6 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,新建一个事务。

事务超时:
所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。
默认设置为底层事务系统的超时值,如果底层数据库事务系统没有设置超时值,那么就是none,没有超时限制。

事务只读:
只读事务用于客户代码只读但不修改数据的情形,只读事务用于特定情景下的优化,比如使用Hibernate的时候。
默认为读写事务。

Spring事务回滚规则:
指示spring事务管理器在什么时候提交事务,什么时候回滚事务。
默认是抛出非检查异常和错误的时候回滚事务,抛出检查异常的时候不回滚事务。我们还可以通过设置setRollbackOnly()方法设置一个事务必须回滚。

编程式事务管理:
在代码中显示调用开启事务,提交事务,回滚事务等事务处理方法的程序。
TransactionTemplate继承了DefaultTransactionDefinition,是TransactionDefinition的一个实现,TransactionDefinition是事务属性配置的入口,他可以配置事务的隔离级别,传播属性,超时时间,是否只读等事务相关属性。因为TransactionTemplate实现了TransactionDefinition接口,因此它也具有配置事务属性的能力。

<!--配置transactionManager事务管理器-->
<bean id="transactionManager" class="对应的事务管理器实现类">
    <property name="dataSource" ref="dataSource" />
</bean>
<!-- 配置transactionTemplate -->  
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">  
    <property name="transactionManager" ref="transactionManager"></property>  
    <!--定义事务隔离级别,-1表示使用数据库默认级别-->  
    <property name="readOnly" value="false"></property>  
    <property name="isolationLevelName" value="ISOLATION_DEFAULT"></property>  
    <property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"></property>  
</bean> 

// 事务管理代码
@Test
public void transactionTest(){
  //有返回值的事务
  Integer result = transactionTemplate.execute(new TransactionCallback(){
     @Override
     public Integer doInTransaction(TransactionStatus status){
        ----事务逻辑代码块----
        //status.setRollbackOnly(); 设置事务回滚
        return 1;
      }
   });

  //没有返回值的事务
   transactionTemplate.execute(new TransactionCallbackWithoutResult(){
   @Override
     public Integer doInTransactionWithoutResult(TransactionStatus status){
        ----事务逻辑代码块----
        //status.setRollbackOnly(); 设置事务回滚
        return 1;
      }
   });
}

声明式事务管理:
Spring声明式事务管理是建立在AOP基础之上的,他在需要执行的事务逻辑方法前通过切面创建一个事务,在事务逻辑结束之后再次通过切面判断进行事务的提交还是回滚。

基于tx和aop命名空间的声明式事务管理:

...
<!--配置Spring的事务管理器-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

<!--配置通知-->
<tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
        <!-- 默认的事务设置 -->
        <tx:method name=""/>
        <!-- 只读事务(所有ronly开头的方法) -->
        <tx:method name="ronly*" read-only="true"/>
        <!--其中name属性可以使用表达式进行匹配-->
    </tx:attributes>
</tx:advice>

<!--启用事务通知-->
<aop:config>
    <!-- 定义切点 -->
    <aop:pointcut expression="execution(* com.sun.Test*(..))" id="testCut"/>
    <!-- 织入->
    <aop:advisor advice-ref="txAdvice" pointcut-ref="testCut"/>
</aop:config>

基于@Transactional注解的声明式事务管理:
@Transactional可以标注在类上,类方法上和接口上。标注在接口上时,只有使用了基于接口的代理时他才会生效。标注在类方法上时,该类中的所有public方法添加事务管理。对于private和protexted方法不进行事务管理操作。标注在类方法上时,只有类方法添加事务管理。我们也可以使用在类方法上的注解覆盖在类级别上的注解。
当使用jdk代理情况下,只有在代理类外部的方法调用时才会进行事务管理,内部类的方法调用并不会调用事务管理,即使标注了@Transaction注解(cglib代理情况下任何时候都可以调用事务管理)。

    <!-- 使用annotation注解方式配置事务 -->
    <tx:annotation-driven transaction-manager="transactionManager" />

@Transactional注解参数:
1、readonly(boolean):用于指示当前事务是否为只读事务。
2、propagation(int):用于设置事务的传播行为。
3、isolation(int):用于设置数据库的事务隔离级别。
4、timeout(int):用于设置事务的超时秒数,默认-1,代表永不超时。
5、rollbackFor:用于设置需要回滚的异常类数组,当方法中抛出以下异常时进行回滚:
@Transactional(rollbackFor=RuntimeException.class)
@Transactional(rollbackFor={IOException.class,SQLException.class})
6、rollbackForClassName:用于设置需要回滚的异常类名称数组,当方法中抛出以下异常时回滚。
@Transactional(rollbackForClassName=RuntimeException)
@Transactional(rollbackForClassName={IOException,SQLException})
7、noRollbackFor:用于设置不需要回滚的异常类数组,当方法中抛出以下异常时不需要回滚。
使用方法同(5)
8、noRollbackForClassName:用于设置不需要回滚的异常类名称数组,当方法中抛出以下异常时不需要回滚。
使用方法同(6)

相关文章

网友评论

      本文标题:Spring事务管理

      本文链接:https://www.haomeiwen.com/subject/muvpdftx.html