当前位置:首页 > 技术 > 正文内容

Spring编程式事务管理详解

访客 技术 2026年8月24日 1

目录

  • 事务管理器核心接口
  • 事务定义配置
  • 事务状态控制
  • 编程式事务实现
  • 手动事务管理
  • 事务模板应用

事务管理器核心接口

PlatformTransactionManager是Spring框架处理事务的核心接口,它为不同的事务管理实现提供了一个统一的编程模型。Spring本身并不直接管理事务,而是通过这个接口来适配各种底层的事务机制。该接口主要包含三个核心方法:

public interface PlatformTransactionManager {
    
    // 根据事务定义获取或创建事务
    TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
    
    // 提交当前事务
    void commit(TransactionStatus status) throws TransactionException;
    
    // 回滚当前事务
    void rollback(TransactionStatus status) throws TransactionException;
}

核心方法说明:

  • getTransaction(TransactionDefinition definition)
    • 根据事务定义(传播行为、隔离级别、超时等)获取一个事务
    • 如果当前线程已有事务,根据传播行为决定是加入还是新建
    • 返回TransactionStatus对象,表示当前事务状态
  • commit(TransactionStatus status)
    • 提交事务
    • 如果事务已标记为rollback-only,则执行回滚
  • rollback(TransactionStatus status)
    • 回滚事务

事务定义配置

TransactionDefinition接口用于定义事务的属性,描述事务的边界和行为规则。主要包括以下几个方面:

  • 传播行为(Propagation)
    • REQUIRED(默认):如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务
    • REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起
    • NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务;如果当前没有事务,则等价于REQUIRED
    • SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行
    • NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起
    • NEVER:以非事务方式运行,如果当前存在事务,则抛出异常
    • MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常
  • 隔离级别(Isolation)
    • DEFAULT:使用底层数据库的默认隔离级别
    • READ_UNCOMMITTED:读未提交
    • READ_COMMITTED:读已提交
    • REPEATABLE_READ:可重复读
    • SERIALIZABLE:串行化
  • 超时时间(Timeout)
  • 是否只读(Read-only)

事务状态控制

TransactionStatus接口表示事务的状态,用于在事务的执行过程中查询状态和控制事务:

public interface TransactionStatus extends SavepointManager {
    
    // 判断是否是新的事务
    boolean isNewTransaction();
    
    // 判断是否有保存点
    boolean hasSavepoint();
    
    // 设置事务为只回滚
    void setRollbackOnly();
    
    // 判断事务是否已被标记为只回滚
    boolean isRollbackOnly();
    
    // 判断事务是否已完成
    boolean isCompleted();
}

编程式事务实现

编程式事务允许开发人员在代码中显式调用事务管理API来控制事务边界,提供了比声明式事务更细粒度的事务控制能力。

手动事务管理

首先,在Spring配置文件中配置一个事务管理器:

<bean class="org.springframework.transaction.support.TransactionTemplate" id="transactionTemplate">
    <property name="transactionManager" ref="transactionManager"/>
</bean>

然后在服务层注入事务管理器,并编写相应的方法。以下示例使用MyBatis作为ORM框架:

public class AccountService {
    
    @Autowired
    private PlatformTransactionManager transactionManager;
    
    @Autowired
    private AccountRepository accountRepository;
    
    public void transferAccounts() {
        // 1. 定义默认的事务属性
        DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
        
        // 2. 获取事务状态
        TransactionStatus transaction = transactionManager.getTransaction(definition);
        
        try {
            // 执行数据库操作
            accountRepository.updateAccountBalance(1, 100.0);
            accountRepository.updateAccountBalance(2, -100.0);
            
            // 提交事务
            transactionManager.commit(transaction);
        } catch (Exception e) {
            // 发生异常时回滚事务
            transactionManager.rollback(transaction);
            throw new RuntimeException("账户转账失败", e);
        }
    }
}

运行此方法后,你会发现数据修改成功,看起来似乎是否添加事务没有区别。接下来,在代码中抛出一个异常:

即使已经调用了接口方法,数据也没有被修改,这表明事务被成功回滚了!

事务模板应用

Spring提供了TransactionTemplate类,它封装了事务管理的复杂性,使编程式事务更加简洁:

首先,在Spring配置文件中配置事务模板:

<bean class="org.springframework.transaction.support.TransactionTemplate" id="transactionTemplate">
    <property name="transactionManager" ref="transactionManager"/>
</bean>

然后注入TransactionTemplate到服务类:

public class OrderService {
    
    @Autowired
    private TransactionTemplate transactionTemplate;
    
    @Autowired
    private OrderRepository orderRepository;
    
    /**
     * 使用TransactionTemplate执行事务操作
     * TransactionTemplate是Spring提供的事务模板类,简化了编程式事务的代码
     */
    public void processOrder() {
        // 调用TransactionTemplate的execute方法,传入事务回调接口
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            
            // 重写回调接口的doInTransactionWithoutResult方法
            // 该方法内的代码会在事务环境中执行
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                try {
                    // 创建订单
                    orderRepository.createOrder(new Order("ORD123", 99.99));
                    
                    // 模拟异常情况
                    if (true) {
                        throw new RuntimeException("模拟系统异常");
                    }
                    
                    // 更新库存
                    orderRepository.updateInventory("PROD456", -1);
                    
                } catch (Exception e) {
                    // 异常处理:标记事务为需要回滚
                    status.setRollbackOnly();
                }
            }
        });
    }
}

可以通过transactionTemplate.setIsolationLevel()方法设置事务的隔离级别,从而满足不同业务场景的需求。

标签: Spring事务

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

linux screen 用法详情 (nohup 的替代方案)

一、screen 是什么?能干嘛?screen 是一个终端复用器,可以:在一个 SSH 会话中开多个“虚拟终端”SSH 断线后,程序仍然在后台运行随时重新连接到原来的会话特别适合:nohup 的替代方案跑脚本 / 爬虫 / 训练模型运维、远程开发二、安装 screen# CentOS / Rocky / Almayum install -y screen# Debian / Ubuntuapt i...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。