一、什么是事务
事务:多个操作,要么都做,要么都不做。
数据库的事务管理流程:
- 开启事务
- 执行多个操作
- 提交或回滚
二、Spring事务
Spring的事务管理跟数据库的事务管理也是一样的。
- 支持多种不同的事务管理实现
贴一下spring实现事务管理的xml配置:
三、Spring事务源码
目前我研究的是:
一个接口,一个抽象类,两个实现类
- 接口是:PlatformTransactionManager.class
- 抽象类:AbstractPlatformTransactionManager.class
- 两个实现类:DataSourceTransactionManager.class(可实现多个方法在一个事务中)
JtaTransactionManager.class(分布式事务管理器,springboot只提供了规范,需要开发者自己去实现)
3.1 PlatformTransactionManager(平台事务管理器)
3.1.1 方法图
可以看到他的方法无非就是开启事务、提交、回滚。
3.1.1.1 TransactionDefinition
TransactionDefinition——是getTransaction()方法中入参,我们看看它的组成:
看到了吗,它就是事务定义类——就是我们@Transaction注解里的各种参数。
由上图延伸出问题:
- spring有几种事务隔离级别,几种传播行为?
TransactionDefinition的实现类与继承关系:
3.1.2 所有实现与继承
DataSourceTransactionManager类继承图:DataSourceTransactionManager后面会详细讲解。
3.1.3 @Transactional注解
3.2 切面代码——TransactionInterceptor
在应用系统调用声明@Transactional 的目标方法时,Spring Framework 默认使用 AOP 代理,在代码运行时生成一个代理对象,根据@Transactional 的属性配置信息,这个代理对象决定该声明@Transactional 的目标方法是否由拦截器 TransactionInterceptor 来使用拦截,在 TransactionInterceptor 拦截时,会在在目标方法开始执行之前创建并加入事务,并执行目标方法的逻辑, 最后根据执行情况是否出现异常,利用抽象事务管理器(图 2 有相关介绍)AbstractPlatformTransactionManager 操作数据源 DataSource 提交或回滚事务。
3.2.1
TransactionInterceptor.invoke——>invokeWithinTransaction 就是执行@Transactional注解标注的代码逻辑。
开启事务:
异常是否回滚:
3.2.2 invokeWithinTransaction代码
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
final String joinpointIdentification = methodIdentification(method, targetClass);
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
try {
Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,
new TransactionCallback<Object>() {
@Override
public Object doInTransaction(TransactionStatus status) {
TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
try {
return invocation.proceedWithInvocation();
}
catch (Throwable ex) {
if (txAttr.rollbackOn(ex)) {
// A RuntimeException: will lead to a rollback.
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
}
else {
throw new ThrowableHolderException(ex);
}
}
else {
// A normal return value: will lead to a commit.
return new ThrowableHolder(ex);
}
}
finally {
cleanupTransactionInfo(txInfo);
}
}
});
// Check result: It might indicate a Throwable to rethrow.
if (result instanceof ThrowableHolder) {
throw ((ThrowableHolder) result).getThrowable();
}
else {
return result;
}
}
catch (ThrowableHolderException ex) {
throw ex.getCause();
}
}
}
方法基本逻辑分析:
- 获取事务属性,根据事务属性获取事务管理器。
- 判断属性是否为空,或者事务管理是否是CallbackPreferringPlatformTransactionManager类型,如果是该类型,则会执行事务管理器的execute方法。
- 生成一个封装事务管理器、事务属性、方法签名字符串、事务状态对象的TransactionInfo事务信息对象,改对象会在事务回滚或者失败时起作用。
- 调用目标对象方法或者下一个过滤器的方法
- 如果方法由异常则执行 completeTransactionAfterThrowing 方法,调用事务管理器的回滚方法。如果没有异常,调用 commitTransactionAfterReturning 提交方法。最后返回返回值
四、DataSourceTransactionManager
多个方法要操作一个db,想要设置成一个事务,spring如何实现?
——怎么让多个方法拿到同一个连接。
——DataSourceTransactionManager
4.1 事务管理器中的抽象类(模板方法),代码解读
AbstractPlatformTransationManager.java是一个抽象类
doGetTransation()是一个抽象方法。不同的子类可以实现自己的doGetTransaction()方法。
——这就什么设计模式?模板方法设计模式
AbstractPlatformTransationManager标准的commit方法:
commit调用过程:
commit——>processCommit(defStatus)——>doCommit(status);
同样的,其中doCommit()是抽象方法,doRollback()也是抽象方法。
为什么在抽象层实现,因为流程是一样的,只是个别方法有些许差异。
4.2 数据源的事务管理器代码解读
TreadLocal是一个线程一份,那为什么所有线程共用了ThreadLocal?
——TreadLocal是随着线程消失而消失的,新的线程与老线程无关。
4.2.1 连接的逻辑
开启事务:
doBegin又是抽象方法:为什么用protected修饰,因为要让子类调用
查看它在DataSourceTransactionManager中的实现: