引言
什么事事务?事务是一组原子性的SQL语句,这组语句要么全部成功,要么发生失败时全部不执行。一个良好的支持事务数据库系统必须支持如下4个特性:
- 原子性(atomicity)
- 一致性(consistency)
- 隔离性(isolation)
- 持久性(durability)
事务中的隔离性在数据库系统中一般采用锁来实现,针对不同的隔离级别有不同的隔离策略,要想在性能和隔离性中作出均衡,在数据库系统种是一个难点。
一、事务的特征
一个好的事务数据库,必须具备ACID特征:
- 原子性:
一个事务必须是不可分割的最小工作单元,整个事务中所有操作要么全部提交成功,或者全部失败回滚。 - 一致性:
数据库总是从一个一致性的状态转换到另一个一致性的状态,事务不会破坏数据库的完整性和业务上的一致性。 - 隔离性:
一个事务所做的修改在最终提交前,对其他事务是不可见的。在并发时,每个事务都拥有自己的工作和数据空间,不会相互干扰。 - 持久性:
一旦事务提交,所做的修改会永久保存到数据库系统中,及时系统崩溃,修改的数据也不会丢失。
数据库系统采用日志来保证事物的原子性,一致性和持久性。日志保存了用户对数据库所做的更改,如果事务在执行过程中发生错误,则数据库可以根据日志所记录的更改过程,回退到事务开始执行前的状态。
隔离性有多个级别(未提交读,提交读,可重复读,可串行化),一般数据库采用锁机制实现事务的隔离性,并达到某个级别,此时就可以保证事务的隔离性。当多个事务同时更新数据库中的相同数据时,只允许持有锁的事务才能更改数据,其他事务必须等待获得锁后才能更改数据。
二、隔离级别
SQL标准中定义了四种隔离级别,每种级别规定了一个事务中所做的修改,哪些时事务间可见,那些事事务内可见,哪些不可见,低级别的隔离往往具有更高的并发性能,开销也低。
- 未提交读:
事务中的修改,没有提交,其他事务也可以读取未提交的数据,也叫脏读。实际中一般很少用。 - 提交读:
大多数数据库系统的默认隔离级别是提交读,但MySQL不是。提交读满足隔离性的简单定义:一个事务开始时,只能看见已经提交的事务所做的修改。这个级别可能会在事务开启前后两次读到的数据不一致,又称为不可重复读。 - 可重复读:
可重复读解决了脏读和不可重复读的问题,保证在同一个事务中多次读取 同样的数据结果是一致的(即使有其他事务在此期间对该记录进行了修改)。仍存在幻读的问题:当某个事务在读取某范围 内的记录时,另一个事务在该范围内插入了新的记录,之前的食物重新读取该范围时,会产生新的记录(幻行)。
在MySQL中默认隔离级别为可重复读,并且InnoDB使用MVCC(多版本并发控制)解决了幻读的问题。 - 可串行化:
最高的隔离级别。强制事务串行化,避免了幻读的问题。会在读取的每一行数据上加锁,会导致锁争用问题,实际很少使用。
ANSI SQL隔离级别
隔离级别 | 脏读可能性 | 不可重复读可能性 | 幻读可能性 | 加锁读 |
---|---|---|---|---|
read uncommitted | Yes | Yes | Yes | No |
cead committed | No | Yes | Yes | No |
repedtabel read | NO | No | Yes | No |
serializable | No | No | No | Yes |
三、数据库中的锁
在数据库中多个SQL语句在同一时刻修改数据,会产生并发控制的问题,如果不加以控制,就会造成事务中的隔离性被破坏,引起不可预知的错误。
1.锁的类型
实现并发访问可以采用两种类型的锁,读锁/共享锁和写锁/排它锁:
- 读锁/共享锁:共享的锁,多个客户端可以同时读取一个资源,互补干扰。
- 写锁/排它锁:一个锁会阻塞其他的写锁和读锁,确保一个时刻只有一个客户端对通过一个数据进行修改写入。
在数据库系统中,锁对于用户时透明的,一般情况下,用户不用关心什么时候使用锁。
2.锁的粒度
锁定的数据量越少,系统的并发性能越好,因此数据库的锁只对需要修改的数据进行锁定。但加锁也需要消耗资源,锁的各种操作,包括获得,检查锁状态和释放锁都会增加系统开销。因此有必要在锁的开销和数据安全性之间平衡。一般情况下,数据库系统通常采用行级锁,即锁定修改的数据行。
在MySQL中提供了多种选择,每种引擎均会实现自己的锁策略和粒度。下面是两个最重要的锁策略。
- 表锁
是开销比较小的策略,会锁定整张表。用户对表进行写操作,需要先获得锁,并且会阻塞用户对该表的所有读操作。
数据库中对表进行修改,如alter table会使用到表锁,会锁定整张表,因此此类操作在数据库中应该谨慎使用。 - 行锁
行锁可以高效的支持并发,当然锁开销也是最大。MySQL的InnoDB引擎中实现了行锁,在用户写数据时,只锁定需要操作的数据行,相比于表锁并发度更好。