事务四大特性(( 简称 ACID)
- 原子性(Atomicity):事务中的全部操作在数据库中是不可分割的,要么全部完成,要么均不执行。
- 一致性(Consistency)(其他特性的基础):几个并行执行的事务,其执行结果必须与按某一顺序串行执行的结果相一致。**事务必须是使数据库从一个一致性状态变到另一个一致性状态。**多个账户钱的总和不变
- 隔离性(Isolation):事务的执行不受其他事务的干扰,事务执行的中间结果对其他事务必须是透明的。(即事务隔离级别)(转钱时,从其他用户角度看)
- 持久性(Durability):对于任意已提交事务,系统必须保证该事务对数据库的改变不被丢失,即使数据库出现故障。
事务隔离级别
-
脏读
脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。 当一个事务正在多次修改某个数据都还未提交,这时另一个并发的事务来访问该数据,就会造成两个事务得到的数据不一致。例如:用户 A 向用户 B 转账 100 元当只执行第一条 SQL 时,A 通知 B 查看账户,B 发现确实钱已到账(此时即发生了脏读),而之后无论第二条 SQL 是否执行,只要该事务不提交,则所有操作都将回滚,那么当 B 以后再次查看账户时就会发现钱其实并没有转。
-
不可重复读
不可重复读是指在对于数据库中的某个数据,一个事务范围内多次相同查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。不可重复读出现的原因就是事务并发修改记录,要避免这种情况,最简单的方法就是对要修改的记录加锁,这回导致锁竞争加剧,影响性能。另一种方法是通过 MVCC 可以在无锁的情况下,避免不可重复读。
例如事务 T1 在读取某一数据,而事务 T2 立马修改了这个数据并且提交事务给数据库,事务 T1 再次读取该数据就得到了不同的结果,发送了不可重复读。
不可重复读和脏读的区别是,脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。
-
虚读(幻读)
在同一个事务中,同一个查询多次返回的结果不一致。事务 A 新增了一条记录,事务 B在事务 A 提交前后各执行了一次查询操作,发现后一次比前一次多了一条记录。就好像产生幻觉一样,这就是发生了幻读。幻读是由于并发事务增加记录导致的,这个不能像不可重复读通过记录加锁解决,因为对于新增的记录根本无法加锁。需要将事务串行化,才能避免。
幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。
MySQL 数据库的四种隔离级别(从低到高、为解决并发事务问题):
-
Read uncommitted (读未提交):最低级别,任何情况都无法保证。
-
Read committed (读已提交):只有在事务提交后,其更新结果才会被其他事务看见。可避免脏读的发生。
-
Repeatable read (可重复读):在一个事务中,对于同一份数据的读取结果总是相同的,无论是否有其他事务对这份数据进行操作,以及这个事务是否提交。可避免脏读、不可重复读的发生。
缺点:早晨9点开始开启了事务,只要事务不结束,到晚上9点,读到的数据还是那样!读到的是假象。不够绝对的真实
-
Serializable (串行化):事务串行化执行,隔离级别最高,牺牲了系统的并发性。可避免脏读、不可重复读、幻读的发生。
隔离级别 | 脏读可能性 | 不可重复读可能性 | 幻读可能性 | 加锁读 |
---|---|---|---|---|
read uncommitted | yes | yes | yes | no |
read commited | no | yes | yes | no |
repeatable read | no | no | yes | no |
serializable | no | no | no | yes |
在 MySQL 数据库中,支持上面四种隔离级别,默认的为 **Repeatable read (可重复读);**而在 Oracle 数据库中,**只支持 Serializable (串行化)级别和 Read committed (读已提交)这两种级别,**其中默认的为 Read committed 级别