事物
事务是由一组SQL语句组成的逻辑处理单元,是满足 ACID 特性的一组操作,可以通过 Commit 提交一个事务,也可以使用 Rollback 进行回滚。事务具有以下4个属性,通常简称为事务的ACID属性:
原子性(Atomicity): 事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行。
一致性(Consistent): 在事务开始和完成时,数据都必须保持一致状态。
隔离性(Isolation): 并发访问数据库时,一个用户的事物不被其他事物所干扰,各并发事务之间数据库是独立的。
持久性(Durable): 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
并发一致性问题
脏读(Dirty read): 当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。
解决办法: 把数据库的事务隔离级别调整到READ_COMMITTED
更新丢失(Lost Update): 指在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。
不可重复读(Unrepeatableread): 指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。
一个事务范围内两个相同的查询却返回了不同数据。
解决办法: 把数据库的事务隔离级别调整到REPEATABLE_READ
幻读(Phantom read): 幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。
不可重复度和幻读区别:
不可重复读的重点是修改,幻读的重点在于新增或者删除。
事物的隔离级别
“脏读”、”不可重复读”和”幻读”,必须由事务隔离机制来解决。
SQL 标准定义了四个隔离级别:
读未提交(Read Uncommitted):
最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读读已提交(Read Committed):
允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
Oracle、SqlServer默认隔离级别都是READ-COMMITTED
可重复读(Repeatable Read):
对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生
MYSQL默认隔离级别是REPEATABLE-READ
串行化(Serializable):
最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读
总结
读未提交: 一个事务还没提交时,它做的变更就能被别的事务看到。
读已提交: 一个事务提交之后,它做的变更才会被其他事务看到。
可重复读 : 一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。
串行化: 顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。
四个级别逐渐增强,每个级别解决一个问题,事务级别越高,性能越差,大多数环境(Read committed
就可以了)
隔离级别 | 读数据一致性 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|---|
读未提交 | 最低级别 | Y | Y | Y |
读已提交 | 语句级 | N | Y | Y |
可重复读 | 事物级 | N | N | Y |
串行化 | 最高级别、事物级 | N | N | N |