MySQL数据库事物的4大特性:
事务ACID属性,即原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。
四大隔离级别:
由低到高依次为Readuncommitted、Readcommitted、Repeatableread、Serializable。
隔离级别(Isolation level) | 脏读(Dirty reads) | 不可重复读(Non-repeatable reads) | 幻读(Phantoms) |
未提交读(Read Uncommitted) | 可能发生 | 可能发生 | 可能发生 |
已提交读(Read Committed) | 不会发生 | 可能发生 | 可能发生 |
可重复读(Repeatable Read) | 不会发生 | 不会发生 | 可能发生 |
串行化(Serializable) | 不会发生 | 不会发生 | 不会发生 |
脏读 | 事物1读取到事物2还没有提交的数据 |
可重复读 | 同一个事物两次读取同一条记录,结果却不一致。就是说读取的同时有其他事物修改了这条记录。 |
幻读 | 读取记录时有其它事物同时新增了记录。导致查询到的记录条数和原来不一致了。 |
1 、未提交读(Read Uncommitted)
时间线T | 事物1 | 事物2 |
T1 | 读取账户金额总共500元 | |
T2 | 转出200元 | |
T2 | 再次读取莫名其妙变成了300元 | |
T4 | 事务回滚,将扣掉的200再加回去。提交(commit) | |
T5 | 再次读取又莫名其妙的变成了500元 | |
T6 | 提交(commit) |
分析:事务1读取到事务2还没有提交的数据,这种情况称为脏读,没有数据库会采用这种隔离级别。
2、已提交读(Read Committed)
Oracle 11g, PostgreSQL, SQL Server 2012等都是默认此隔离级别,但MySQL的默认级别是可重复读(Repeatable Read)
官方解释:
当每个对象在写的时候,数据库会记住已经被提交的旧值和当前事务持有写锁设置的新值。
当一个事务还在进行中,那么其他事务读取到的就是旧值。只有当新值被提交的时候才会被其他事务读取到。
通常数据库避免脏写是使用了行级锁,当一个事务想要去修改数据时,
它会首先得到这个数据对象的锁,直到事务提交或者回滚。
而且只有一个事务能够持有这个锁;
如果其他事务想要去写相同的数据对象,它必须等到上一个事务提交或者回滚然后去得到这把锁。
这种锁机制是数据库在read committed或者更高的隔离级别下自动做到的。
这种情况下只能看到其它事物已经提交的数据,
3、可重复读(Repeatable Read)
在一个事物中,查询多次得到的结果是一致的,即使有其它事物修改了正在查询的记录,在该事物中再次查询也得到相同的结果。也就是其它事物修改的结果不会被本事物查询到。如果想要查询到最新的记录,需要commit后再查询。
但是却无法避免幻读,幻读就是读取记录时,有其它事物同时新增了记录。这是查询到的记录条数和原来不一致了。
4、串行化(Serializable)
事物1执行完后事物2才能执行,就和单线程类似,虽说解决了所有问题,但是代价高性能很低,很少使用。