面试官:谈谈Spring事务实现原理
你知道的越多,不知道的就越多,业余的像一棵小草!
你来,我们一起精进!你不来,我和你的竞争对手一起精进!
编辑:业余草
cnblogs.com/insaneXs/p/13638034.html
推荐:https://www.xttblog.com/?p=5281
前言
对于一个应用而言,事务的使用基本是不可避免的。虽然 Spring 给我们提供了开箱即用的事务功能 @Transactional
,但是,自带的事务功能却也存在控制粒度不够的缺点。更糟糕的是,@Transactional
在某些情况下就失效了。可能一些读者 baidu/google 一下解决办法后,失效的问题确实解决了。但是由于不了解底层的原理,这样的问题可能在今后的工作中往复出现。

本文就为大家揭开@Transactional
下的秘密。
原生的事务管理
在没有 Spring 存在的时候,事务就已经诞生了。其实框架依赖的还是底层提供的能力,只不过它对这一过程的抽象和复用。
这里我们用底层的 API 来了解下事务管理的过程( JDBC 为例):
// 获取mysql数据库连接
Connection conn = DriverManager.getConnection("xxxx");
conn.setAutoCommit(false);
statement = conn.createStatement();
// 执行sql,返回结果集
resultSet = statement.executeQuery("xxxx");
conn.commit(); //提交
//回滚
//conn.rollback();
上面是一个原生操作事务的一个例子,这些过程也是 Spring 事务逃不开的,只不过在为了编程的效率让这一过程自动化或是透明化的你无法感知罢了。
而我们之后做的就是逐步还原这一自动化的过程。
Spring提供的事务API
Spring 提供了很多关于事务的 API。但是最为基本的就是PlatformTransactionManager
、TransactionDefintion
和TransactionStatus
。
事务管理器 PlatformTransactionManager
PlatformTransactionManager
是事务管理器的顶层接口。事务的管理是受限于具体的数据源的(例如,JDBC 对应的事务管理器就是DatasourceTransactionManager
),因此PlatformTransactionManager
只规定了事务的基本操作:创建事务,提交事物和回滚事务。
public interface PlatformTransactionManager extends TransactionManager {
/**
* 打开事务
*/
TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException;
/**
* 提交事务
*/
void commit(TransactionStatus status) throws TransactionException;
/**
* 回滚事务
*/
void rollback(TransactionStatus status) throws TransactionException;
}
同时为了简化事务管理器的实现,Spring 提供了一个抽象类AbstractPlatformTransactionManager
,规定了事务管理器的基本框架,仅将依赖于具体平台的特性作为抽象方法留给子类实现。
事务状态 TransactionStatus
事务状态是我对TransactionStatus
这个类的直译。其实我觉得这个类可以直接当作事务的超集来看(包含了事务对象,并且存储了事务的状态)。PlatformTransactionManager.getTransaction()
时创建的也正是这个对象。
这个对象的方法都和事务状态相关:
public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable {
/**
* 是否有Savepoint Savepoint是当事务回滚时需要恢复的状态
*/
boolean hasSavepoint();
/**
* flush()操作和底层数据源有关,并非强制所有数据源都要支持
*/
@Override
void flush();
}
此外,TransactionStatus
还从父接口中继承了其他方法,都归总在下方:
/**
* 是否是新事务(或是其他事务的一部分)
*/
boolean isNewTransaction();
/**
* 设置rollback-only 表示之后需要回滚
*/
void setRollbackOnly();
/**
* 是否rollback-only
*/
boolean isRollbackOnly();
/**
* 判断该事务已经完成
*/
boolean isCompleted();
/**
* 创建一个Savepoint
*/
Object createSavepoint() throws TransactionException;
/**
* 回滚到指定Savepoint
*/
void rollbackToSavepoint(Object savepoint) throws TransactionException;
/**
* 释放Savepoint 当事务完成后,事务管理器基本上自动释放该事务所有的savepoint
*/
void releaseSavepoint(Object savepoint) throws TransactionException;
事务属性的定义 TransactionDefinition
TransactionDefinition
表示一个事务的定义,将根据它规定的特性去开启事务。
事务的传播等级和隔离级别的常量同样定义在这个接口中。
/**
* 返回事务的传播级别
*/
default int getPropagationBehavior() {
return PROPAGATION_REQUIRED;
}
/**
* 返回事务的隔离级别
*/
default int getIsolationLevel() {
return ISOLATION_DEFAULT;
}
/**
* 事务超时时间
*/
default int getTimeout() {
return TIMEOUT_DEFAULT;
}
/**
* 是否为只读事务(只读事务在处理上能有一些优化)
*/
default boolean isReadOnly() {
return false;
}
/**
* 返回事务的名称
*/
@Nullable
default String getName() {
return null;
}
/**
* 默认的事务配置
*/
static TransactionDefinition withDefaults() {
return StaticTransactionDefinition.INSTANCE;
}
编程式使用Spring事务
有了上述这些 API,就已经可以通过编程的方式实现 Spring 的事务控制了。
但是 Spring 官方建议不要直接使用PlatformTransactionManager
这一偏低层的 API 来编程,而是使用TransactionTemplate
和TransactionCallback
这两个偏向用户层的接口。
示例代码如下:
//设置事务的各种属性;可以猜测TransactionTemplate应该是实现了TransactionDefinition
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
transactionTemplate.setTimeout(30000);
//执行事务 将业务逻辑封装在TransactionCallback中
transactionTemplate.execute(new TransactionCallback