百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT技术 > 正文

SpringBoot事务管理详解:从基础到高级实战(一个字:全)

wptr33 2025-06-10 02:11 13 浏览

一、事务管理基础概念

1.1 什么是事务?

专业解释:事务(Transaction)是数据库操作的一个执行单元,它由一个或多个SQL语句组成,这些语句要么全部执行成功,要么全部失败回滚。

通俗理解:就像银行转账,A给B转100元,需要从A账户扣100,同时给B账户加100。这两个操作必须同时成功或同时失败,不能只完成一个。

1.2 事务的四大特性(ACID)

特性

全称

解释

生活化例子

原子性

Atomicity

事务是不可分割的工作单位,要么全部执行,要么全部不执行

要么转账完全成功,要么完全失败,不会出现钱扣了但对方没收到的情况

一致性

Consistency

事务执行前后,数据库从一个一致状态变到另一个一致状态

转账前后,A和B的账户总额保持不变

隔离性

Isolation

多个事务并发执行时,一个事务的执行不应影响其他事务

多人同时给同一个人转账,结果应该和顺序执行一样正确

持久性

Durability

事务一旦提交,其结果就是永久性的

转账成功后,即使系统崩溃,结果也不会丢失

1.3 Spring事务管理核心接口

Spring事务管理主要基于以下几个核心接口:

  1. PlatformTransactionManager - 事务管理器顶层接口
  2. TransactionDefinition - 事务定义信息(隔离级别、传播行为等)
  3. TransactionStatus - 事务运行状态

二、SpringBoot事务基础配置

2.1 快速启用事务管理

SpringBoot中只需添加@
EnableTransactionManagement
注解即可启用事务管理(实际上SpringBoot自动配置已经帮我们做了)

@SpringBootApplication
@EnableTransactionManagement // 可省略,SpringBoot自动配置会启用
public class MyApp {
    public static void main(String[] args) {
        SpringApplication.run(MyApp.class, args);
    }
}

2.2 配置数据源和事务管理器

SpringBoot自动配置会为我们创建
DataSourceTransactionManager
,我们也可以自定义:

@Configuration
public class DataSourceConfig {
    
    @Bean
    public DataSource dataSource() {
        // 这里以HikariCP为例
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
        dataSource.setUsername("root");
        dataSource.setPassword("password");
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        return dataSource;
    }
    
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

三、声明式事务管理

3.1 @Transactional注解基础使用

@Service
public class OrderService {
    
    @Autowired
    private OrderDao orderDao;
    
    @Autowired
    private AccountDao accountDao;
    
    @Transactional
    public void createOrder(Order order) {
        // 1. 创建订单
        orderDao.insert(order);
        
        // 2. 扣减账户余额
        accountDao.deduct(order.getUserId(), order.getAmount());
        
        // 如果这里抛出异常,上面两个操作都会回滚
    }
}

3.2 @Transactional注解属性详解

属性

类型

说明

默认值

propagation

Propagation

事务传播行为

REQUIRED

isolation

Isolation

事务隔离级别

DEFAULT(使用数据库默认)

timeout

int

事务超时时间(秒)

-1(使用系统默认)

readOnly

boolean

是否只读事务

false

rollbackFor

Class[]

指定哪些异常类触发回滚

{}

rollbackForClassName

String[]

指定哪些异常类名触发回滚

{}

noRollbackFor

Class[]

指定哪些异常类不触发回滚

{}

noRollbackForClassName

String[]

指定哪些异常类名不触发回滚

{}

3.3 事务传播行为详解

传播行为定义了事务方法相互调用时事务如何传播。

传播行为

解释

生活化例子

REQUIRED

如果当前没有事务,就新建一个事务;如果已经存在一个事务,就加入这个事务

朋友聚餐:如果已经有人组织(有事务)就加入;没人组织就自己组织一个

SUPPORTS

支持当前事务,如果当前没有事务,就以非事务方式执行

朋友聚餐:有人组织就一起;没人组织就各自AA

MANDATORY

使用当前的事务,如果当前没有事务,就抛出异常

必须有人组织聚餐,没人组织就生气

REQUIRES_NEW

新建事务,如果当前存在事务,把当前事务挂起

不管有没有人组织,自己单独再组织一次

NOT_SUPPORTED

以非事务方式执行操作,如果当前存在事务,就把当前事务挂起

不参与集体活动,自己单独行动

NEVER

以非事务方式执行,如果当前存在事务,则抛出异常

拒绝参加有组织的聚餐

NESTED

如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则执行与REQUIRED类似的操作

大聚餐中的小聚餐,可以单独回滚小聚餐

代码示例

@Service
public class OrderService {
    
    @Autowired
    private InventoryService inventoryService;
    
