常规的事务大致有许多种,比如jdbc事务, Hibernate的事务, JpaTransactionObject事务 关于他们的对比可以看看事务比较 我们直接看
PlatformTransactionManager
Spring进行了统一的抽象,形成了PlatformTransactionManager事务管理器接口
,事务的提交、回滚等操作
全部交给它来实现。
Spring的事务体系也是在PlatformTransactionManager事务管理器接口
上开展开来的(不管是JPA还是JDBC等都实现自接口 PlatformTransactionManager
如果你添加的是 spring-boot-starter-jdbc
依赖,框架会默认注入 DataSourceTransactionManager
实例。如果你添加的是 spring-boot-starter-data-jpa
依赖,框架会默认注入 JpaTransactionManager
实例。,所以先来了解下PlatformTransactionManager事务管理器。
先来看下三大接口,三个接口功能一句话总的来说事务管理器基于事务基础信息在操作事务时候对事务状态进行更新。
PlatformTransactionManager
: 事务管理器TransactionDefinition
: 事务的一些基础信息,如超时时间、隔离级别、传播属性等TransactionStatus
: 事务的一些状态信息,如是否是一个新的事务、是否已被标记为回滚public interface PlatformTransactionManager {
//根据事务定义TransactionDefinition,获取事务
TransactionStatus getTransaction(TransactionDefinition definition);
//提交事务
void commit(TransactionStatus status);
//回滚事务
void rollback(TransactionStatus status);
}
事务的隔离级别是数据库本身的事务功能,我们只是基于对数据库的Connection,对书屋操作做封装,而事务的传播属性则是Spring自己为我们提供的功能,数据库事务没有事务的传播属性这一说法。
DefaultTransactionDefinitio
实现了该接口(TransactionDefinition):进行了一些默认的事务定义public class DefaultTransactionDefinition implements TransactionDefinition, Serializable {
private int propagationBehavior = PROPAGATION_REQUIRED;
private int isolationLevel = ISOLATION_DEFAULT;
private int timeout = TIMEOUT_DEFAULT;
private boolean readOnly = false;
//略
}
传播属性
为PROPAGATION_REQUIRED
,如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。被设置成这个级别时,会为每一个被调用的方法创建一个逻辑事务域。如果前面的方法已经创建了事务,那么后面的方法支持当前的事务,如果当前没有事务会重新建立事务,其他请看事务的传播属性 隔离级别
采用底层数据库默认的隔离级别
超时时间
采用底层数据库默认的超时时间
是否只读
为false先引出Connection
连接中的保存点
功能:
//创建一个保存点
conn.setSavepoint(name);
//回滚到某个保存点
conn.rollback(savepoint);
//释放某个保存点
conn.releaseSavepoint(savepoint);
TransactionStatus它继承了SavepointManager接口,SavepointManager是对事务中上述保存点功能
的封装,如下:
public interface SavepointManager {
Object createSavepoint() throws TransactionException;
void rollbackToSavepoint(Object savepoint) throws TransactionException;
void releaseSavepoint(Object savepoint) throws TransactionException;
}
Spring利用保存点功能实现了事务的嵌套功能。后面会详细说明。
至于我们说的TransactionStatus
本身更多存储的是事务的一些状态信息:
常用的TransactionStatus接口实现为DefaultTransactionStatus,真正用来操作事务的:
目前jdbc事务是通过Connection来实现事务的,Hibernate是通过它自己定义的Transaction来实现的,所以各家的事务都不同
,所以
Spring只能以Object transaction的形式来表示各家的事务,事务的回滚和提交等操作都会最终委托给上Object transaction
来完成。
Object transaction的职责就是提交回滚事务,这个transaction的选择可能如下:
详细信息分别如下:
DataSourceTransactionObject
中有一个ConnectionHolder
,它封装了一个Connection
。SessionHolder
,和上面的ConnectionHolder一样,它封装了一个Session,有了Session,我们就可以通过Session来产生一个Hibernate的Transaction,从而实现事务操作。类图关系如下:
重点来说下
这就需要来看看事务管理器的接口,上述的他们都是怎么实现的:
从当前线程中获取绑定的ConnectionHolder,可能为null,如果为null,则会在下一个开 启事务的过程中,从dataSource中获取一个Connection,封装成ConnectionHolder,然后再绑定到当前线程 然后我们new 一个DataSourceTransactionObject了,具体过程如下:
DataSourceTransactionManager的DataSourceTransactionObject开启过程如下:
首先判断之前的获取当前线程绑定的ConnectionHolder是否为null,如果为null,从dataSource中获取一个Connection,封装成ConnectionHolder
,然后再绑定到当前线程(通过ThreadLocal来实现,可以看我别的文章)
因为开启了一个事务,则必须要关闭DataSourceTransactionObject中Connection的自动提交,代码如下(省略一些):
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
//如果ConnectionHolder是否为null,从新获取
if (txObject.getConnectionHolder() == null ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
Connection newCon = this.dataSource.getConnection();
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
con = txObject.getConnectionHolder().getConnection();
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
//取消自动提交
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
con.setAutoCommit(false);
}
txObject.getConnectionHolder().setTransactionActive(true);
//如果是新增的ConnectionHolder,则绑定到当前线程
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
}
}
回滚,则还是利用DefaultTransactionStatus内部的Object transaction来执行回滚操作
DataSourceTransactionManager就是使用DataSourceTransactionObject中的Connection来进行回滚操作
protected void doRollback(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
try {
con.rollback();
}
catch (SQLException ex) {
throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
}
}
同理,DataSourceTransactionManager依托内部的Connection来完成提交操作
比如我们现在涉及到一个付款成功的业务,涉及到数据库金额更新和数据库订单状态数据更新,那么前端发送一个请求到我们的controller,我们在controller做向上反馈,在service做事务管理的业务操作以及数据库操作
@PostMapping("moneyOperation")
public String moneyOperation() {
if (transactionOperation.moneyOperation()) {
return "付款成功";
}
else {
return "付款失败!";
}
}
/**
* @description: money相关事务demo
* @author: zyh
* @create: 2021-06-23 14:06
**/
@Service
@Slf4j
@RequiredArgsConstructor
public class TransactionOperation {
private final PlatformTransactionManager transactionManager;
public boolean moneyOperation() {
TransactionStatus status;
// 手动开启事务初始化
status = transactionManager.getTransaction(new DefaultTransactionDefinition());
//操作
try {
// 数据库操作后(例如业务上需先更新金额,再更新订单信息)
moneyDaoOperation();
DefaultTransactionDefinition
// 操作无异常:提交事务
transactionManager.commit(status);
log.debug("操作xxxx成功");
return true;
} catch (Exception e) {
log.debug("操作xxxx成功出错,正在回滚,错误信息为:"+e.getMessage());
// 捕获异常, 事务回滚
transactionManager.rollback(status);
log.debug("操作xxxx已回滚");
return false;
}
}
}
参考https://blog.csdn.net/luzhensmart/article/details/90167871 ``