事务的特性
一组批量的SQL语句(insert,update,delete)执行来操作数据库数据,使用事务来处理,保证数据的完整性,要么全部执行,要么全部不执行。这组批量SQL可视为一个完整的逻辑处理工作单元。
比如:转账,借钱的批量更新操作,删除用户所有信息级联删除的操作。
那么事务应满足四个条件(ACID):
-
原子性-Atomicity
事务作为一个整体(不可分割的工作单元),要么全部成功(commit),要么全部失败(rollback)。不可能只执行其中的一部分操作。
-
一致性-Consistency
事务在开启之前和结束之后,数据的完整性没有被破坏。
-
隔离性-Isolation
一个事务的执行,不影响其他事务的执行。即:并发执行的事务之间不能互相干扰。
-
持久性-Durability
已提交的事务对数据的操作是永久的。
MySQL四种隔离级别
隔离级别由低到高:读未提交、读已提交、可重复读、串行化。
MySQL默认隔离级别为可重复读(RR)。
使用select @@tx_isolation;
进行查看。
如果是MySQL 8以上版本,使用select @@transaction_isolation;
查看。
-
读未提交 RU(Read Uncommitted)
对同一条数据,所有的事务都可以看到其他事务未提交的执行结果。
比如事务A,事务B,同时对一条数据操作,即使事务B更新完该条数据后,没有进行提交的操作,事务A也能看到修改后的数据值。
很少用于实际应用。
-
读已提交 RC(Reda Committed)
某事务提交了对数据的修改操作,其他事务就能读取到修改后的数据值,会存在两次查询结果不一致的情况。
比如事务A,先进行该条数据的查询,此时事务B对同条数据进行更新,并提交了事务。那么事务A再进行该条数据的查询结果与开始的查询结果会不一致。
大多数数据库的默认隔离级别是RC。
-
可重复读 RR(Repeatable Reda)
与RC不同的是,在一个事务里,无论执行多少次同一SQL查询,结果都是一样的。
MySQL默认隔离级别是RR。
-
串行化 Serializable
顾名思义,就是事务一个个的执行,等事务A执行完毕以后,事务B才能执行。
因隔离级别不同,读取数据会出现脏读、不可重复读、幻读的情况。
出现的问题
-
脏读
典型的就是RU,事务A对数据进行了更新,此时事务B对该数据进行了操作,事务A这是发生了回滚。那么事务B就读到了脏数据。
-
不可重复度
在一个事务中两次查询结果数据不一致的情况。RC中出现的问题。
-
幻读
同样是在同一个事务中,两次查询结果的数据条数不一致。比如事务A在查询一定区间范围的数据,事务B在此区间内新增或删除了数据,事务A再次查询结果也会出现与第一次查询结果不一致的情况。
如何区分不可重复读与幻读?
不可重复读在于对数据进行了修改,幻读则对数据进行了新增或删除;
要解决不可重复读的问题,锁住满足条件的行即可,要解决幻读,需要进行锁表。
汇总:
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交RU | √ | √ | √ |
读已提交RC | × | √ | √ |
可重复读RR | × | × | √ |
串行化Serializable | × | × | × |
串行化的隔离级别最高,但是效率也是最差的。事务需要排队执行(表锁),也刚好解决了幻读的问题。
MySQL默认隔离级别为RR,虽然会出现幻读,但是InnoDB存储引擎通过MVCC(多版本并发控制 Multiversion Concurrency Control)的机制解决了该问题。
<