    @Transactional(propagation = Propagation.REQUIRED)
    public void placeOrder(Order order) {
        // 主业务逻辑
        saveOrder(order);
        
        try {
            // 调用库存服务,使用REQUIRES_NEW传播行为
            inventoryService.updateStock(order.getProductId(), order.getQuantity());
        } catch (Exception e) {
            // 库存更新失败不影响订单创建
            log.error("库存更新失败", e);
        }
    }
}

@Service
public class InventoryService {
    
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void updateStock(Long productId, int quantity) {
        // 更新库存逻辑
    }
}

3.4 事务隔离级别详解

隔离级别定义了一个事务可能受其他并发事务影响的程度。

隔离级别

解释

可能的问题

生活化例子

DEFAULT

使用数据库默认隔离级别

取决于数据库

使用公司默认规定

READ_UNCOMMITTED

允许读取未提交的变更(脏读)

脏读、不可重复读、幻读

看同事未保存的文档草稿

READ_COMMITTED

只能读取已提交的数据

不可重复读、幻读

只能看同事已保存的文档

REPEATABLE_READ

确保同一事务中多次读取同样数据结果一致

幻读

拍照记录同事文档状态,之后查看照片

SERIALIZABLE

最高隔离级别,完全串行化执行

锁门独自修改文档,其他人必须等待

代码示例

@Service
public class AccountService {
    
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public BigDecimal getAccountBalance(Long accountId) {
        // 这个方法保证读取的是已提交的数据
        return accountDao.getBalance(accountId);
    }
    
    @Transactional(isolation = Isolation.REPEATABLE_READ)
    public void transfer(Long fromId, Long toId, BigDecimal amount) {
        // 转账操作需要可重复读,保证多次读取余额一致
        BigDecimal fromBalance = accountDao.getBalance(fromId);
        if (fromBalance.compareTo(amount) < 0) {
            throw new RuntimeException("余额不足");
        }
        // 其他操作...
    }
}

四、编程式事务管理

除了声明式事务,Spring还提供了编程式事务管理。

4.1 使用TransactionTemplate

@Service
public class OrderService {
    
    @Autowired
    private TransactionTemplate transactionTemplate;
    
    @Autowired
    private OrderDao orderDao;
    
    public void createOrder(final Order order) {
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                try {
                    // 业务逻辑
                    orderDao.insert(order);
                    // 其他操作...
                } catch (Exception e) {
                    status.setRollbackOnly(); // 标记为回滚
                    throw e;
                }
            }
        });
    }
}

4.2 使用PlatformTransactionManager

@Service
public class OrderService {
    
    @Autowired
    private PlatformTransactionManager transactionManager;
    
    @Autowired
    private OrderDao orderDao;
    
    public void createOrder(Order order) {
        // 定义事务属性
        DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
        definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        definition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
        definition.setTimeout(30);
        
        TransactionStatus status = transactionManager.getTransaction(definition);
        
        try {
            // 业务逻辑
            orderDao.insert(order);
            // 其他操作...
            
            transactionManager.commit(status);
        } catch (Exception e) {
            transactionManager.rollback(status);
            throw e;
        }
    }
}

五、事务高级特性

5.1 事务回滚规则

默认情况下,事务只在遇到运行时异常(RuntimeException)和错误(Error)时回滚,检查异常(Checked Exception)不会触发回滚。

自定义回滚异常

@Transactional(rollbackFor = {BusinessException.class, SQLException.class})
public void businessOperation() throws BusinessException {
    // 业务逻辑
    if (someCondition) {
        throw new BusinessException("业务异常");
    }
}

5.2 事务超时设置

@Transactional(timeout = 30) // 单位秒
public void longRunningProcess() {
    // 这个方法执行时间超过30秒会触发超时回滚
}

5.3 只读事务

@Transactional(readOnly = true)
public BigDecimal getAccountBalance(Long accountId) {
    // 只读操作,可以优化性能
    return accountDao.getBalance(accountId);
}

六、分布式事务

6.1 JTA与XA事务

对于跨多个数据源或消息队列的分布式事务,可以使用JTA。

配置示例

@Configuration
@EnableTransactionManagement
public class JtaTransactionConfig {
    
    @Bean
    public JtaTransactionManager transactionManager() {
        return new JtaTransactionManager();
    }
}

6.2 Spring的分布式事务解决方案

  1. XA协议:传统两阶段提交
  2. TCC模式:Try-Confirm-Cancel
  3. SAGA模式:长事务解决方案
  4. 本地消息表:最终一致性
  5. Seata:阿里巴巴开源的分布式事务解决方案

七、常见问题与解决方案

7.1 事务失效的常见场景

场景

原因

解决方案

方法非public

Spring AOP限制

