spring源码解析--事务篇(前篇)
对于每一个JAVA程序员,spring应该是再熟悉不过的框架了,它的功能有多强大我就不多说了,既然他有这么强大的功能,是如何实现的呢?这个就需要从他的原理去了解,而最直接了解原理的方式莫过于源码。当然Spring源码那么大,有时候会显得无从下手,而且也是晦涩难懂。所以我们可以按照功能模块地方式去解读,第一阶段我就先跟大家分享下面spring的事务,读源码前,我们先得了解下spring事务的相关原理:事务的传播特性和隔离级别
spring的传播特性: PROPAGATION_REQUIRED, PROPAGATION_SUPPORTS, PROPAGATION_MANDATORY, PROPAGATION_REQUIRES_NEW, PROPAGATION_NOT_SUPPORTED, PROPAGATION_NEVER, PROPAGATION_NESTED
我们来一一介绍下
class A{
methodA(){
//逻辑处理
b.methodB();
//逻辑处理
}
}
class B{
methodB();
}
1.PROPAGATION_REQUIRED:如果存在一个事务,则支持当前事务。如果没有事务则开启
解释:当A.methodA()和B.methodB()都打上REQUIRED的事务标志,执行A.methodA()方法的时候,看到上下文没有事务,会新建一个事务,当执行到b.methodB()的时候,发现上下文已经有事务了,则不会新建事务,用A.methodA()新建的那个事务。
如果b.methodB()执行成功,a.methodA()执行失败,那么b.methodB()和a.methodA()都会回滚(用的都是a.methodA()的事务)
2.PROPAGATION_SUPPORTS:如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行
解释:当B.methodB()打上PROPAGATION_SUPPORTS的事务标志,执行A.methodA()方法,当执行到b.methodB()的时候,会检查上下文有没有事务,如果A.methodA()有事务,则b.methodB()沿用该事务,反之b.methodB()就以非事物的方式执行
3.PROPAGATION_MANDATORY:如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常
解释:当B.methodB()打上PROPAGATION_MANDATORY的事务标志,执行A.methodA()方法,当执行到b.methodB()的时候,会检查上下文有没有事务,如果A.methodA()有事务,则b.methodB()沿用该事务,如果没有,则会抛出异常
4.PROPAGATION_REQUIRES_NEW:总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起
解释:当B.methodB()打上PROPAGATION_REQUIRES_NEW的事务标志,执行A.methodA()方法,当执行到b.methodB()的时候,会检查上下文有没有事务,如果A.methodA()有事务,则会挂起A.methodA()的事务,新建一个属于b.methodB(),当b.methodB()
的事务执行结束的时候,则会唤醒b.methodB()的事务。和PROPAGATION_REQUIRED的差别在于回滚,当b.methodB()的事务提交后,A.methodA()执行失败,只会回滚A.methodA不会回滚b.methodB(),当b.methodB()执行失败,异常被A.methodA()方法
catch到的话,A.methodA()事务不会回滚
5.PROPAGATION_NOT_SUPPORTED:总是非事务地执行,并挂起任何存在的事务
解释:当B.methodB()打上PROPAGATION_NOT_SUPPORTED的事务标志,执行A.methodA()方法,当执行到b.methodB()的时候,会检查上下文有没有事务,如果A.methodA()有事务,则会挂起A.methodA()的事务,当执行完b.methodB()方法的时候, A.methodA()方法继续以事务的方式执行
6.PROPAGATION_NEVER: 总是非事务地执行,如果存在一个活动事务,则抛出异常
解释:当B.methodB()打上PROPAGATION_NEVER的事务标志,执行A.methodA()方法,当执行到b.methodB()的时候,会检查上下文有没有事务,如果有事务,则抛出异常,如果没有则以非事务执行
7.PROPAGATION_NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, PROPAGATION_REQUIRED 属性执行
解释:当B.methodB()打上PROPAGATION_NOT_SUPPORTED的事务标志,执行A.methodA()方法,当执行到b.methodB()的时候,如果A.methodA()方法有事务,则会用当前事务,如果 b.methodB()执行失败,只会回滚 b.methodB(),不会回滚A.methodA(), 只有当A.methodA()执行完成后才会提交b.methodB()的事务,如果A.methodA()方法没有事务,就会新建一个事务;
事务隔离级别: ISOLATION_DEFAULT,ISOLATION_READ_UNCOMMITTED,ISOLATION_READ_COMMITTED,ISOLATION_REPEATABLE_READ,ISOLATION_SERIALIZABLE
1.ISOLATION_DEFAULT:这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别
2. ISOLATION_READ_UNCOMMITTED :这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。
3. ISOLATION_READ_COMMITTED :保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。:
4. ISOLATION_REPEATABLE_READ :这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。
5. ISOLATION_SERIALIZABLE :这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻读。
ok,现在我们事务的传播特性和隔离级别有了一定的了解。我们开始去尝试阅读源码
想要阅读源码,我们必须先弄清楚spring事务的几个类和接口的关系,先看下图:

