本文整理自:《精通Spring4.X 企业应用开发实战》
什么是事务:
事务是一组原子性的SQL查询,是一个独立的工作单元。要么所有全部执行成功,要么全部执行失败。这种思想反映到数据库上,就是多条SQL语句,要么所有执行成功,要么所有执行失败。
事务的四个特性:
- 原子性(Atomicity):
表示组成一个事务的多个数据库操作是一个不可分割的原子单元(可以理解为一个整体),只有所有的操作执行成果,整个事务才会提交。事务中的任何一个数据库操作失败,已经执行的任何操作都必须撤销,让数据库回滚到初始状态。也就是说不可能执行其中的一部分操作。 - 一致性(consistency):
事务操作成功后,数据库所处的状态和它的业务规则是一致的,即数据不会被破坏。如从A账户转账100元到B账户,不管操作成功与否,A账户和B账户的存款总额是不变的。 - 隔离性(isolation):
在并发数据库操作时,不同的事务拥有各自的数据空间,它们的操作不会对对方产生干扰。准确地说,并非要求做操完全无干扰。数据库规定了多种事务隔离级别,不同的隔离级别对应不同的干扰程度,隔离级别越高,数据一致性越好,但并发越弱。 - 持久性(durability):
一旦事务提交成功后,事务中所有数据操作都必须被持久化到数据库中。即使在提交事务后,数据库马上崩溃,在数据库重启时,也必须保证能够通过某种机制恢复数据。
在以上事务特性中,数据“一致性”是最终目标,其他特性都是为了达到这个目标而采取的措施、要求或手段。
脏读、不可重复读、幻读、丢失更新
在说隔离级别之前,先说一下由数据库并发导致的脏读,幻读,不可重复读。以及第一类丢失更新、第二类丢失更新
脏读
A事务读取B事务上位提交的更改操作,并在这个数据的基础上进行操作。如果恰巧B事务回滚,那么A事务读到的数据根本是不被承认的。
幻读
A事务读取B事务提交的新增数据,这是A事务将出现幻象读的问题。
不可重复读
不可重复读是指A事务读取了B事务已经提交的更改数据。
第一类丢失更新
A事务撤销时,把已经提交的B事务的更新数据覆盖了
第二类丢失更新
A事务覆盖B事务已经提交的数据,造成B事务所做操作丢失。
数据库锁机制
对于上述并发引发的问题,数据库通过锁机制是可以解决的。
按照锁定的对象不同
- 表锁
- 行锁。
从并发事务锁定的关系
- 共享锁定
- 独占锁定。
共享锁定会防止独占锁定,但允许其他的共享锁定。而独占锁定既防止其他的独占锁定,也防止和其他的共享锁定。
为了更改数据,数据库必须在进行更改的行上市价行独占锁定,INSERT,UPDATE,DELETE 和 SLEECT FOR UPDATE语句都会隐式采用必要的行锁定。
事务隔离级别
READ UNCOMMITTED (未提交读)
在READ UNCOMMITTED 级别,事务中的修改,即使没有提交,对其它事务也都是可见的。事务可以读取未提交的数据,这也就是脏读。在实际一般很少使用。
READ COMMITTED (读提交)
READ COMMITTED 一个事务从开始知道提交之前,所做的任何修改对其他事物都是不可见的。
REPEATABLE READ (可重复度)
REPEATABLE READ 解决了脏读的问题。改几倍保证了在同一个事务中多次读取同样记录的结果是一直的。但是理论上,可重复读隔离级别还是无法解决另一个幻读的问题。
该级别是 Mysql 默认的事务隔离级别。
SERIALIZABLE (序列化 、可串行化)
SERIALIZABLE 是最高的格列界别。它通过强制事务串行执行,避免了前面说的幻读的问题。简单来说,SERIALIZABLE 会再读取的每一行数据上都加锁,所以可能导致大量的超时 和锁征用的问题。实际应用中也很少使用到这个隔离级别。
事务隔离级别整理
隔离界别 | 脏读 | 不可重复读 | 幻读 | 第一类丢失更新 | 第二类更新丢失 |
---|---|---|---|---|---|
READ UNCOMMITTED | 允许 | 允许 | 允许 | 不允许 | 不允许 |
READ COMMITTED | 不允许 | 允许 | 允许 | 不允许 | 允许 |
REPEATABLE READ | 不允许 | 不允许 | 允许 | 不允许 | 不允许 |
SERIALIZABLE | 不允许 | 不允许 | 不允许 | 不允许 | 不允许 |