改为public方法

自调用

代理失效

注入自身或使用AopContext

异常被捕获

异常未传播

重新抛出或设置rollbackFor

数据库不支持

如MyISAM引擎

使用InnoDB引擎

传播行为设置错误

如NOT_SUPPORTED

调整传播行为

7.2 自调用问题解决方案

问题代码

@Service
public class OrderService {
    
    public void createOrder(Order order) {
        validateOrder(order);
        // 其他逻辑...
    }
    
    @Transactional
    public void validateOrder(Order order) {
        // 验证逻辑
    }
}

解决方案1:注入自身

@Service
public class OrderService {
    
    @Autowired
    private OrderService self; // 注入自身
    
    public void createOrder(Order order) {
        self.validateOrder(order); // 通过代理调用
        // 其他逻辑...
    }
    
    @Transactional
    public void validateOrder(Order order) {
        // 验证逻辑
    }
}

解决方案2:使用AopContext

@Service
public class OrderService {
    
    public void createOrder(Order order) {
        ((OrderService) AopContext.currentProxy()).validateOrder(order);
        // 其他逻辑...
    }
    
    @Transactional
    public void validateOrder(Order order) {
        // 验证逻辑
    }
}

八、性能优化与最佳实践

8.1 事务性能优化建议

  1. 尽量缩短事务范围:只在必要的地方使用事务
  2. 合理设置隔离级别:不要过度使用SERIALIZABLE
  3. 避免大事务:将大事务拆分为多个小事务
  4. 合理使用只读事务:对查询操作使用readOnly=true
  5. 注意异常处理:避免不必要的回滚

8.2 事务最佳实践

  1. 事务注解应放在实现类上:而不是接口
  2. 明确指定回滚异常:使用rollbackFor明确指定
  3. 避免在事务中处理耗时操作:如RPC调用、IO操作等
  4. 合理设置超时时间:避免长时间占用连接
  5. 注意事务传播行为的选择:根据业务场景选择合适的传播行为

九、完整案例演示

9.1 电商下单完整事务案例

@Service
public class OrderServiceImpl implements OrderService {
    
    @Autowired
    private OrderDao orderDao;
    
    @Autowired
    private ProductDao productDao;
    
    @Autowired
    private AccountDao accountDao;
    
    @Autowired
    private CouponDao couponDao;
    
    @Autowired
    private InventoryService inventoryService;
    
    @Transactional(propagation = Propagation.REQUIRED, 
                  isolation = Isolation.READ_COMMITTED,
                  timeout = 30,
                  rollbackFor = {BusinessException.class, RuntimeException.class})
    @Override
    public OrderResult createOrder(OrderRequest request) throws BusinessException {
        // 1. 验证订单基本信息
        validateOrderRequest(request);
        
        // 2. 锁定库存(使用REQUIRES_NEW传播行为,独立事务)
        inventoryService.lockInventory(request.getProductId(), request.getQuantity());
        
        // 3. 扣减账户余额
        deductAccountBalance(request.getUserId(), request.getTotalAmount());
        
        // 4. 使用优惠券(如果有)
        if (request.getCouponId() != null) {
            useCoupon(request.getUserId(), request.getCouponId());
        }
        
        // 5. 创建订单
        Order order = createOrderRecord(request);
        
        // 6. 发送创建订单事件(异步,不影响主事务)
        sendOrderCreatedEvent(order);
        
        return convertToResult(order);
    }
    
    private void validateOrderRequest(OrderRequest request) throws BusinessException {
        // 验证逻辑...
        if (request.getQuantity() <= 0) {
            throw new BusinessException("购买数量必须大于0");
        }
    }
    
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void lockInventory(Long productId, int quantity) throws BusinessException {
        // 锁定库存逻辑...
    }
    
    private void deductAccountBalance(Long userId, BigDecimal amount) throws BusinessException {
        // 扣减余额逻辑...
    }
    
    @Transactional(propagation = Propagation.MANDATORY)
    public void useCoupon(Long userId, Long couponId) throws BusinessException {
        // 使用优惠券逻辑...
    }
    
    private Order createOrderRecord(OrderRequest request) {
        // 创建订单记录逻辑...
    }
    
    private void sendOrderCreatedEvent(Order order) {
        // 异步发送事件...
    }
}

十、事务监控与调试

10.1 日志配置

在application.properties中添加:

# 开启Spring事务日志
logging.level.org.springframework.transaction.interceptor=TRACE
logging.level.org.springframework.jdbc.datasource.DataSourceTransactionManager=DEBUG
logging.level.org.springframework.orm.jpa.JpaTransactionManager=DEBUG

10.2 使用TransactionSynchronization

可以在事务的不同阶段执行回调:

