spring源码之事务上篇

 

前言

本篇之前,已经写过关于AOP的源码分析,在此基础上来阅读事务的源码是比较清晰的。另外,需要对数据库有一定的了解,我们所说是事务一般指的都是狭义的事务,即数据库事务。文中没有特别指出的数据库,均指的是mysql,后面再来写一篇关于mysql的锁和事务的文章。

概述

事务指的是一个程序执行单元,这个执行单元要么成功,要么失败,绝对不允许存在中间状态,它是我们恢复和并发控制的基本单位。

知识点

学习spring事务时,我们一般会从事务特性、隔离级别、传播行为三个进行分析

  • 事务的四个特性

  学习事务时,一般会拿转钱来做说明,这里也拿张三向李四转100元来说明,这个过程分为两步,张三帐户减100,李四帐户加100.

  事务的四个特性(ACID)

    • 原子性:事务由一系列操作来完成,要么保证这一系列操作同时起作用,要到全部不起作用。以例子来说,张三减100,李四加100。要同时成功或失败,不然就不满足原子性。
    • 一致性:从一个数据库状态转变到别一个状态。一致性和原子性,经常会让人认为是一个东西,个人理解一致性是从状态变化的角度来看问题,即结果,而原子性更偏向于过程来看问题。以例子来说,这里的状态就是转帐前后,张三和李四总的资金数没有发生变化。可以说原子性保证了一致性。
    • 隔离性:并发执行的事务是相互隔离的。以例子来说,假设张三帐户有1000元,他同时向王五也转帐100,转给李四时,他的户头上扣了100,就只有900了,转给王五是,再扣100,只有800了,如果李四收钱时出了问题,而王五收钱成功,这时把800写入到数据库。张三就会很生气,因为帐户被多扣了100。这个就是有问题的。
    • 持久性:事务完成,不论发生什么,都不会对操作有影响。
  • mysql数据库的隔离级别

  事务级别越高,数据的完整性和一致性越好,但对并发性能的影响也越大。innodb默认REPEATABLE READ。

  分为以下四个级别,每个级别都是来解决特点问题的

    • READ UNCOMMITTED,写成READ UNCOMMITTED DATA更合适,读到未提交的数据,会有脏读
      • 脏读:事务一修改了数据但没有提交,事务二来读到这个未提交的数据,假设后面事务一回滚了,那么事务二就读取了脏数据
    • READ COMMITTED,·写成READ UNCOMMITTED DATA更合适,读到已提交的数据,避免了脏读,会有不可重复读
      • 不可重复读:事务一修改了数据但没有提交,事务二来读这个数据,读取是未提交的数据,这个时候事务一提交成功了,事务二再来读这个数据,读到是事务一已经提交的数据。那么,事务二再次读取到的数据是不一样的
    • REPEATABLE READ:重复读,避免了脏读、不可以重复读,会有幻读
      • 幻读:理解为幻行更好些,事务一读了一个范围的数据,事务二修改了这个范围的数据并提交,事务一再来读这个范围的数据,两次结果不一致
    • SERIALIZABLE:串行读,事务一个个执行,避免了脏读、不可重复读,幻读 
  • spring中的隔离级别

  和数据库对应四个级别,再加上默认级别,共五个

//TransactionDefinition的属性
int ISOLATION_DEFAULT = -1;
int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;
int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;
int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;
//Connection的属性
int TRANSACTION_READ_UNCOMMITTED = 1;
int TRANSACTION_READ_COMMITTED = 2;
int TRANSACTION_REPEATABLE_READ = 4;
int TRANSACTION_SERIALIZABLE = 8;
  • spring中的传播属性

  服务接口方法嵌套调用时, Spring通过事务传播行为控制当前的事务如何传播到被嵌套调用的目标服务接口方法中。

  下面从源码中看到有七种,我们常用的就是PROPAGATION_REQUIRED

 
  
//TransactionDefinition的属性
//如果当前存在事务,就加入该事务,如果没有事务,则创建五个新事务
int
PROPAGATION_REQUIRED = 0;
//如果当前存在事务,就加入该事务,如果没有事务,就以非事务的方法运行
int PROPAGATION_SUPPORTS = 1;
//如果当前存在事务,就加入该事务,如果没有事务,就抛出异常
int PROPAGATION_MANDATORY = 2;
//不管当前事务存在事务,都创建新事务
int PROPAGATION_REQUIRES_NEW = 3; //不管当前是否存在事务,都以非事务方法运行
int PROPAGATION_NOT_SUPPORTED = 4;
//以非事务方式运行,如果当前存在事务,就抛出异常
int PROPAGATION_NEVER = 5;
//如果当前存在事务,则以嵌套事务方式运行,如果不事务,则新建一个事务
int PROPAGATION_NESTED = 6;
  • spring事务的常用配置

  首先配置配置一个dataSource,这里就不贴代码了,这里配置了<aop:config>,可能在我们实际中开发中并不会配置这个,这里拿出来是为了后面的源码分析


<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <tx:annotation-driven transaction-manager="transactionManager"/> <aop:config> <aop:pointcut expression="execution(public * com.gupaoedu.vip..*.service..*Service.*(..))" id="transactionPointcut"/> <aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice"/> </aop:config> <tx:advice id="transactionAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="add*" propagation="REQUIRED" rollback-for="Exception,RuntimeException"/> <tx:method name="remove*" propagation="REQUIRED" rollback-for="Exception,RuntimeException"/> <tx:method name="modify*" propagation="REQUIRED" rollback-for="Exception,RuntimeException"/> <tx:method name="login" propagation="REQUIRED"/> <tx:method name="query*" read-only="true"/> </tx:attributes> </tx:advice>

总结

到这里基本上对一些基本概念介绍清楚了,下一篇开始参源码这块进行分析。

参考链接

 

转载于:https://www.cnblogs.com/lucas2/p/9319917.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值