MySQL事务处理与并发控制( 二 )


MySQL事务处理与并发控制

文章插图
 
ACID意义上的隔离性意味着 , 同时执行的事务是相互隔离的:它们不能相互冒犯 。传统的数据库教科书将隔离性形式化为可串行化(Serializability) , 这意味着每个事务可以假装它是唯一在整个数据库上运行的事务 。数据库确保当事务已经提交时 , 结果与它们按顺序运行(一个接一个)是一样的 , 尽管实际上它们可能是并发运行的 。不过在实际生产环境中 , 很少使用可串行化 , 因为这会使得性能大幅降低 。
  • 4.持久性:数据库系统的目的是 , 提供一个安全的地方存储数据 , 而不用担心丢失 。持久性 是一个承诺 , 即一旦事务成功完成 , 即使发生硬件故障或数据库崩溃 , 写入的任何数据也不会丢失 。当然了 , 没有绝对的持久性 , 如果你的数据所在的磁盘损坏了呢?备份也损坏了呢?因此没有绝对的持久性安全性 , 增加副本只能增加安全性的几率 , 但是绝对达不到100% 。
以上介绍了数据库的四大特性 , 接下来看看为什么需要并发控制呢?
1.3 为什么需要并发控制我们已经知道 , 数据库会同时被多个用户(多个事务)访问 , 如果多个事务访问不同的数据 , 那么事务之间不会有任何干扰 , 如果多个事务操作相同的数据 , 那么各个事务之前就会互相干扰违背事务的隔离性 , 导致数据不一致 。因此 , 为了满足隔离性 , 使得各个并发的事务互不干扰 , 数据库系统必须对并发的事务进行控制 , 即:并发控制 。
那么不进行并发控制会有哪些问题呢?
事务之间的关系有如下三种:
  • 1、读--读:如果多个事务都是只读操作 , 那么这些事务可以并发 , 不会互相干扰(因为没有数据更新) 。
  • 2、读--写:如果读写都存在 , 则会存在脏读、不可重复度、幻读等问题 。
  • 3、写--写:如果多个事务并发的写同一数据 , 如果不加并发控制也会带来数据异常 。
接下来看看三种常见的读异常:
MySQL事务处理与并发控制

文章插图
读数据异常
如上图:
脏读:如果没有并发控制机制 , 事务T2在Time1处读到了无效的数据(因为事务T1在Time2时中止了)
不可重复读:事务T1在Time3处发生了不可重复读(同一个事务 , 在事务执行的过程中 , 同一行数据 , 读到了不同的值)
幻读:事务T1在Time3处发生了幻读 。
没有并发控制的情况下 , 读--写操作不仅会造成三种读异常 , 写写操作也会造成写异常 , 下边我们看看写-写操作导致的异常:
MySQL事务处理与并发控制

文章插图
写数据异常
如上图: 脏写:事务T1在time3时刻回滚掉了不是自己修改的数据 , 即事务T1在time3出发生了脏写 。
丢失更新:事务T1在time3处覆盖掉了不是自己修改的数据 , 即T1在time3出发生了丢失更新异常 , 如果是T2在time3时提交 , 道理也是一样的 , 只不过在T2上发生了丢失更新 。
除了以上读写异常 , 还存在一种**语义约束(事务的特性是要保证语义约束的)**引发的数据异常--写偏序:为了理解写偏序 , 我们先看一个例子(该例子来自《数据密集型应用系统设计》一书):
  • 你正在为医院写一个医生轮班管理程序 。医院通常会同时要求几位医生待命 , 但底线是至少有一位医生在待命 。医生可以放弃他们的班次(例如 , 如果他们自己生病了) , 只要至少有一个同事在这一班中继续工作 。现在想象一下 , Alice和Bob是两位值班医生 。两人都感到不适 , 所以他们都决定请假 。不幸的是 , 他们恰好在同一时间点击按钮下班 。下图说明了接下来的事情:

MySQL事务处理与并发控制

文章插图
写偏序
在两个事务中 , 应用首先检查是否有两个或以上的医生正在值班;如果是的话 , 它就假定一名医生可以安全地休班 。由于两次检查都返回 2  , 所以两个事务都进入下一个阶段 。Alice更新自己的记录休班了 , 而Bob也做了一样的事情 。两个事务都成功提交了 , 现在没有医生值班了 。违反了**至少有一名医生在值班(数据库的一致性)**的要求 。


推荐阅读