数据库事务具有四个特征,分别是原子性(Atomicity)、一致性(Consistency)、隔离性(Isoation)、持久性(Durability),简称为事务的ACID特性。
事务的隔离性是指在并发环境中,并发的事务是相互隔离的。SQL标准中定义了四种数据库事务隔离级别,级别从低到高分别为:读未提交(Read Uncommitted)、读已提交(Read Committed)、可重复读(Repeatable Read)、串行化(Serializable)。在事务的并发操作中会出现脏读、不可重复读、幻读。在事务的并发操作中第二类更新丢失可以通过乐观锁和悲观锁解决。
一 读未提交(Read Uncommitted)
1. 该隔离级别, 所有的事务都可以看到其他未提交事务的执行结果。通俗的讲就是,在一个事务中可以读取到另一个事务中新增或修改但未提交的数据 2. 该隔离级别可能导致问题的脏读。因为另一个事务可能回滚,所以在第一个事务中读取到的数据很可能是无效的数据,造成脏读现象 > set tx_isolation='READ-UNCOMMITTED';
二 读已提交(Read Committed)
1.这是大多数数据库系统默认的隔离级别(但不是MySQL默认的) 2.一个事务只能看见已经提交事务所做的修改。换句话说,一个事务从开始直到提交之前,所做的任何修改对其他事务都是不可见的 3. 该隔离级别可能导致的问题是不可重复读,两次执行同样的查询,可能会得到不同的结果 > set tx_isolation='READ-COMMITTED';
三 可重复读(Repeatable Read)
1.这是Mysql事务隔离的级别 2. 他确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。通俗来讲,可重复读在一个事务里读取数据,怎么读都不会变,除非提交了该事务,再次进行读取。 3. 该隔离级别存在的问题是幻读 set tx_isolation='REPEATABLE-READ';
下面看如何出现幻读的
四 串行化(Serializable)
1.这是最高的隔离级别 2. 他要通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。通俗的讲就是,假如两个事务都操作到同一数据行,那么这个数据行就会被锁定,只允许先读取/操作到数据行的事务优先操作,只有当事务提交了,数据行才会解锁,后一个事务才能成功操作这个数据行,否则只能一直等待 3. 该隔离级别可能导致大量的超时现象和锁竞争 > set tx_isolation='SERIALIZABLE';
注:
1.这里使用ctime,utime字段进行查询和修改,是为了展示使用非索引字段也有事务隔离效果
2. 在该事务隔离级别中,select语句会自动获取共享锁,update/insert/delete会自动获取排他锁
3. 一个事务中的一行记录的共享锁被拿走,其他事务只能获取该行的共享锁,不能获取排它锁;一个事务中的一行记录的排他锁被拿走,其他事务不能获取该行的共享锁和排他锁
从上面的四种数据库事务隔离级别介绍可以对应出解决的问题,如图:
悲观锁:
悲观锁分为共享锁和排它锁。
共享锁又称为读锁,简称s锁,顾名思义,共享锁就是多个事务对于同一数据可以共享一把锁,共享锁是用来读取数据的。另外一个事务获取了同一数据的共享锁,其他事务就不能获取该数据的排他锁。
排他锁又称为写锁,简称X锁,顾名思义,排它锁就是不能与其他锁共存,如一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁,包括共享锁和排它锁,另外不存什么事务隔离级别,update/insert/delete会自动获取排它锁
共享锁获取方式:select * from account where name='jack' lock in share mode;
排它锁获取方式:select * from account where name='jack' for update;