事务是一个抽象层,允许应用程序假装某些并发问题和某些类型的硬件和软件故障不存在。各式各样的错误被简化为一种简单情况:事务中止(transaction abort),而应用需要的仅仅是重试。
如果没有事务处理,各种错误情况(进程崩溃,网络中断,停电,磁盘已满,意外并发等)意味着数据可能以各种方式变得不一致。例如,非规范化的数据可能很容易与源数据不同步。如果没有事务处理,就很难推断复杂的交互访问可能对数据库造成的影响。
本章深入讨论了并发控制的话题。我们讨论了几个广泛使用的隔离级别,特别是:
并通过研究竞争条件的各种例子,来描述这些隔离等级:
一个客户端读取到另一个客户端尚未提交的写入。读已提交或更强的隔离级别可以防止脏 读。
要求读锁的办法在实践中效果并不好。因为一个长时间运行的写入事务会迫使许多只读 事务等到这个慢写入事务完成。这会损失只读事务的响应时间,并且不利于可操作性.
大多数数据库使用如下方式防止脏读:对于写入的每个对象,数据库都 会记住旧的已提交值,和由当前持有写入锁的事务设置的新值。 当事务正在进行时,任何其 他读取对象的事务都会拿到旧值。 只有当新值提交后,事务才会切换到读取新值。
一个客户端覆盖写入了另一个客户端尚未提交的写入。几乎所有的事务实现都可以防止脏 写。
数据库通过使用行锁(row-level lock) 来防止脏写:当事务想要修改特定 对象(行或文档)时,它必须首先获得该对象的锁。然后必须持有该锁直到事务被提交或中 止。一次只有一个事务可持有任何给定对象的锁;如果另一个事务要写入同一个对象,则必 须等到第一个事务提交或中止后,才能获取该锁并继续。这种锁定是读已提交模式(或更强 的隔离级别)的数据库自动完成的。
在同一个事务中,客户端在不同的时间点会看见数据库的不同状态。快照隔离经常用于解决 这个问题,它允许事务从一个特定时间点的一致性快照中读取数据。快照隔离通常使用多版 本并发控制(MVCC) 来实现。
两个客户端同时执行读取-修改-写入序列。其中一个写操作,在没有合并另一个写入变更情 况下,直接覆盖了另一个写操作的结果。所以导致数据丢失。快照隔离的一些实现可以自动 防止这种异常,而另一些实现则需要手动锁定( SELECT FOR UPDATE )。
使用提供的原子操作或显示锁定
一个事务读取一些东西,根据它所看到的值作出决定,并将决定写入数据库。但是,写作的 时候,决定的前提不再是真实的。只有可序列化的隔离才能防止这种异常。
事务读取符合某些搜索条件的对象。另一个客户端进行写入,影响搜索结果。快照隔离可以 防止直接的幻像读取,但是写入歪斜环境中的幻影需要特殊处理,例如索引范围锁定。
弱隔离级别可以防止这些异常情况,但是让应用程序开发人员手动处理其他应用程序(例 如,使用显式锁定)。只有可序列化的隔离才能防范所有这些问题。
数十年来,两阶段锁定一直是实现可序列化的标准方式,但是许多应用出于性能问题的考虑避免使用它。
在2PL中,写入不仅会阻塞其他写入,也会阻塞读,反之亦然。快照隔离使得读不阻塞写,写 也不阻塞读(参阅“实现快照隔离”),这是2PL和快照隔离之间的关键区别。另一方面,因为 2PL提供了可序列化的性质,它可以防止早先讨论的所有竞争条件,包括丢失更新和写入偏 差。
读与写的阻塞是通过为数据库中每个对象添加锁来实现的。锁可以处于共享模式(shared mode)或独占模式(exclusive mode)。
事务 B 的 update 语句会被阻塞,直到事务 A 执行 commit 之后,事务 B 才能继续执行。
也就是说,在 InnoDB 事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有