事务管理在Spring Boot项目的介绍
新建的Spring Boot
项目中,一般都会引用spring-boot-starter
或者spring-boot-starter-web
,而这两个起步依赖中都已经包含了对于spring-boot-starter-jdbc
或spring-boot-starter-data-jpa
的依赖。 当我们使用了这两个依赖的时候,框架会自动默认分别注入DataSourceTransactionManager
或JpaTransactionManager
。 所以我们不需要任何额外配置就可以用@Transactional
注解进行事务的使用。
例如用户新增需要插入用户表、用户与岗位关联表、用户与角色关联表,如果插入成功,那么一起成功,如果中间有一条出现异常,那么回滚之前的所有操作, 这样可以防止出现脏数据,就可以使用事务让它实现回退。
做法非常简单,我们只需要在方法或类添加@Transactional
注解即可。
@Transactional public int insertUser(User user) { // 新增用户信息 int rows = userMapper.insertUser(user); // 新增用户岗位关联 insertUserPost(user); // 新增用户与角色管理 insertUserRole(user); return rows; }
- 常见坑点1:遇到检查异常时,事务开启,也无法回滚。 例如下面这段代码,用户依旧增加成功,并没有因为后面遇到检查异常而回滚!!
@Transactional public int insertUser(User user) throws Exception { // 新增用户信息 int rows = userMapper.insertUser(user); // 新增用户岗位关联 insertUserPost(user); // 新增用户与角色管理 insertUserRole(user); // 模拟抛出SQLException异常 boolean flag = true; if (flag) { throw new SQLException("发生异常了.."); } return rows; }
@Transactional(rollbackFor = Exception.class) public int insertUser(User user) throws Exception { // 新增用户信息 int rows = userMapper.insertUser(user); // 新增用户岗位关联 insertUserPost(user); // 新增用户与角色管理 insertUserRole(user); // 模拟抛出SQLException异常 boolean flag = true; if (flag) { throw new SQLException("发生异常了.."); } return rows; }
- 常见坑点2: 在业务层捕捉异常后,发现事务不生效。 这是许多新手都会犯的一个错误,在业务层手工捕捉并处理了异常,你都把异常“吃”掉了,
Spring
自然不知道这里有错,更不会主动去回滚数据。
例如:下面这段代码直接导致用户新增的事务回滚没有生效。
@Transactional public int insertUser(User user) throws Exception { // 新增用户信息 int rows = userMapper.insertUser(user); // 新增用户岗位关联 insertUserPost(user); // 新增用户与角色管理 insertUserRole(user); // 模拟抛出SQLException异常 boolean flag = true; if (flag) { try { // 谨慎:尽量不要在业务层捕捉异常并处理 throw new SQLException("发生异常了.."); } catch (Exception e) { e.printStackTrace(); } } return rows; }
推荐做法:在业务层统一抛出异常,然后在控制层统一处理。
@Transactional public int insertUser(User user) throws Exception { // 新增用户信息 int rows = userMapper.insertUser(user); // 新增用户岗位关联 insertUserPost(user); // 新增用户与角色管理 insertUserRole(user); // 模拟抛出SQLException异常 boolean flag = true; if (flag) { throw new RuntimeException("发生异常了.."); } return rows; }
TransactionDefinition
传播行为的常量:
常量 | 含义 |
---|---|
TransactionDefinition.PROPAGATION_REQUIRED | 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。 |
TransactionDefinition.PROPAGATION_REQUIRES_NEW | 创建一个新的事务,如果当前存在事务,则把当前事务挂起。 |
TransactionDefinition.PROPAGATION_SUPPORTS | 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。 |
TransactionDefinition.PROPAGATION_NOT_SUPPORTED | 以非事务方式运行,如果当前存在事务,则把当前事务挂起。 |
TransactionDefinition.PROPAGATION_NEVER | 以非事务方式运行,如果当前存在事务,则抛出异常。 |
TransactionDefinition.PROPAGATION_MANDATORY | 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。 |
TransactionDefinition.PROPAGATION_NESTED | 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。 |