前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >详解Spring的事务管理PlatformTransactionManager

详解Spring的事务管理PlatformTransactionManager

作者头像
名字是乱打的
发布2021-12-24 09:14:26
3.3K0
发布2021-12-24 09:14:26
举报
文章被收录于专栏:软件工程

常规的事务大致有许多种,比如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 : 事务的一些状态信息,如是否是一个新的事务、是否已被标记为回滚

一. 看下PlatformTransactionManager如何来操作事务:

代码语言:javascript
复制
public interface PlatformTransactionManager {
 
    //根据事务定义TransactionDefinition,获取事务
    TransactionStatus getTransaction(TransactionDefinition definition);
 
    //提交事务
    void commit(TransactionStatus status);
 
    //回滚事务
    void rollback(TransactionStatus status);
}

二. 事务定义接口TransactionDefinition

  • 1.事务的定义包含:事务的隔离级别、事务的传播属性、超时时间设置、是否只读
    1. 红线上方是些常量定义,关于常量定义(事务的隔离级别和事务的传播属性等等) 具体事务常量定义
这里我们要明白的地方:

事务的隔离级别是数据库本身的事务功能,我们只是基于对数据库的Connection,对书屋操作做封装,而事务的传播属性则是Spring自己为我们提供的功能,数据库事务没有事务的传播属性这一说法。

DefaultTransactionDefinitio实现了该接口(TransactionDefinition):进行了一些默认的事务定义
代码语言:javascript
复制
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

三. 事务的状态信息定义TransactionStatus

先引出Connection连接中的保存点功能:

代码语言:javascript
复制
//创建一个保存点
conn.setSavepoint(name);
//回滚到某个保存点
conn.rollback(savepoint);
//释放某个保存点
conn.releaseSavepoint(savepoint);

TransactionStatus它继承了SavepointManager接口,SavepointManager是对事务中上述保存点功能的封装,如下:

代码语言:javascript
复制
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
  • HibernateTransactionObject
  • JpaTransactionObject(之后再详细说)

详细信息分别如下:

  • 对于DataSourceTransactionObject: 我们使用了dataSource来获取连接,要想实现事务功能,必然需要使用Connection,所以它中肯定有一个Connection来执行事务的操作。 DataSourceTransactionObject中有一个ConnectionHolder,它封装了一个Connection
  • 对于HibernateTransactionObject: 我们使用了hibenrate,此时要想实现事务功能,必然需要通过hibernate自己定义的Transaction来实现。 HibernateTransactionObject中含有一个SessionHolder,和上面的ConnectionHolder一样,它封装了一个Session,有了Session,我们就可以通过Session来产生一个Hibernate的Transaction,从而实现事务操作。

四. 事务管理器接口定义PlatformTransactionManager

类图关系如下:

重点来说下

  • AbstractPlatformTransactionManager
    • DataSourceTransactionManager
    • HibernateTransactionManager
    • JpaTransactionManager(之后详细再说)

这就需要来看看事务管理器的接口,上述的他们都是怎么实现的:

  • 1 第一个接口:TransactionStatus getTransaction(TransactionDefinition definition) 根据事务定义获取事务状态 大体内容就是先获取上述说明的Object transaction,判断当前事务是否已存在,如果存在则进行事务的传播属性处理,后面详细说明,如果不存在new DefaultTransactionStatus,新创建一个事务,同时使用Object transaction开启事务。 分成了几个过程: 不同的事务管理器获取不同的Object transaction
    • Spring获取Object transaction: DataSourceTransactionManager就是获取上述的DataSourceTransactionObject

    从当前线程中获取绑定的ConnectionHolder,可能为null,如果为null,则会在下一个开 启事务的过程中,从dataSource中获取一个Connection,封装成ConnectionHolder,然后再绑定到当前线程 然后我们new 一个DataSourceTransactionObject了,具体过程如下:

构建DefaultTransactionStatus,使用Object transaction开启事务

DataSourceTransactionManager的DataSourceTransactionObject开启过程如下: 首先判断之前的获取当前线程绑定的ConnectionHolder是否为null,如果为null,从dataSource中获取一个Connection,封装成ConnectionHolder,然后再绑定到当前线程(通过ThreadLocal来实现,可以看我别的文章)

因为开启了一个事务,则必须要关闭DataSourceTransactionObject中Connection的自动提交,代码如下(省略一些):

代码语言:javascript
复制
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());
        }
    }
第二个接口:void rollback(TransactionStatus status) 回滚事务

回滚,则还是利用DefaultTransactionStatus内部的Object transaction来执行回滚操作

DataSourceTransactionManager就是使用DataSourceTransactionObject中的Connection来进行回滚操作

代码语言:javascript
复制
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);
    }
}
第三个接口: void commit(TransactionStatus status) 提交事务

同理,DataSourceTransactionManager依托内部的Connection来完成提交操作

这里对于使用提供一个小demo

比如我们现在涉及到一个付款成功的业务,涉及到数据库金额更新和数据库订单状态数据更新,那么前端发送一个请求到我们的controller,我们在controller做向上反馈,在service做事务管理的业务操作以及数据库操作

代码语言:javascript
复制
@PostMapping("moneyOperation")
    public String moneyOperation() {
        if (transactionOperation.moneyOperation()) {
            return "付款成功";
        }
        else {
            return "付款失败!";
        }
    }
代码语言:javascript
复制
/**
 * @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 ``

事务的失效场景

https://mp.weixin.qq.com/s/wrs5rUlFKdemU6m_QUYCZg

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/9/12 下,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 事务功能的总体接口设计
    • 一. 看下PlatformTransactionManager如何来操作事务:
      • 二. 事务定义接口TransactionDefinition
        • 三. 事务的状态信息定义TransactionStatus
          • 四. 事务管理器接口定义PlatformTransactionManager
            • 构建DefaultTransactionStatus,使用Object transaction开启事务
            • 事务的失效场景
        • 这里对于使用提供一个小demo
        相关产品与服务
        数据库
        云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档