1.事务的隔离级别
数据库事务的隔离级别有4种,由低到高分别为Read Uncommited、Read Commited、Repeatable Read、Serializable。并发数据访问时可能会出现以下问题,3类数据读取问题(脏读、不可重复读、幻读)和2类数据更新问题(第1类丢失更新和第2类丢失更新)。
- Read Uncommited,读未提交,即一个事务可以读取另一个未提交事务的数据;并发操作会导致脏读
- Read Commited,读操作,即一个事务要等到另一个事务提交后才能读取数据;解决脏读问题;并发操作会导致不可重复读
- Repeatable Read,重复读,即开始读取数据(事务开启)时,不再允许修改操作;解决不可重复读问题;并发操作会导致幻读(对应insert操作)
- Serializable,序列化,最高的事务隔离级别,该级别下,事务串行化顺序执行;避免脏读、不可重复读与幻读;但是该级别效率低下,比较消耗数据库性能,一般不用。
脏读 | 不可重复读 | 幻读 | 第1类丢失更新 | 第2类丢失更新 | 备注 | |
Read Uncommited | √ | √ | √ | × | √ | |
Read Commited | × | √ | √ | × | √ | 读取事务要等到这个更新操作事务提交后才能读取数据,可以解决脏读问题。 (大多数数据库默认的隔离级别,比如Oracle 、Sql Server) |
Repeatable Read | × | × | √ | × | × | 开始读取数据(事务开始)时,不允许修改操作(即update操作)。 MySQL的默认隔离级别 |
Serializable | × | × | × | × | × | 以上并发问题都不存在,但是效率低下,一般不用 |
对应的是Up date操作 | 对应insert操作 |
2.并发问题
数据库并发访问所产生的问题,在有些场景下可能是允许的,但是有些场景下可能是致命的,数据库通常会通过锁机制来解决数据并发访问问题,按锁对象不同分为表级锁和行级锁;按并发事务锁定关系分为共享锁和独占锁。直接使用锁非常麻烦,为此数据库为用户提供了自动锁机制,用户指定会话的事务隔离级别,数据库就会通过分析SQL语句然后为事务访问的资源加上合适的锁,此外,数据库还会维护这些锁通过各种手段提高系统的性能,这些对用户来讲都是透明的。
- 脏读:一个事务读取另一个未提交的数据。
- 不可重复读:一个事务范围内两个相同的查询却返回了不同数据。
- 幻读:一个事务范围内两个相同的查询却返回了不同数据。对应的是插入操作。
- 第1类丢失更新:两个事务均进行更新操作,相互影响,某一事务撤销影响最终结果的准确性。
- 第2类丢失更新:事务A覆盖事务B已经提交的数据,造成事务B所做的操作丢失。为了避免此问题,可以使用Repeatable Read隔离级别,或者查询和更新操作用where、set price=price+10等类型语句。