@Transactional
public void businessMethod() {
    // 业务逻辑...
    
    TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
        @Override
        public void afterCommit() {
            // 事务提交后执行
            sendNotification();
        }
        
        @Override
        public void afterCompletion(int status) {
            // 事务完成后执行(status: 0=提交, 1=回滚)
            cleanUpResources();
        }
    });
}

总结

SpringBoot事务管理是开发企业级应用的重要部分。通过本文的全面介绍,你应该已经掌握了:

  1. 事务的基本概念和ACID特性
  2. SpringBoot事务的配置和使用方式
  3. 声明式和编程式事务的实现
  4. 事务传播行为和隔离级别的详细解析
  5. 高级特性和常见问题的解决方案
  6. 分布式事务的基本概念
  7. 性能优化和最佳实践

关注我?别别别,我怕你笑出腹肌找我赔钱。


头条对markdown的文章显示不太友好,想了解更多的可以关注微信公众号:“Eric的技术杂货库”,后期会有更多的干货以及资料下载。

相关推荐

redis的八种使用场景

前言:redis是我们工作开发中,经常要打交道的,下面对redis的使用场景做总结介绍也是对redis举报的功能做梳理。缓存Redis最常见的用途是作为缓存,用于加速应用程序的响应速度。...

基于Redis的3种分布式ID生成策略

在分布式系统设计中,全局唯一ID是一个基础而关键的组件。随着业务规模扩大和系统架构向微服务演进,传统的单机自增ID已无法满足需求。高并发、高可用的分布式ID生成方案成为构建可靠分布式系统的必要条件。R...

基于OpenWrt系统路由器的模式切换与网页设计

摘要:目前商用WiFi路由器已应用到多个领域,商家通过给用户提供一个稳定免费WiFi热点达到吸引客户、提升服务的目标。传统路由器自带的Luci界面提供了工厂模式的Web界面,用户可通过该界面配置路...

这篇文章教你看明白 nginx-ingress 控制器

主机nginx一般nginx做主机反向代理(网关)有以下配置...

如何用redis实现注册中心

一句话总结使用Redis实现注册中心:服务注册...

爱可可老师24小时热门分享(2020.5.10)

No1.看自己以前写的代码是种什么体验?No2.DooM-chip!国外网友SylvainLefebvre自制的无CPU、无操作码、无指令计数器...No3.我认为CS学位可以更好,如...

Apportable:拯救程序员,IOS一秒变安卓

摘要:还在为了跨平台使用cocos2d-x吗,拯救objc程序员的奇葩来了,ApportableSDK:FreeAndroidsupportforcocos2d-iPhone。App...

JAVA实现超买超卖方案汇总,那个最适合你,一篇文章彻底讲透

以下是几种Java实现超买超卖问题的核心解决方案及代码示例,针对高并发场景下的库存扣减问题:方案一:Redis原子操作+Lua脚本(推荐)//使用Redis+Lua保证原子性publicbo...

3月26日更新 快速施法自动施法可独立设置

2016年3月26日DOTA2有一个79.6MB的更新主要是针对自动施法和快速施法的调整本来内容不多不少朋友都有自动施法和快速施法的困扰英文更新日志一些视觉BUG修复就不翻译了主要翻译自动施...

Redis 是如何提供服务的

在刚刚接触Redis的时候,最想要知道的是一个’setnameJhon’命令到达Redis服务器的时候,它是如何返回’OK’的?里面命令处理的流程如何,具体细节怎么样?你一定有问过自己...

lua _G、_VERSION使用

到这里我们已经把lua基础库中的函数介绍完了,除了函数外基础库中还有两个常量,一个是_G,另一个是_VERSION。_G是基础库本身,指向自己,这个变量很有意思,可以无限引用自己,最后得到的还是自己,...

China&#39;s top diplomat to chair third China-Pacific Island countries foreign ministers&#39; meeting

BEIJING,May21(Xinhua)--ChineseForeignMinisterWangYi,alsoamemberofthePoliticalBureau...

移动工作交流工具Lua推出Insights数据分析产品

Lua是一个适用于各种职业人士的移动交流平台,它在今天推出了一项叫做Insights的全新功能。Insights是一个数据平台,客户可以在上面实时看到员工之间的交流情况,并分析这些情况对公司发展的影响...

Redis 7新武器:用Redis Stack实现向量搜索的极限压测

当传统关系型数据库还在为向量相似度搜索的性能挣扎时,Redis7的RedisStack...

Nginx/OpenResty详解,Nginx Lua编程,重定向与内部子请求

重定向与内部子请求Nginx的rewrite指令不仅可以在Nginx内部的server、location之间进行跳转,还可以进行外部链接的重定向。通过ngx_lua模块的Lua函数除了能实现Nginx...