Spring中的事务和事务的传播机制
事务是一组操作的集合,不可以被分割。事务会把所有的操作作为一个整体,这组操作要么全部成功,要么全部失败。
(图片来源网络,侵删)
事务有三种操作:
- 开启事务;
- 提交事务;
- 回滚事务。
如果代码的执行逻辑是这样:
开启事务 业务A 回滚事务
此时A当中的所有操作都不会生效
开启事务 业务A 提交事务
开启事务后只有这种情况下A中的逻辑才会生效
Spring中事务的实现有两种
编程式(手动操作事务)
Spring Boot对于事务操作内置了两个类,我们在使用时可以选择直接注入:
- DataSourceTransactionManager:事务管理器,里面包含了事务的操作和获取;
- TransactionDefinition:事务的属性。在获取事务时需要充当参数。
提交事务
@Slf4j @RestController @RequestMapping("/trans") public class Test { //获取事务管理器 @Autowired private DataSourceTransactionManager dataSourceTransactionManager; //获取事务属性 @Autowired private TransactionDefinition definition; @Autowired private UserMapper userMapper; @RequestMapping("/fun1") public void fun1() { //获取并开启事务 TransactionStatus transaction = dataSourceTransactionManager.getTransaction(definition); //业务操作 //向数据库中插入一条数据 userMapper.userInsert("zhangsan","man"); //打印日志 log.info("数据插入完成"); //提交事务 dataSourceTransactionManager.commit(transaction); } }
@Mapper public interface UserMapper { @Insert("insert into userinfo(username,gender) values (#{userName},#{gender});") void userInsert(String userName, String gender); }
这是数据库的初始状态
(图片来源网络,侵删)代码执行后数据成功插入
回滚事务
@RequestMapping("/fun1") public void fun1() { //获取并开启事务 TransactionStatus transaction = dataSourceTransactionManager.getTransaction(definition); //业务操作 userMapper.userInsert("zhangsan","man"); log.info("数据插入完成"); //提交事务 // dataSourceTransactionManager.commit(transaction); //回滚事务 dataSourceTransactionManager.rollback(transaction); }
当代码执行成功后,数据库中的数据并没有变多。
注解式(利用注解自动实现事务)
使用注解实现事务是非常简单的只需要给需要添加事务的方法加上@Transactional注解。添加该注解后程序会自动的在方法开始前开启事务,在方法结束后提交事务;如果在方法执行中发生了没有处理的异常会自动进行回滚事务。
@Transactional既可以修饰方法也可以修饰类:
(图片来源网络,侵删)- 修饰方法时该方法必须是被public修饰的方法,否则既不会生效也不会报错;
- 当修饰类时,会对该类中的所有被public修饰的方法生效。
当方法正常执行完毕后会自动提交事务 :
@Slf4j @RestController @RequestMapping("/trans") public class Test { @Autowired private UserMapper userMapper; @Transactional @RequestMapping("/fun2") public void fun2() { userMapper.userInsert("lisi","man"); log.info("数据插入完成"); } }
当方法执行过程中发生异常时自动回滚事务 (该注解默认只回滚运行时异常和错误):
发生运行时异常,事务回滚:
@Slf4j @RestController @RequestMapping("/trans") public class Test { @Autowired private UserMapper userMapper; @Transactional @RequestMapping("/fun2") public void fun2() { userMapper.userInsert("lisi111","man"); log.info("数据插入完成"); //发生运行时异常,事务回滚 throw new RuntimeException(); } }
编译时异常不会回滚:
@Slf4j @RestController @RequestMapping("/trans") public class Test { @Autowired private UserMapper userMapper; @Transactional @RequestMapping("/fun2") public void fun2() throws IOException { userMapper.userInsert("lisi111","man"); log.info("数据插入完成"); //发生编译时异常,事务不会回滚 throw new IOException(); } }
此时尽管程序已经报错了,可数据还是正常插入了。如何解决这个问题呢?
rollbackFor
可以通过配置 @Transactional 注解当中的 rollbackFor 属性,通过 rollbackFor 这个属性来指定出现何种异常类型时事务进行回滚。
这个属性的类型是数组需要注意
Class
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。
还没有评论,来说两句吧...