数据库事务
什么是事务,事务的作用,事务带来的问题,事务的隔离级别
什么是事务
事务是访问数据库的一个操作序列,数据库应用系统通过事务集来完成对数据库的存取。事务的正确执行使得数据库从一种状态转换为另一种状态。事务必须服从的ACID原则,即:
1 原子性(Atomicity)
即不可分割,事务要么全部被执行,要么全部不执行。如果事务的所有子事务全部提交成功,则所有的数据库操作被提交,数据库状态发生变化;
如果有子事务失败,则其他子事务的数据库操作被回滚,即数据库回到事务执行前的状态,不会发生状态转换。
2 一致性(Consistency)
事务的执行使得数据库从一种正确状态转换成另外一种正确状态。
3 隔离性(Isolation)
在事务正确提交之前,不允许把事务对该数据的改变提供给任何其他事务,即在事务正确提交之前,它可能的结果不应该显示给其他事务。
4 持久性(Durability)
事务正确提交之后,其结果将永远保存在数据库之中,即使在事务提交之后有了其他故障,事务的处理结果也会得到保存。
备注
根据凤凰架构的说法:C是目的,AID是手段。
事务的作用
事务管理保证了用户的每一次操作都是可靠的,即便出现了异常的访问情况,也不至于破坏后台数据的完整性。
并发事务处理会带来的问题
1 更新丢失(Lost Update)
当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题——最后的更新覆盖了由其他事务所作的更新。
一句话:事务A、B操作同一条数据,事务B提交覆盖了事务A
2 脏读(Dirty Reads)
一个事务正在对一条记录做修改,在这个事务完成并提交前,这条记录的数据就处于不一致状态;这时,另一个事务也就读取同一条记录,如果不加控制,第二个事务读取了这些”脏“数据,并据此做进一步的处理,就会产生未提交的数据依赖关系。这种现象被形象地叫做”脏读“
一句话:事务A提交了,事务B读到了提交前的数据
3 不可重复读(Non-Repeatable Reads)
一个事务在读取某些数据后的某个时间,再次读取以前读过的数据,却发现其读出的数据已经发生了改变、或某些记录已经被删除了,这种现象就叫做”不可重复读”。
一句话:在一个事务里面读取了两次某个数据,读出来的数据不一致(被其他事务更新/删除)
4 幻读(Phantom Reads)
一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象被称为”幻读”。
一句话:在一个事务里面读取了两次某批数据,读出来的数据不一致(被其他事务插入)
事务隔离级别
为了解决 丢失更新、脏读、不可重复读、幻读 问题,诞生了事务隔离。为什么要有事务隔离级别,事务隔离级别越高,在并发下会产生的问题就越少,但同时付出的性能消耗也将越大,因此很多时候必须在并发性和性能之间做一个权衡。
事务隔离级别有4种:
READ_UNCOMMITTED
读未提交,即能够读取到没有被提交的数据,所以很明显这个级别的隔离机制无法解决脏读、不可重复读、幻读中的任何一种,因此很少使用。
READ_COMMITED
(Oracle默认级别)
读已提交,即能够读到那些已经提交的数据,自然能够防止脏读,但是无法限制不可重复读和幻读。
REPEATABLE_READ
(MySQL默认级别)
重复读取,即在数据读出来之后加锁,类似"select * from XXX for update",明确数据读取出来就是为了更新用的,所以要加一把锁,防止别人修改它。REPEATABLE_READ的意思也类似,读取了一条数据,这个事务不结束,别的事务就不可以改这条记录,这样就解决了脏读、不可重复读的问题,但是幻读的问题还是无法解决。
SERLALIZABLE
串行化,最高的事务隔离级别,不管多少事务,挨个运行完一个事务的所有子事务之后才可以执行另外一个事务里面的所有子事务,这样就解决了脏读、不可重复读和幻读的问题了。但效率降低。
事务隔离级别解决问题图解
隔离级别 | 脏读可能性 | 不可重复读可能性 | 幻读可能性 | 加锁读 |
---|---|---|---|---|
READ_UNCOMMITTED | 是 | 是 | 是 | 否 |
RED_COMMITTED | 否 | 是 | 是 | 否 |
REPEATABLE_READ | 否 | 否 | 是 | 否 |
SERIALZABLE | 否 | 否 | 否 | 是 |