当前位置: 首页 > 科技观察

解决MySQL幻读终极指南

时间:2023-03-20 21:14:11 科技观察

译者|布加迪评论家|孙淑娟提到关系型数据库,人们通常首先想到的是MySQL。MySQL使用InnoDB作为其存储引擎,并且RepeatableRead隔离级别(在事务开始之前查看数据)是最常见的。但是,与PostgreSQL不同的是,InnoDB中的可重复读隔离级别无法处理丢失更新和幻读(phantomread)等问题,您不需要额外的技巧来解决PostgreSQL中丢失更新的问题。您可以使用多种技术来执行幻读,例如范围类型和其他机制。MySQL开发人员应该意识到可能存在的陷阱,并能够采取适当的步骤来避免更新丢失和幻读等问题。本文介绍了MySQL开发人员如何解决可能由幻读引起的“写入偏差”。导致幻读的场景不同的场景都可能导致幻读。通常,这些场景遵循类似的模式。最初在MySQL数据库中搜索一个特定的范围,然后根据搜索到的范围的结果进行CREATE(创建)、UPDATE(更新)或DELETE(删除)等操作。之后,执行的操作直接影响从搜索范围获得的结果。例如,假设搜索特定范围后要执行的操作是UPDATE或DELETE。在这种情况下,MySQL开发人员可以使用独占锁来避免“写偏差”。然后,开发人员可以在“SELECT”操作开始时使用FORUPDATE,之后他们可以强制两个同时发生的事务按顺序完成。因此,这两个同时进行的事务避免了竞争条件下的“写入偏差”。但是,如果我们假设基于特定范围的搜索结果所采取的操作是CREATE,则上述解决方案是不完整的:没有相应的行可供开发人员使用SELECT锁定,这意味着稍后形成一行。如何解决使用CREATE时出现幻读我们将介绍一个实际场景来更好地理解使用CREATE时出现幻读的问题。想象一个人们可以预订会议室的系统;有人使用系统预订房间后,新数据将添加到表中。该系统允许用户根据他们想要预订的时间段检查房间是否可用。一旦有人创建了新的预订条目,所有其他用户都可以避免时段冲突。但是,当两个人同时预订同一个房间时,就会出现问题。两个用户都能够通过初始SELECT身份验证,这意味着他们理论上可以同时预订同一时间段的房间,从而导致时间段冲突。例如,如果有多个用户需要使用预订系统通过VPN连接到远程SQL服务器,则问题可能会更加复杂。即使MySQL开发人员添加了独占锁,这个问题也无法避免,因为他们无法在初始SELECT验证期间锁定该行。使用唯一约束索引解决MySQL开发者无法通过排它锁将并发操作转换为顺序操作的问题。因此,他们需要通过向表添加唯一约束来使操作失败。开发人员可以使用唯一约束索引来定位房间预订表中房间号和会议开始时间对应的列。该解决方案可以防止某人预订其他人已经预订的时间段,并且开发人员可以做到这一点,以便任何人都不能预订超过一个小时的房间。但是,如果两个用户的会议时间重叠,此解决方案也会阻止唯一约束起作用。为了妥善解决这个问题,开发人员必须改用物化冲突。我们所说的解决幻读的正确方法是通过物化冲突来发现表隐藏的冲突。开发人员可以使用协调并发操作的数据集预先填充一个全新的表。如果我们以会议室系统为例,想象创建一个新的表来指定时间段,并提前显示所有可用的时间段。使用这个新表,开发人员现在将在指定可用时间段的列上执行SELECT,并添加FORUPDATE,因为数据已经存在。开发人员需要在初始SELECT之前运行此SELECTFORUPDATE。通过具体化上述示例中的冲突,开发人员可以使用排他锁来防止任何两个预定时间段相互重叠,从而强制将一个时间段添加到另一个时间段之前或之后。由于第一个时间段已经完成,后续时间段将立即到期。结论虽然物化冲突是一个困难且不直观的解决方案,但在使用MySQL数据库时有必要避免显着的性能下降。不幸的是,MySQL的InnoDB隔离级别不是可序列化的,因此开发人员需要牺牲一定程度的复杂性以获得可接受的性能级别。任何使用数据库的人都必须了解相应数据库的功能和解决方案。否则,将无法预测数据库的哪些行为可能危及数据库设计和开发工作。此外,了解如何妥善处理潜在风险也同样重要。虽然我们在本文中描述的时间预订系统用例与其他用例不同,但出现的模式非常相似,因此了解如何解决它们将使将来处理其他场景变得更容易。原标题:解决MySQL幻读权威指南,作者:NahlaDavies