在MySQL中简单的了解过事务,简单说事务就是把一组操作封装成一个执行单元,要么全部成功,要么全部失败。
在一次转账中,第一步A减去一百元,第二步B增加一百元。如果没有事务,第一步执行成功了,但是第二步失败了,那么A的一百元就会平白无故的丢失。使用事务就可以解决这个问题,让这一组操作要么一起成功,要么一起失败。
编程式事务
编程式事务也就是手动写代码操作事务,有三个重要的步骤:
- 开启事务(获取事务)
- 提交事务
- 回滚事务
SpringBoot内置了两个对象,DataSourceTransactionManager用来获取事务、提交或回滚事务。而TransactionDefinition是事务的属性,在获取事务的时候需要将TransactionDefinition传递进去从而获得一个事务TransactionStatus。
我们需要借助事务管理器来开启事务。并且提交事务和回滚事务通过commit和rollback来完成。
声明式事务
编程式事务虽然可以实现事务,但是操作也很繁琐,可以使用声明式事务来完成。
使用@Transactional注解就可以实现,无需手动开启事务和提交事务,进入方法时自动开启事务,方法执行完会自动提交事务,如果中途发生了没有处理的异常会自动回滚事务。
@Transactional
- 修饰方法:只能应用到public方法上,否则不生效
- 修饰类:表名对这个类中所有的public方法都生效
如果@Transactional在异常被捕获的情况下,是不会进行事务的自动回滚:
此时有两种解决方案:
1.重新将异常抛出去:
2.手动回滚事务
手动回滚事务,在方法中使用 TransactionAspectSupport.currentTransactionStatus() 可以得到当前的事务,然后设置回滚方法 setRollbackOnly 就可以实现回滚了。
@Transactional工作原理
事务隔离级别
事务有四大特性(AICD),原子性、持久性、一致性和隔离性。而这四种特性中,只有隔离性(隔离级别)是可以设置的。设置事务的隔离级别可以用来保障多个并发事务执行更可控、更符合操作者的预期。
MySQL 事务隔离级别有 4 种:
- READ UNCOMMITTED:读未提交,也叫未提交读,脏读。
- READ COMMITTED:读已提交,也叫提交读,不可重复读。
- REPEATABLE READ::可重复读,是 MySQL 的默认事务隔离级别,幻读。
- SERIALIZABLE:序列化,事务最⾼隔离级别,不会出现冲突问题。
在SQL中通过select @@global.tx_isolation,@@tx_isolation;来查询全局事务隔离级别和当前连接的事务隔离级别:
Spring事务隔离级别有5种:
- Isolation.DEFAULT:以连接的数据库的事务隔离级别为主。
- Isolation.READ_UNCOMMITTED:读未提交,可以读取到未提交的事务,存在脏读。
- Isolation.READ_COMMITTED:读已提交,只能读取到已经提交的事务,解决了脏读,存在不可重复读。
- Isolation.REPEATABLE_READ:可重复读,解决了不可重复读,但存在幻读(MySQL默认级别)。
- Isolation.SERIALIZABLE:串行化,可以解决所有并发问题,但性能太低。
事务传播机制
事务隔离级别解决的是同时调用一个数据库的问题,而事务传播机制解决的是多个事物同时调用数据库的问题。
http://t.csdnimg.cn/myv2qhttp://t.csdnimg.cn/myv2q