spring事务源码分析结合mybatis源码(一)
最近想提升,苦逼程序猿,想了想还是拿最熟悉,之前也一直想看但没看的spring源码来看吧,正好最近在弄事务这部分的东西,就看了下,同时写下随笔记录下,以备后查。
spring tx源码分析
这里只分析简单事务也就是DataSourceTransactionManager
首先肯定找入口了,看过spring源码的同学一定都会找spring tx的入口就是在TxAdviceBeanDefinitionParser这里将解析tx的配置,生成TransactionInterceptor对象,这个也就是一个普通的切面类,只要符合AOP规则的调用都会进入此切面。
在invoke方法中最重要的一段代码:这里主要分析一个新的事务的开始过程
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
final TransactionAttribute txAttr =
getTransactionAttributeSource().getTransactionAttribute(invocation.getMethod(), targetClass);//获取配置的TransactionAttribute信息
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
final String joinpointIdentification = methodIdentification(invocation.getMethod(), targetClass);
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);//开启一个新的事务
Object retVal = null;
try {
retVal = invocation.proceed();//原有逻辑执行
}
catch (Throwable ex) {
completeTransactionAfterThrowing(txInfo, ex);//发生异常时候对异常的处理
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);//清理TransactionInfo信息
}
commitTransactionAfterReturning(txInfo);//提交事务
return retVal;
首先开启事务,也就是调用createTransactionIfNecessary方法:
protected TransactionInfo createTransactionIfNecessary(
PlatformTransactionManager tm, TransactionAttribute txAttr, final String joinpointIdentification) {
if (txAttr != null && txAttr.getName() == null) {
txAttr = new DelegatingTransactionAttribute(txAttr) {
@Override
public String getName() {
return joinpointIdentification;
}
};
}
TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
status = tm.getTransaction(txAttr);
}
else {
}
}
}
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
这里其实主要就是调用PlatformTransactionManager的getTransactionf方法来获取TransactionStatus来开启一个事务:
public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
Object transaction = doGetTransaction();
if (definition == null) {
definition = new DefaultTransactionDefinition();
}
if (isExistingTransaction(transaction)) {//这个判断很重要,是否已经存在的一个transaction
return handleExistingTransaction(definition, transaction, debugEnabled);//如果是存在的将进行一些处理
}
if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
}
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
//如果是PROPAGATION_REQUIRED,PROPAGATION_REQUIRES_NEW,PROPAGATION_NESTED这三种类型将开启一个新的事务
else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
SuspendedResourcesHolder suspendedResources = suspend(null);
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
doBegin(transaction, definition);//开启新事物
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException ex) {
resume(null, suspendedResources);
throw ex;
}
catch (Error err) {
resume(null, suspendedResources);
throw err;
}
}
else {
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
}
}
这段代码比较长也是比较核心的一段代码,让我们来慢慢分析,首先这里将执行doGetTransaction方法来获取一个transaction
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(this.dataSource);
//这一行代码中TransactionSynchronizationManager很重要,是对connection的核心获取、持有、删除等
txObject.setConnectionHolder(conHolder, false);
//这里不论获取到或者获取不到都将此设置newConnectionHolder为false
return txObject;
}
这段代码中主要是根据this.dataSource来获取ConnectionHolder,这个ConnectionHolder是放在TransactionSynchronizationManager的ThreadLocal中持有的,如果是第一次来获取,肯定得到是null。
接着代码往下将执行到isExistingTransaction(transaction),这里主要是依据下面代码判断:
txObject.getConnectionHolder() != null && txObject.getConnectionHolder().isTransactionActive()
如果是第一次开启事务这里必然是false,否则将返回true。
我们这里先讨论第一次进入的情况,也就是false的时候将继续往下执行到了判断事务Propagation的时候了,如果Propagation为:ROPAGATION_REQUIRED,PROPAGATION_REQUIRES_NEW,PROPAGATION_NESTED中的一个将开启一个新事物,new一个新的DefaultTransactionStatus ,并且
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
if (txObject.getConnectionHolder() == null ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
Connection newCon = this.dataSource.getConnection();//从dataSource中获取一个Connection
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);//为当前Transaction设置ConnectionHolder,并且设置newConnectionHolder为true
}
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
//这里主要是根据definition对connection进行一些设置
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
if (con.getAutoCommit()) {//开启事务,设置autoCommit为false
txObject.setMustRestoreAutoCommit(true);
con.setAutoCommit(false);
}
//这里设置transactionActive为true,还记得签名判断是否存在的transaction吧?就是根据这个
txObject.getConnectionHolder().setTransactionActive(true);
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
if (txObject.isNewConnectionHolder()) {
//这里将当前的connection放入TransactionSynchronizationManager中持有,如果下次调用可以判断为已有的事务
TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
}
}
}
这里其实主要就是从dataSource中获取一个新的connection,形成一个ConnectionHolder,并且放入TransactionSynchronizationManager中持有,记得前面doGetTransaction方法吧,如果同一个线程,再此进入执行的话就会获取到同一个ConnectionHolder,在后面的isExistingTransaction方法也可以判定为是已有的transaction。
接下来将执行prepareSynchronization方法,主要是对TransactionSynchronizationManager的一系列设置。
然后将返回上层代码执行prepareTransactionInfo方法
protected TransactionInfo prepareTransactionInfo(PlatformTransactionManager tm,
TransactionAttribute txAttr, String joinpointIdentification, TransactionStatus status) {
TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
if (txAttr != null) {
txInfo.newTransactionStatus(status);
}
txInfo.bindToThread();
return txInfo;
}
这里其实比较简单主要生成一个TransactionInfo并绑定到当前线程的ThreadLocal
private void bindToThread() {
this.oldTransactionInfo = transactionInfoHolder.get();
transactionInfoHolder.set(this);
}
形成了一个链表,具体啥用我也暂时没看到,唯一看到的就是通过TransactionAspectSupport.currentTransactionStatus()可以获取当前的transaction状态。
然后再返回到上层代码,接着就是执行相应的逻辑代码了
retVal = invocation.proceed();
执行过程的finally代码块将执行cleanupTransactionInfo(txInfo);
private void restoreThreadLocalStatus() {
transactionInfoHolder.set(this.oldTransactionInfo);
}
这里就是将txInfo进行重置工作,让它恢复到前一个状态。
然后就是提交操作(commitTransactionAfterReturning)或者是回滚操作(completeTransactionAfterThrowing)了。
这里就拿提交操作来为例来说明,回滚操作类似:
protected void commitTransactionAfterReturning(TransactionInfo txInfo) {
if (txInfo != null && txInfo.hasTransaction()) {
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
}
实际就是执行的processCommit方法
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
try {
boolean beforeCompletionInvoked = false;
try {
prepareForCommit(status);
triggerBeforeCommit(status);
triggerBeforeCompletion(status);
beforeCompletionInvoked = true;
boolean globalRollbackOnly = false;
if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {
globalRollbackOnly = status.isGlobalRollbackOnly();
}
if (status.hasSavepoint()) {
status.releaseHeldSavepoint();
}
else if (status.isNewTransaction()) {
doCommit(status);
}
if (globalRollbackOnly) {
throw new UnexpectedRollbackException(
"Transaction silently rolled back because it has been marked as rollback-only");
}
}
catch (UnexpectedRollbackException ex) {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
throw ex;
}
catch (TransactionException ex) {
if (isRollbackOnCommitFailure()) {
doRollbackOnCommitException(status, ex);
}
else {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
}
throw ex;
}
catch (RuntimeException ex) {
if (!beforeCompletionInvoked) {
triggerBeforeCompletion(status);
}
doRollbackOnCommitException(status, ex);
throw ex;
}
catch (Error err) {
if (!beforeCompletionInvoked) {
triggerBeforeCompletion(status);
}
doRollbackOnCommitException(status, err);
throw err;
}
try {
triggerAfterCommit(status);
}
finally {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
}
}
finally {
cleanupAfterCompletion(status);
}
}
首先将执行一些提交前的准备工作,这里将进行是否有savepoint判断status.hasSavepoint(),如果有的话将进行释放savePoint,即getConnectionHolderForSavepoint().getConnection().releaseSavepoint((Savepoint) savepoint);
接着就判断是否是新的transaction:status.isNewTransaction(),如果是的话将执行 doCommit(status);
protected void doCommit(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
try {
con.commit();
}
catch (SQLException ex) {
throw new TransactionSystemException("Could not commit JDBC transaction", ex);
}
}
其实也就是调用了Connection的commit()方法。
最后无论成功与否都将调用finally块中的cleanupAfterCompletion(status)
private void cleanupAfterCompletion(DefaultTransactionStatus status) {
status.setCompleted();
if (status.isNewSynchronization()) {
TransactionSynchronizationManager.clear();//TransactionSynchronizationManager清理工作
}
if (status.isNewTransaction()) {
doCleanupAfterCompletion(status.getTransaction());//这个比较重要
}
if (status.getSuspendedResources() != null) {
resume(status.getTransaction(), (SuspendedResourcesHolder) status.getSuspendedResources());
}
}
首先对TransactionSynchronizationManager进行一系列清理工作,然后就将执行doCleanupAfterCompletion方法:
protected void doCleanupAfterCompletion(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
if (txObject.isNewConnectionHolder()) {
//从TransactionSynchronizationManager中解绑相应的connectionHolder
TransactionSynchronizationManager.unbindResource(this.dataSource);
}
Connection con = txObject.getConnectionHolder().getConnection();
try {
//对获取到的Connection进行一些还原
if (txObject.isMustRestoreAutoCommit()) {
con.setAutoCommit(true);
}//对获取到的Connection进行一些还原
DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel());
}
catch (Throwable ex) {
}
if (txObject.isNewConnectionHolder()) {
//如果是newConnection将这个链接关闭,如果是连接池将还给连接池
DataSourceUtils.releaseConnection(con, this.dataSource);
}
//这里将这只transactionActive为false
txObject.getConnectionHolder().clear();
}
其实就是将TransactionSynchronizationManager中持有的connectionHolder释放,并且还原当前Connection 的状态,然后将对当前的transaction进行清理包括设置transactionActive为false等。
至此整个spring的事务过程也就结束了。
两篇比较好的关于事务的博客:
http://www.iteye.com/topic/78674
http://www.cnblogs.com/yangy608/archive/2011/06/29/2093478.html
spring事务源码分析结合mybatis源码(一)的更多相关文章
- spring事务源码分析结合mybatis源码(三)
下面将结合mybatis源码来分析下,这种持久化框架是如何对connection使用,来达到spring事务的控制. 想要在把mybatis跟spring整合都需要这样一个jar包:mybatis-s ...
- spring事务源码分析结合mybatis源码(二)
让我们继续上篇,分析下如果有第二个调用进入的过程. 代码部分主要是下面这个: if (isExistingTransaction(transaction)) { return handleExisti ...
- spring事务详解(三)源码详解
系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.引子 ...
- Spring Ioc源码分析系列--Ioc源码入口分析
Spring Ioc源码分析系列--Ioc源码入口分析 本系列文章代码基于Spring Framework 5.2.x 前言 上一篇文章Spring Ioc源码分析系列--Ioc的基础知识准备介绍了I ...
- NIO 源码分析(05) Channel 源码分析
目录 一.Channel 类图 二.begin 和 close 是什么 2.1 AbstractInterruptibleChannel 中的 begin 和 close 2.2 Selector 中 ...
- NIO 源码分析(02-2) BIO 源码分析 Socket
目录 一.BIO 最简使用姿势 二.connect 方法 2.1 Socket.connect 方法 2.2 AbstractPlainSocketImpl.connect 方法 2.3 DualSt ...
- NIO 源码分析(02-1) BIO 源码分析
目录 一.BIO 最简使用姿势 二.ServerSocket 源码分析 2.1 相关类图 2.2 主要属性 2.3 构造函数 2.4 bind 方法 2.5 accept 方法 2.6 总结 NIO ...
- [源码分析] 从实例和源码入手看 Flink 之广播 Broadcast
[源码分析] 从实例和源码入手看 Flink 之广播 Broadcast 0x00 摘要 本文将通过源码分析和实例讲解,带领大家熟悉Flink的广播变量机制. 0x01 业务需求 1. 场景需求 对黑 ...
- drf的基本使用、APIView源码分析和CBV源码拓展
cbv源码拓展 扩展,如果我在Book视图类中重写dispatch方法 -可以实现,在get,post方法执行之前或者之后执行代码,完成类似装饰器的效果 def dispatch(self, requ ...
随机推荐
- python小白——进阶之路——day4天-———流程控制while if循环
# ### 代码块: 以冒号作为开始,用缩进来划分作用域,这个整体叫做代码块 if 5 == 5: print(1) print(2) # 注意点: 要么全部使用4个空格,要么全部使用1个缩进 ,这样 ...
- C# Json字符串保存信息
1.我们在进行数据通信的时候,往往是需要传输一个字符串类型的参数,而这个字符串类型的参数又需要封装大量的数据信息. 这个时候,就需要使用Json来封装这些数据,最后将Json数据以字符串的格式输出 2 ...
- SpringBoot中各配置文件的优先级及加载顺序
我们在写程序的时候会碰到各种环境(开发.测试.生产),因而,在我们切换环境的时候,我们需要手工切换配置文件的内容.这大大的加大了运维人员的负担,同时会带来一定的安全隐患. 为此,为了能更合理地重写各属 ...
- springboot项目利用Swagger2生成在线接口文档
Swagger简介. Swagger2是一款restful接口文档在线生成和在线调试工具.很多项目团队利用Swagger自动生成接口文档,保证接口文档和代码同步更新.在线调试.简单地说,你可以利用这个 ...
- jQuery对象与DOM对象之间的转换(转)
原文:https://www.cnblogs.com/lsy0403/p/5907084.html 什么是DOM对象 使用JavaScript中的方法获取页面中的元素返回的对象就是dom对象.比如使用 ...
- iso data 聚类算法
isodata算法就是先拟定一个预期类,再选取一些聚类中心,通过不断合并或者分裂聚类,达到分类的目的 关键就是在于,如何分裂,合并 要合并或者分裂 必须要确定一些指标 所以第一步就是要确定 某些指标 ...
- openstack搭建之-horizon配置(14)
一.ctrl控制节点安装horizon #安装软件yum install openstack-dashboard -y vim /etc/openstack-dashboard/local_setti ...
- 【学习总结】Git学习-GIT工作流-千峰教育(来自B站)
Git工作流指南 - av32575602 文档资料 目录: 1-什么是版本控制系统 2-工作流简介 3-集中式工作流 4-功能分支工作流 5-GitFlow工作流 小记: 初看差点放弃了,不过后面还 ...
- 源码编译安装php7
现在新启的项目都是采用php7了,无奈很多Linux发行版中还是php5 第三方php7源在自己本机上用用到无所谓,放到正式环境上还是有点不放心 其实编译安装也就几分钟,麻烦的是各种依赖 先删除老版本 ...
- 清北澡堂 Day2 下午 一些比较重要的数论知识整理
1.欧拉定理 设x1,x2,.....,xk,k=φ(n)为1~n中k个与n互质的数 结论一:axi与axj不同余 结论二:gcd(axi,n)=1 结论三:x1,x2,...,xk和ax1,ax2, ...