什么是事务?
所谓事务,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位。
- 例如, 银行转帐工作:从一个帐号扣款并使另一个帐号增款,这两个操作要么都执行,要么都不执行。
事务 ACID 特性
数据库事务必须具备 ACID 特性,ACID 是 Atomic(原子性)、Consistency(一致性)、Isolation(隔离 性)和 Durability(持久性)的英文缩写。
- 原子性:一个事务是一个不可分割的工作单位,要不全部执行,要不全部不执行。
- 一致性:事务执行前和后,必须都保持一致性或完整性。
- 隔离性:一个事务在执行的过程中,不受其他事务的影响。
- 持久性:当一个事提交后,对数据库的改变是永久性的,不会被回滚。
数据库管理系统采用锁机制来实现事务的隔离性。当多个事务同时更新数据库中相同的数据时,只允许持有锁的事务能更新该数据,其他事务必须等待,直到前一个事务释放了锁,其他事务才有机会更新该数据。
并发事务带来的问题
相对于串行处理来说,并发事务处理能大大增加数据库资源的利用率,提高数据库系统的事务吞吐量,从而可以支持可以支持更多的用户。但并发事务处理也会带来一些问题,主要包括以下几种情况。
更新丢失(Lost Update)
:当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题——最后的更新覆盖了其他事务所做的更新。- 例如,两个编辑人员制作了同一文档的电子副本。每个编辑人员独立地更改其副本,然后保存更改后的副本,这样就覆盖了原始文档。最后保存其更改保存其更改副本的编辑人员覆盖另一个编辑人员所做的修改。如果在一个编辑人员完成并提交事务之前,另一个编辑人员不能访问同一文件,则可避免此问题。
脏读(Dirty Reads)
:一个事务正在对一条记录做修改,在这个事务修改并提交前,这条记录的数据就处于不一致状态;这时,另一个事务也来读取同一条记录,如果不加控制,第二个事务读取了这些“脏”的数据,并据此做进一步的处理,就会产生未提交的数据依赖关系。这种现象被形象地叫做“脏读”。- 为什么会出现脏读,因为你对数据库的任何修改都会是立即生效的,至于别人能不能看到主要取决与你 是否加锁了,数据库的执行与事务没有关系,事务只是保证对数据库所做的操作会不会撤销而已,mysql默认是行级锁,修改时只会对修改的那几行加锁,加锁期间其他用户线程是看不到修改结果的,所以会导致不可重复读和幻读的问题;
不可重复读(Non-Repeatable Reads)
:一个事务在读取某些数据已经发生了改变、或某些记录已经被删除了!这种现象叫做“不可重复读”。幻读(Phantom Reads)
:一个事务按相同的查询条件重新读取以前检索过的数- 幻读的原因:因为mysql默认是通过行级锁来实现的,而不是表级锁,那么在修改期间其他线程当然可以新插入数据了;如果使用了mysql表级锁的引擎如:MyIsAM,幻读就不可能出现;
脏读和不可重复读的区别
在于读的时候是否加了读共享锁,不可重复读加了读共享锁;脏读是写的时候加了排他锁
Spring事务
Spring事务的五种隔离级别
隔离级别 | 解释 |
---|---|
DEFAULT:采用 DB 默认的事务隔离级别 | MySql 默认为 REPEATABLE_READ;Oracle 默认为:READ_COMMITTED; |
READ_UNCOMMITTED:读未提交 | 未解决任何并发问题。 |
READ_COMMITTED:读已提交 | 解决脏读,存在不可重复读与幻读。 |
REPEATABLE_READ:可重复读 | 解决脏读、不可重复读。存在幻读。 |
SERIALIZABLE:串行化 | 不存在并发问题。 |
Spring事务的七种传播行为
所谓事务传播行为是指,处于不同事务中的方法在相互调用时,执行期间事务的维护情况。
比如,A 事务中的方法 a() 调用 B 事务中的方法 b(),在调用执行期间事务的维护情况,就称为事务传播行为。事务传播行为是加在方法上的。
REQUIRED
:指定的方法必须在事务内执行。若被调用方法当前存在事务,就加入到调用后的事务中;若被调用方法当前没有事务,则创建一个新事务。这种传播行为也是Spring 默认的事务传播行为
。SUPPORTS
:指定的方法支持当前事务,但若被调用方法当前没有事务,调用方法也可以以非事务方式执行。MANDATORY
:指定的方法必须在当前事务内执行,若被调用方法当前没有事务,则直接抛出异常。REQUIRES_NEW
:总是新建一个事务,若被调用方法当前存在事务,就将当前事务挂起,创建一个新事务(只包含自身),直到新事务执行完毕。NOT_SUPPORTED
:指定的方法不能在事务环境中执行,若被调用方法当前存在事务,就将当前事务挂起。NEVER
:指定的方法不能在事务环境下执行,若被调用方法当前存在事务,就直接抛出异常。NESTED
:指定的方法必须在事务内执行。若当前存在事务,则在嵌套事务内执行;若当前没有事务,则创建一个新事务。
数据库事务
数据库事务的四种隔离级别
隔离级别 | 解释 |
---|---|
READ_UNCOMMITTED:读未提交 | 未解决任何并发问题。 |
READ_COMMITTED:读已提交 | 解决脏读,存在不可重复读与幻读。 |
REPEATABLE_READ:可重复读 | 解决脏读、不可重复读。存在幻读。 |
SERIALIZABLE:串行化 | 不存在并发问题。 |
- 4种事务隔离级别从上往下,级别越高,并发性越差,安全性就越来越高。
看到这儿,聪明的你是不是发现了点什么。
联系
事务原本是数据库中的概念,用于数据访问层。但一般情况下,我们经常在业务层操作数据库,因此需要将事务提升到业务层,即 Service 层。这样做是为了能够使用事务的特性来管理具体的业务。Spring事务本质上其实是使用了数据库的事务,而数据库事务的底层原理是使用了锁机制。
- 总的来说,Spring的事务是对数据库的事务的封装,最后本质的实现还是在数据库。
假如数据库不支持事务的话,Spring的事务是没有作用的。
数据库的事务说简单就只有开启、回滚和关闭。 - Spring对数据库事务的包装,原理就是拿一个数据连接,根据Spring的事务配置,操作这个数据连接对数据库进行事务开启、回滚或关闭操作。但是Spring除了实现这些,还配合Spring的传播行为对事务进行了更广泛的管理。Spring的事务是通过事务管理器
PlatformTransactionManager
接口对象下的实现类进行操作的,其主要用于完成事务的提交、回滚,及获取事务的状态信息。
- PlatformTransactionManager 接口有两个常用的实现类:
- DataSourceTransactionManager:使用 JDBC 或 MyBatis 进行持久化数据时使用。
- HibernateTransactionManager:使用 Hibernate 进行持久化数据时使用。
你知道的越多,你不知道的越多。
有道无术,术尚可求,有术无道,止于术。
如有其它问题,欢迎大家留言,我们一起讨论,一起学习,一起进步