Spring Boot(四)开启声明式事务

本文介绍如何在SpringBoot中使用事务管理,通过示例演示如何在MyBatis服务层添加事务,并在控制器中调用,同时讨论了事务回滚的常见问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简介

以前用Spring想要用事务的时候,都需要自己在spring的配置文件中配置事务管理器。而Spring Boot则默认对jpa,jdbc,mybatis开启了事务,引入他们的依赖的时候,事务就开启了。使用事务只需要一个@Transactional注解就可以了。

准备

以上一篇文章【Spring Boot(三)整合MyBatis,Mybatis Generator】为例,演示事务的使用。

修改代码

在IUserService.java中添加增加员工的方法

public interface IUserService {
    User get(Integer id);
    User insert(User user) throws Exception;
}

在UserServiceImpl.java中实现该方法

@Service("iUserService")
public class UserServiceImpl implements IUserService {
    @Autowired
    private UserMapper userMapper;

    @Override
    public User get(Integer id) {
        return userMapper.selectByPrimaryKey(id);
    }

    @Override
    @Transactional
    public User insert(User user) throws Exception{
        userMapper.insert(user);
        throw new RuntimeException();
    }
}

在Controller中添加插入用户的方法

@RestController
public class UserController {

    @Autowired
    private IUserService iUserService;

    @GetMapping("/get_user/{userId}")
    public User getUser(@PathVariable("userId") Integer userId){
        User user =iUserService.get(userId);
        return user;
    }

    @PostMapping("/add_user")
    public String addUser(User user){
        try {
            iUserService.insert(user);
            return "插入成功";
        } catch (Exception e) {
            e.printStackTrace();
            return "插入失败";
        }
    }
}

测试

这里,在UserServiceImpl的insert方法中使用了@Transactional注解开启事务。方法体中抛出一个运行时异常,所以客户端调用add_user方法时,不会插入数据到数据库。

常见问题

1、spring事务默认的事务规则是对运行时异常(RuntimeException)和程序错误(Error)才会回滚。如果针对非检测异常进行事务回滚,则可以在@Transactional中设置rollbackFor属性声明指定回滚异常:

@Override
@Transactional(rollbackFor = Exception.class)
public User insert(User user) throws Exception{
    userMapper.insert(user);
    throw new SQLException("发生了sql异常");
}

2、如果在业务层的异常被捕获了,则不会触发事务回滚。可以在异常中使用TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 进行手动回滚。

### Java Spring Boot 声明式事务最佳实践与示例 #### 1. 配置事务管理器 在 Spring Boot 中,声明式事务的核心是配置一个事务管理器。通常使用 `DataSourceTransactionManager` 来管理 JDBC 数据源的事务[^2]。以下是一个基于注解的事务管理器配置示例: ```java import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import javax.sql.DataSource; @Bean public DataSourceTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } ``` #### 2. 启用注解驱动的事务支持 为了启用注解驱动的事务支持,需要在启动类上添加 `@EnableTransactionManagement` 注解[^4]。例如: ```java import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.transaction.annotation.EnableTransactionManagement; @SpringBootApplication @EnableTransactionManagement public class SpringBootTxApplication { public static void main(String[] args) { SpringApplication.run(SpringBootTxApplication.class, args); } } ``` #### 3. 使用 `@Transactional` 注解 `@Transactional` 注解可以作用于类或方法上,用于声明事务边界。以下是一个典型的 `@Transactional` 示例: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service public class OrderService { @Autowired private OrderRepository orderRepository; @Transactional public void placeOrder(Order order) { orderRepository.save(order); // 其他业务逻辑 } } ``` #### 4. 设置事务属性 `@Transactional` 注解支持多种属性,包括传播行为、隔离级别、超时时间等。例如,设置事务的传播行为为 `REQUIRES_NEW`: ```java import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @Transactional(propagation = Propagation.REQUIRES_NEW) public void createNewTransaction() { // 新的事务逻辑 } ``` #### 5. 处理异常回滚 默认情况下,Spring 只会在运行时异常(如 `RuntimeException`)或错误(如 `Error`)时回滚事务。如果需要在其他异常类型下回滚,可以通过 `rollbackFor` 属性指定。例如: ```java import org.springframework.transaction.annotation.Transactional; @Transactional(rollbackFor = Exception.class) public void processOrder() throws Exception { // 业务逻辑 } ``` #### 6. 最佳实践 - **避免在 Setter 方法上使用 `@Transactional`**:Setter 方法通常是轻量级操作,不应涉及事务逻辑。 - **将事务边界定义在服务层**:通常将 `@Transactional` 放置在服务层,而不是 DAO 层[^3]。 - **明确指定事务的传播行为**:根据业务需求选择合适的传播行为,例如 `REQUIRED` 或 `REQUIRES_NEW`。 - **监控事务性能**:通过 AOP 或日志记录工具监控事务的执行时间和回滚情况。 #### 7. 示例代码 以下是一个完整的基于注解的声明式事务示例: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service public class UserService { @Autowired private UserRepository userRepository; @Transactional public void registerUser(User user) { userRepository.save(user); // 模拟业务逻辑 if (user.getName().equals("error")) { throw new RuntimeException("注册失败"); } } } ``` #### 8. 测事务 为了验证事务的行为,可以通过单元测模拟不同场景。以下是一个基于 JUnit 的测示例: ```java import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest public class UserServiceTest { @Autowired private UserService userService; @Test public void testRegisterUser() { User user = new User(); user.setName("test"); user.setEmail("test@example.com"); userService.registerUser(user); assertNotNull(user.getId()); } @Test public void testRegisterUserWithError() { User user = new User(); user.setName("error"); user.setEmail("error@example.com"); assertThrows(RuntimeException.class, () -> userService.registerUser(user)); } } ``` #### 注意事项 - 确保事务管理器正确配置并引用正确的数据源。 - 默认情况下,事务只会在运行时异常或错误时回滚。如果需要在其他异常类型下回滚,必须显式指定 `rollbackFor` 属性。 - 在分布式系统中,可能需要考虑分布式事务的解决方案,例如使用两阶段提交或补偿机制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值