事务的定义接口:TransactionDefinition
包含事务的两个重要属性:传播特性和隔离级别(上面已作介绍,不在重复)
public interface 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;
int ISOLATION_DEFAULT = -1;
int ISOLATION_READ_UNCOMMITTED = 1;
int ISOLATION_READ_COMMITTED = 2;
int ISOLATION_REPEATABLE_READ = 4;
int ISOLATION_SERIALIZABLE = 8;
int TIMEOUT_DEFAULT = -1;
int getPropagationBehavior();
int getIsolationLevel();
int getTimeout();
boolean isReadOnly();
String getName();
}
TransactionDefinition 的一个实现类:DefaultTransactionDefinition
就是对上述属性设置一些默认值,默认的传播特性为PROPAGATION_REQUIRED ,隔离级别为ISOLATION_DEFAULT
public class DefaultTransactionDefinition implements TransactionDefinition, Serializable {
public static final String PREFIX_PROPAGATION = "PROPAGATION_";
public static final String PREFIX_ISOLATION = "ISOLATION_";
public static final String PREFIX_TIMEOUT = "timeout_";
public static final String READ_ONLY_MARKER = "readOnly";
static final Constants constants = new Constants(TransactionDefinition.class);
private int propagationBehavior = 0;//默认值
private int isolationLevel = -1;
private int timeout = -1;
private boolean readOnly = false;
private String name;
public DefaultTransactionDefinition() {
}
public DefaultTransactionDefinition(TransactionDefinition other) {
this.propagationBehavior = other.getPropagationBehavior();
this.isolationLevel = other.getIsolationLevel();
this.timeout = other.getTimeout();
this.readOnly = other.isReadOnly();
this.name = other.getName();
}
public DefaultTransactionDefinition(int propagationBehavior) {
this.propagationBehavior = propagationBehavior;
}
public final void setPropagationBehaviorName(String constantName) throws IllegalArgumentException {
if(constantName != null && constantName.startsWith("PROPAGATION_")) {
this.setPropagationBehavior(constants.asNumber(constantName).intValue());
} else {
throw new IllegalArgumentException("Only propagation constants allowed");
}
}
public final void setPropagationBehavior(int propagationBehavior) {
if(!constants.getValues("PROPAGATION_").contains(Integer.valueOf(propagationBehavior))) {
throw new IllegalArgumentException("Only values of propagation constants allowed");
} else {
this.propagationBehavior = propagationBehavior;
}
}
public final int getPropagationBehavior() {
return this.propagationBehavior;
}
public final void setIsolationLevelName(String constantName) throws IllegalArgumentException {
if(constantName != null && constantName.startsWith("ISOLATION_")) {
this.setIsolationLevel(constants.asNumber(constantName).intValue());
} else {
throw new IllegalArgumentException("Only isolation constants allowed");
}
}
public final void setIsolationLevel(int isolationLevel) {
if(!constants.getValues("ISOLATION_").contains(Integer.valueOf(isolationLevel))) {
throw new IllegalArgumentException("Only values of isolation constants allowed");
} else {
this.isolationLevel = isolationLevel;
}
}
public final int getIsolationLevel() {
return this.isolationLevel;
}
public final void setTimeout(int timeout) {
if(timeout < -1) {
throw new IllegalArgumentException("Timeout must be a positive integer or TIMEOUT_DEFAULT");
} else {
this.timeout = timeout;
}
}
public final int getTimeout() {
return this.timeout;
}
public final void setReadOnly(boolean readOnly) {
this.readOnly = readOnly;
}
public final boolean isReadOnly() {
return this.readOnly;
}
public final void setName(String name) {
this.name = name;
}
public final String getName() {
return this.name;
}
public boolean equals(Object other) {
return other instanceof TransactionDefinition && this.toString().equals(other.toString());
}
public int hashCode() {
return this.toString().hashCode();
}
public String toString() {
return this.getDefinitionDescription().toString();
}
protected final StringBuilder getDefinitionDescription() {
StringBuilder result = new StringBuilder();
result.append(constants.toCode(Integer.valueOf(this.propagationBehavior), "PROPAGATION_"));
result.append(',');
result.append(constants.toCode(Integer.valueOf(this.isolationLevel), "ISOLATION_"));
if(this.timeout != -1) {
result.append(',');
result.append("timeout_").append(this.timeout);
}
if(this.readOnly) {
result.append(',');
result.append("readOnly");
}
return result;
}
}
TransactionAttribute接口
定义对什么类型的异常进行回滚
public interface TransactionAttribute extends TransactionDefinition {
String getQualifier();
boolean rollbackOn(Throwable var1);
}
TransactionAttribute的实现类:DefaultTransactionAttribute
指明了默认对RuntimeException 和Error都进行回滚
public class DefaultTransactionAttribute extends DefaultTransactionDefinition implements TransactionAttribute {
private String qualifier;
public DefaultTransactionAttribute() {
}
public DefaultTransactionAttribute(TransactionAttribute other) {
super(other);
}
public DefaultTransactionAttribute(int propagationBehavior) {
super(propagationBehavior);
}
public void setQualifier(String qualifier) {
this.qualifier = qualifier;
}
public String getQualifier() {
return this.qualifier;
}
public boolean rollbackOn(Throwable ex) {//指明了对RuntimeException 和Error进行回滚
return ex instanceof RuntimeException || ex instanceof Error;
}
protected final StringBuilder getAttributeDescription() {
StringBuilder result = this.getDefinitionDescription();
if(this.qualifier != null) {
result.append("; '").append(this.qualifier).append("'");
}
return result;
}
}
事务模板类TransactionTemplate
他的核心是里面有PlatformTransactionManager 这个事务管理类,用它来对事务提交和回滚。我们的业务逻辑只要写在TransactionCallback.doInTransaction()方法里面既可以,每次执行这个方法前,先会transactionManager.getTransaction(this)开启一 个事务,执行TransactionCallback.doInTransaction()异常的话会调用transactionManager.rollback(status)来回滚事务,正确的话就会调用transactionManager.commit(status)提交事务;
public class TransactionTemplate extends DefaultTransactionDefinition implements TransactionOperations, InitializingBean {
protected final Log logger = LogFactory.getLog(this.getClass());
private PlatformTransactionManager transactionManager;
public TransactionTemplate() {
}
public TransactionTemplate(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
public TransactionTemplate(PlatformTransactionManager transactionManager, TransactionDefinition transactionDefinition) {
super(transactionDefinition);
this.transactionManager = transactionManager;
}
public void setTransactionManager(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
public PlatformTransactionManager getTransactionManager() {
return this.transactionManager;
}
public void afterPropertiesSet() {
if(this.transactionManager == null) {
throw new IllegalArgumentException("Property 'transactionManager' is required");
}
}
public <T> T execute(TransactionCallback<T> action) throws TransactionException {
if(this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
return ((CallbackPreferringPlatformTransactionManager)this.transactionManager).execute(this, action);
} else {
TransactionStatus status = this.transactionManager.getTransaction(this);
Object result;
try {
result = action.doInTransaction(status);//业务逻辑代码写在这里
} catch (RuntimeException var5) {
this.rollbackOnException(status, var5);
throw var5;
} catch (Error var6) {
this.rollbackOnException(status, var6);
throw var6;
} catch (Exception var7) {
this.rollbackOnException(status, var7);
throw new UndeclaredThrowableException(var7, "TransactionCallback threw undeclared checked exception");
}
this.transactionManager.commit(status);
return result;
}
}
private void rollbackOnException(TransactionStatus status, Throwable ex) throws TransactionException {
this.logger.debug("Initiating transaction rollback on application exception", ex);
try {
this.transactionManager.rollback(status);
} catch (TransactionSystemException var4) {
this.logger.error("Application exception overridden by rollback exception", ex);
var4.initApplicationException(ex);
throw var4;
} catch (RuntimeException var5) {
this.logger.error("Application exception overridden by rollback exception", ex);
throw var5;
} catch (Error var6) {
this.logger.error("Application exception overridden by rollback error", ex);
throw var6;
}
}
}
基于上面的模板类,我们可以这样来实现数据库的事务,把每个逻辑都写在TransactionCallback.doInTransaction()方法里面,他会自动帮我们提交事务
TransactionTemplate transactionTemplate=new TransactionTemplate();
transactionTemplate.setTransactionManager(platformTransactionManager); transactionTemplate.execute(new TransactionCallback<String>() { @Override
public String doInTransaction(TransactionStatus status) {
//数据库操作
return "success";
}
});
但是这样会使每个数据库方法都要要写到TransactionCallback.doInTransaction(),其实耦合度还是很高。Spring于是推出了他的AOP管理事务
这个我会在下一篇详细介绍spring-aop与事务
spring源码解析--事务篇(前篇)的更多相关文章
- Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点
Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...
- Spring源码解析系列汇总
相信我,你会收藏这篇文章的 本篇文章是这段时间撸出来的Spring源码解析系列文章的汇总,总共包含以下专题.喜欢的同学可以收藏起来以备不时之需 SpringIOC源码解析(上) 本篇文章搭建了IOC源 ...
- Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean
Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean 七千字长文深刻解读,Spirng中是如何初始化单例bean的,和面试中最常问的Sprin ...
- Spring源码解析 - AbstractBeanFactory 实现接口与父类分析
我们先来看类图吧: 除了BeanFactory这一支的接口,AbstractBeanFactory主要实现了AliasRegistry和SingletonBeanRegistry接口. 这边主要提供了 ...
- spring 源码解析
1. [文件] spring源码.txt ~ 15B 下载(167) ? 1 springн┤┬вио╬Ш: 2. [文件] spring源码分析之AOP.txt ~ 15KB 下载( ...
- Spring源码解析——循环依赖的解决方案
一.前言 承接<Spring源码解析--创建bean>.<Spring源码解析--创建bean的实例>,我们今天接着聊聊,循环依赖的解决方案,即创建bean的ObjectFac ...
- Spring源码解析之BeanFactoryPostProcessor(三)
在上一章中笔者介绍了refresh()的<1>处是如何获取beanFactory对象,下面我们要来学习refresh()方法的<2>处是如何调用invokeBeanFactor ...
- Spring源码解析之ConfigurationClassPostProcessor(二)
上一个章节,笔者向大家介绍了spring是如何来过滤配置类的,下面我们来看看在过滤出配置类后,spring是如何来解析配置类的.首先过滤出来的配置类会存放在configCandidates列表, 在代 ...
- Spring源码解析-ioc容器的设计
Spring源码解析-ioc容器的设计 1 IoC容器系列的设计:BeanFactory和ApplicatioContext 在Spring容器中,主要分为两个主要的容器系列,一个是实现BeanFac ...
随机推荐
- 【CF666E】Forensic Examination(后缀自动机,线段树合并)
[CF666E]Forensic Examination(后缀自动机,线段树合并) 题面 洛谷 CF 翻译: 给定一个串\(S\)和若干个串\(T_i\) 每次询问\(S[pl..pr]\)在\(T_ ...
- redis搭建集群并用TreeSoft管理
前言:redis作为一款高效的NOSQL数据库已经深入贯彻和落实到我们的日常开发代码中,作为缓存.时间控制.数据仓库.队列等使用方法层出不穷,简直是开写代码.居家旅行之必备良药.曾经,我们的项目都是单 ...
- Django CRM客户关系管理系统
CRM需求分析 随着信息化时代带来的科技创新,CRM客户关系管理系统带来的效益在已经成为很多企业提高竞争优势的一分部,CRM客户关系管理系统将企业管理和客户关系管理集成到统一的平台,其系统功能主要体现 ...
- windows环境利用semophore机制进行线程同步
semophore是信号量的意思,常用于PV操作,所谓PV操作就是pend(等待,直到有资源可用,并且消耗资源) V就是释放资源. semophore和mutex区别,mutex本意为互斥,用于线程独 ...
- 赤池信息量准则 ( Akaike information criterion)
sklearn实战-乳腺癌细胞数据挖掘(博主亲自录制视频) https://study.163.com/course/introduction.htm?courseId=1005269003& ...
- (转) 使用vivado创建工程 3
Create a Hello World application In this experiment we will use Xilinx SDK to create a simple Hello ...
- html中<meta>标签
这个是html文档一般都有的元素. 1. 介绍 元素基本所有浏览器都支持,它提供页面的元信息,比如描述.关键字.web服务等 位于文档头部的内部,将以名称/值对出现 2. 属性 注意:如果没有name ...
- 构造+分块思想 Codeforces Round #319 (Div. 1) C
http://codeforces.com/contest/576/problem/C 题目大意: 给你一个曼哈顿距离的图,然后要求你找到一个链,链穿了所有的点 然后要求这链的长度<=25*10 ...
- 【BZOJ】3238: [Ahoi2013]差异
[题意]给定长度为n的小写字母字符串,令Ti表示以i开头的后缀,求Σ[Ti+Tj-2*lcp(Ti,Tj)],1<=i<j<=n. [算法]后缀自动机 [题解]Σ(Ti+Tj)只与n ...
- JQuery对RadioButton和CheckButton的操作
js对RadioButton和CheckButton的操作,在网站开发中会经常遇到,而JQuery操作RadioButton和CheckButton非常便捷.小编觉得网站开发人员有必要熟练掌握.所以小 ...