事务的安全保障
ACID
原子性(atomicity)、持久性(consistency)、隔离性(isolation)、一致性(durability)。
原子性
当一个事务在执行途中发生错误,我们很难知道哪些更改已经生效,哪些更改没有生效,而如果重试可能会导致数据重复或者数据错误。为了简化这个问题,数据库丢弃或者撤销该事务中迄今为止任何写入,这样做就可以保证没有任何东西在这个过程中被改变,所以可以安全的重试。
中止出错的事务,并撤销该事务进行的所有变更。
一致性
一致性是应用程序的属性,应用程序可以用原子性和隔离性来实现一致性。
如果一个财务系统,账户A转钱到账户B,那么账户A中减少的钱与账户B中增加的钱必须相等。这并不是数据库可以保证的事情,而是应用程序来保证的。
隔离性
同时执行的事务不能互相冒犯。这意味着,每个事务都可以认为它是唯一在整个数据库还是那个运行的事务。数据库确保多个事务提交后,结果与他们按顺序一个接着一个的运行是一样的,尽管实际上他们可能是并发的。
假设两个客户端同时增长一个计数器(当前值为10),每个客户端需要读取计数器的当前值,加1后在写新值。因为发生了两次增长,计数器应该从10增长到12。但是由于两个客户端同时读取,拿到的原值都是10,执行加1操作后都写回了11,出现了数据错误。
持久性
安全的存储数据,而不用担心丢失。
数据库的预写日志或分布式系统的复制可以为持久性做出承诺。
脏读/不可重复读/幻读
事务的隔离,以是否脏读/重复读/幻读为分界线。这里先简要说明一下什么是脏读/重复读/幻读。
脏读
在事务A执行过程中,事务A对数据进行修改,事务B读取了事务A修改后的数据。由于某些原因,事务A并没有完全提交,发生了回滚(rollback)操作,则事务B读取的就是脏数据。
这种读取另一个事务未提交的数据的现象就是脏读。
不可重复读
事务B读取两次数据,在事务B读取数据的过程中事务A修改了数据,导致事务B在两次读取的数据不一致。
这种同一事务中,前后两次读取数据不一致的现象就是不可重复读。
幻读
事务B先后两次读取同一个范围的数据,在事务B两次读取的过程中事务A新增了数据,导致事务B后一次和前一次查到的行不一致。
幻读和不可重复读类似,但是幻读强调的是集合的增减,而不是单条数据的更新。
第一类更新丢失
事务A和事务B对同一个数据进行更新,但是事务A由于某种原因事务回滚了,把已经提交的事务B的数据给覆盖了。这种现象叫第一类更新丢失。
第二类更新丢失
第二类更新丢失和第一类更新丢失有点类似,两个事务对数据进行更新,事务A把事务B的更新覆盖了。这种现象就是第二类更新丢失。
事务隔离级别
读未提交
读已提交
可重复读
串行化
读未提交
Read Uncommitted,是最低的隔离级别,所有的事务都可以看到其他未提交事务的执行结果。只能防止第一类更新丢失,不能解决脏读、可重复读、幻读,很少应用于实际项目。
读已提交
Read Committed,在该隔离级别下,一个事务的更新操作结果只有在该事务提交之后,另一个事务才可能读取到同一笔数据更新后的结果。可以防止脏读和第一类更新丢失,但是不能解决可重复读和幻读。
可重复读
Repeatable read,mysql默认的隔离级别。在该隔离级别下,一个事务多次读同一个数据,在这个事务还没结束时,其他事务不能访问该数据(包括读写),这样就可以在同一个事务内两次读到的数据是一样的。可以防止脏读、不可重复读、第一类更新丢失、第二类更新丢失的问题。不能防止幻读。
串行化
serializable,最高的隔离级别。他要求事务序列化执行,事务只能一个接着一个执行,不能并发执行。在这个级别,可以解决上面提到的所有并发问题,但是可能导致大量的超时现象和锁竞争,通常不会用这个隔离级别。
其他解决幻读的方法
物化冲突
如果幻读的问题是没有对象可以加锁,也许可以人为的在数据库中引入一个锁对象。
串行化实现
两阶段锁定、共享锁、互斥锁
两阶段锁定实现了最强的隔离级别,即串行化----无论怎么并发写,最终与一个一个顺序发生的结果都是一样的。
两阶段锁定要求:只要没有写入,就允许多个事务同时读同一行。但只要有写入(修改或删除),就独占访问权限。换句话说,写入不仅会阻塞其他写入,也会阻塞读。
两阶段锁含义:
第一阶段(只加锁):事务开始前,进程尝试对所有此事务需要的行进行加锁,按顺序一次锁一行,查询就加共享锁,修改就加互斥锁。若第一阶段全部加锁成功,就开始第二阶段(只解锁):执行更新然后释放所有锁。若在第一阶段某个进程加锁时发生冲突,则该进程释放它所有加锁的行,然后重试第一阶段。
两阶段提交用到了两种锁,共享锁(也称为读锁,允许多个事务同时读取同一行)或互斥锁(也称为写锁,只要有写入就独占访问权限)。
两阶段锁定真正实现了串行化性质,它可以防止之前讨论的所有并发问题,也是性能损耗最大的选择,尤其是它可能会更频繁的导致死锁出现。事务由于死锁而被中止后只能重试,这意味着巨大的开销。
总结
事务隔离界别和并发问题解决情况总结
参考
https://www.zhihu.com/question/458275373/answer/1873975439
https://zhuanlan.zhihu.com/p/69380112