隔离级别
事务的隔离级别是指多个事务同时执行时,各自的操作对其他事务是否可见以及是否会相互影响的程度。常见的事务隔离级别有四种,分别是读未提交(Read Uncommitted)、读已提交(Read Committed)、可重复读(Repeatable Read)和串行化(Serializable)。
- 读未提交(Read Uncommitted)在该隔离级别下,一个事务可以读取另一个事务还未提交的数据,可能会发生脏读(Dirty Read)问题。因为其他事务对数据的修改可以立即对本事务可见,而且可能会被回滚,这种级别的隔离性非常低。
- 读已提交(Read Committed)在该隔离级别下,一个事务只能读取已经提交的数据,不能读取其他事务还未提交的数据,可以避免脏读的问题。但是由于其他事务对数据进行的修改,需要等到其提交之后才能对本事务可见,因此可能会出现不可重复读(Non-repeatable Read)问题。
- 可重复读(Repeatable Read)在该隔离级别下,一个事务在执行期间多次读取同一个数据时,得到的结果都是一样的。其他事务对数据的修改只有在本事务提交之后才会对本事务可见。这种隔离级别可以避免不可重复读的问题。
- 串行化(Serializable)在该隔离级别下,多个事务串行执行,相当于将并发执行的事务序列化,可以避免脏读、不可重复读和幻读(Phantom Read)等问题。但是,由于只允许串行执行,因此效率非常低下,通常不建议使用。
在Spring中,可以通过在@Transactional注解中指定isolation属性来设置事务的隔离级别,默认情况下使用数据库的默认隔离级别。
MySQL事务隔离
Spring JDBC事务依赖数据库实现的,隔离级别也是依赖数据库的隔离级别。
MySQL提供了四种事务隔离级别,默认的隔离级别是 REPEATABLE READ。可以使用 SET TRANSACTION ISOLATION LEVEL 命令设置事务隔离级别。
MySQL 查看和设置隔离级别的命令:
-- 查看当前事物级别:
SELECT @@tx_isolation; # MariaDB 10
SELECT @@transaction_isolation; # MYSQL8
SELECT @@SESSION.transaction_isolation; # MYSQL8
-- 设置mysql的隔离级别:
set session transaction isolation level 需要设置的事务隔离级别
-- 设置read uncommitted级别:
set session transaction isolation level read uncommitted;
-- 设置read committed级别:
set session transaction isolation level read committed;
-- 设置repeatable read级别:
set session transaction isolation level repeatable read;
-- 设置serializable级别:
set session transaction isolation level serializable;
在Spring中,可以通过在@Transactional注解中指定isolation属性来设置事务的隔离级别,在Spring设置属性最终会在MySQL中设置为MySQL事务隔离级别。不设置隔离级别,将采用MySQL的默认的REPEATABLE READ。
在大多数情况下,应该在业务层方法上全部标注事务注解,以启用声明式事务功能。这样可以确保方法的整体性,以及数据库操作的一致性。但是,对于特殊情况,例如只读操作或者特定操作,可以根据实际情况灵活处理。
MySQL事务隔离示例
下述案例可以采用两个终端窗口同时进行演示事务并发期间的隔离现象:
READ UNCOMMITTED(未提交读):一个事务可以读取另一个未提交的事务中的数据,出现脏读:
READ COMMITTED(已提交读):一个事务只能读取另一个已经提交的事务中的数据,可以避免脏读,但是会出现不可重复读,也即是在一个事务期间两次读取结果不同!
REPEATABLE READ(可重复读):一个事务在执行过程中看到的数据始终保持一致,即使其他事务对数据进行了修改,该事务也只能读取到自己启动之前的数据版本。可避免脏读和不可重复读问题,但是幻读问题仍然存在:
SERIALIZABLE(可串行化):最高的隔离级别,强制所有事务串行执行,避免脏读、不可重复读、幻读等问题,但是会降低并发性能,不推荐在高并发系统中使用。
总结
事务的隔离级别是指多个事务同时执行时,各自的操作对其他事务是否可见以及是否会相互影响的程度
常见的事务隔离级别有四种
- 读未提交(Read Uncommitted)
- 读已提交(Read Committed)
- 可重复读(Repeatable Read)
- 串行化(Serializable)