目录
- 事务的概念
- 为何需要事务
- 事务异常的原因
- 解决方案
- 1、方案1(一般采用这种)
- 2、方案2
事务的概念
事务这个词,其实我们最先接触的地方应该是数据库,我们会知道事务有着四种特性,分别是:
- 原子性:表示事务执行过程中的任何失败都将导致事务所做的任何修改失效。
- 一致性:表示当事务执行失败时,所有被该事务影响的数据都应该恢复到事务执行前的状态。
- 隔离性:表示在事务执行过程中对数据的修改,在事务提交之前对其他事务不可见。
- 持久性:表示已提交的数据在事务执行失败时,数据的状态都应该正确。
说白了,事务也就是一组sql的指令,每个sql都是事务的一部分
假设每条sql都执行完成并且成功了,那就说明这组sql执行生效了,虽然执行了事务,但是并不影响原来sql的执行;反之如果出现了错误,那就需要事务启动了,事务会将之前的sql进行一一回滚,这条事务也就结束了,原先的sql等于都没有执行,这一组的事务执行失败
为何需要事务
体现到java中来也是一样,我们的程序有时候会不止一次的影响数据库,而如果中间有一次sql执行失败,而前面的sql已经执行,那前面的数据已经创建或者修改了,而另外一条或者多条数据依然没有发生变化,这肯定不符合正常的逻辑:哪怕报错了也不能影响其他的业务!
就像是沃兹基曾经说过:全荣才荣,一损俱损,只要有一处地方产生了错误,这一整个物件就等于坏了,雪崩的时候没有一片雪花是无辜的
而事务是为解决数据安全操作提出的,事务控制实际上就是控制数据的安全访问
事务异常的原因
例如我们这边来看一下这个事务异常出现的原因,首先来看一下代码:
很好!一个大事务里面套了一个小事务,然后又用try-catch捕获小事务,导致连错误的提示都没有了,内层事务在一定场景下抛出了异常,但是却被外层事务用try–catch接住了。于是在内层事务异常的情况下,外层事务继续执行了。
如果只是没有异常提示倒还说,我们一步一步debug也能找到出错的原因,但是如果两个事务关联到了相同的表或者数据,那就容易产生一个更大的问题:lock wait timeout exceeded; try restarting transaction,也就是死锁问题,两个事务共同争取同一个资源,导致循环等待,这个问题有时间再细讲
解决方案
1、方案1(一般采用这种)
如果在确定里层方法不需要使用事务注解的话,把里层的@Transactional注解去了,因为外层本身就有事务注解,不会因为里层的方法体写到另外一个地方就不会执行事务
2、方案2
如果在确定外层事务不会修改数据库的话(例如查询),就可以去除外部的@Transactional