当前位置: 首页 > 面试题库 >

如何正确使用事务和锁来确保数据库完整性?

郎正平
2023-03-14
问题内容

我开发了一个在线预订系统。为了简化起见,假设用户可以预订多个项目,而每个项目只能预订一次。物品首先添加到购物车中。

应用使用MySql/ InnoDB数据库。根据MySql文档,默认隔离级别为Repeatable reads

这是到目前为止我提出的结帐程序

  1. 开始交易
  2. 在购物车中选择项目for update带锁)在此步骤中,
    从中获取记录cart-itemitems表格。
  3. 检查其他人是否还没有预定商品
    基本上检查是否quantity > 0。在实际的应用程序中它更加复杂,因此我将其作为单独的步骤放在这里。
  4. 更新项目 ,设置quantity = 0
    还执行其他必要的数据库操作。
  5. 进行付款 (通过外部API,例如PayPal或Stripe),
    无需用户交互,因为可以在结帐前收集付款详细信息。
  6. 如果一切顺利,则 提交事务或回滚, 否则
  7. 继续执行非必要逻辑
    ,如果成功,请发送电子邮件等,并为错误而重定向。

我不确定这是否足够。我担心是否:

  1. 试图同时预订同一项目的其他用户将得到正确处理。他的交易会T2等到T1完成吗?
  2. 使用PayPal或Stripe付款可能需要一些时间。就性能而言,这不会成为问题吗?
  3. 物品可用性将始终正确显示(物品应可用,直到结帐成功)。这些只读选择是否应该使用shared lock
  4. MySql本身是否可以回滚事务?通常,自动重试或显示错误消息并让用户重试通常更好吗?
  5. 我猜如果SELECT ... FOR UPDATEitems桌子上做就足够了。这样,双击引起的请求和其他用户都必须等到交易完成。他们将等待,因为他们也使用FOR UPDATE。同时,vanilla SELECT只会在事务之前看到db的快照,但是没有延迟,对吗?
  6. 如果使用JOINin SELECT ... FOR UPDATE,两个表中的记录都将被锁定吗?
  7. 我对Willem Renzema答案的 不存在行 部分 上的SELECT … FOR UPDATE 感到有些困惑。什么时候可能变得重要?你能提供任何例子吗?

这是我已阅读的一些资源:
如何处理数据库中的并发更新?,MySQL:事务与锁定表,数据库事务是否防止竞争情况?,
隔离(数据库系统),InnoDB锁定和事务模型,数据库锁定和丢失更新现象的初学者指南。

改写了我原来的问题,使其更笼统。
添加了后续问题。


问题答案:

1.试图同时预订同一项目的其他用户将得到正确处理。 他的交易会T2等到T1完成吗?

是。虽然活动事务保持FOR UPDATE在记录上的锁,在使用任何锁其他交易报表(SELECT ... FOR UPDATESELECT ... LOCK IN SHARE MODEUPDATEDELETE)将暂停,直到无论是主动事务提交或“锁定等待超时”超过。

2.使用PayPal或Stripe付款可能需要一些时间。 就性能而言,这不会成为问题吗?

这将不是问题,因为这正是必需的。结帐交易应按顺序执行,即 后一个结帐不应在前一个结帐之前开始。

3.项目可用性将始终正确显示(项目应该可用,直到结帐成功)。 这些只读选择是否应该使用shared lock

Repeatable reads隔离级别可确保在提交事务之前不可见事务所做的更改。因此,物品可用性将正确显示。在实际付款之前,不会显示不可用的任何内容。无需锁。

SELECT ... LOCK IN SHARE MODE会导致结帐交易等待完成。这可能会使结帐速度变慢而没有任何回报。

4. MySql本身是否可以回滚事务? 通常,自动重试或显示错误消息并让用户重试通常更好吗?

有可能的。当超过“锁定等待超时”或发生死锁时,事务可能会回滚。在这种情况下,最好自动重试。
默认情况下,挂起的语句在50秒后失败。

5.如果我SELECT ... FOR UPDATEitems桌子上做,我猜就足够了。这样,双击引起的请求和其他用户都必须等到交易完成。他们将等待,因为他们也使用FOR UPDATE。同时,vanilla SELECT只会在事务之前看到db的快照,但是没有延迟,对吗?

是的,SELECT ... FOR UPDATEitems桌子上就足够了。
是的,这些选择等待,因为FOR UPDATE是排他锁。
是的,简单的SELECT交易会像交易开始前那样获取价值,这将立即发生。

6.如果使用JOINin SELECT ... FOR UPDATE,两个表中的记录都将被锁定吗?

是的,SELECT ... FOR UPDATESELECT ... LOCK IN SHARE MODEUPDATEDELETE锁定所有读取记录,所以无论我们JOIN是包括在内。参见MySql
Docs。

有趣的是(至少对我而言),无论是否选择,在处理SQL语句时扫描的所有内容都会被锁定。例如,WHERE id < 10还会用id = 10!锁定记录!

If you have no indexes suitable for your statement and MySQL must scan the
entire table to process the statement, every row of the table becomes
locked, which in turn blocks all inserts by other users to the table. It is
important to create good indexes so that your queries do not unnecessarily
scan many rows.



 类似资料:
  • 问题内容: 我想将一些div转换为PDF,并且尝试了jsPDF库,但没有成功。看来我不明白我需要导入什么才能使库正常工作。我已经看过这些示例,但仍然无法弄清楚。我尝试了以下方法: 在jQuery之后: 用于测试目的,但我收到: 身体的第一个div 在哪里。 问题答案: 您可以按如下方式使用html中的pdf, 步骤1:将以下脚本添加到标题 步骤2:添加HTML脚本以执行jsPDF代码 对此进行自定

  • 我正在评估Apache Kafka Streams的事件源,看看它在复杂场景中的可行性。与关系数据库一样,我也遇到过一些情况,原子性/事务性至关重要: 具有两项服务的购物应用程序: OrderService:有一个带有订单的Kafka流商店(OrdersStore) ProductService:有一家Kafka流商店(ProductStockStore),里面有产品及其库存 流量: > Orde

  • 问题内容: 我刚刚开始学习数据库设计,并且我正在与Oracle 11G和SQL Developer一起工作。 我对数据库有以下3条业务规则: 每个官员必须注册一个并且只能注册一个保险公司。每个保险公司可以注册一名或多名官员 每个保险公司必须提供至少五种不同类型的保险类型。每种保险类型最多可以由4个保险公司提供,或者根本不提供 每个保险类型可以由一个或多个官员来订阅。每个官员最多可以订阅同一家公司提

  • 我正在使用Spring 4.0.0. RELEASE,Spring数据共享1.7.0. M1,Spring Hateoas 0.8.0. RELEASE 我的资源是一个简单的POJO: 我的资源汇编程序将User对象转换为UserResources对象: 在我的UserController我想检索

  • 问题内容: 尝试从我知道仅包含整数的数组中获取最高和最低值似乎比我想象的要难。 我希望这能显示出来。相反,它显示。因此,似乎排序是将值作为字符串处理。 有没有一种方法可以使sort函数对整数值进行实际排序? 问题答案: 默认情况下,sort方法按字母顺序对元素进行排序。要进行数字排序,只需添加一个处理数字排序的新方法(sortNumber,如下所示)- 在ES6中,可以使用箭头功能简化此操作: 说

  • 问题内容: 我有以下代码供用户单击按钮使用,当他们单击按钮时,正在查看的特定字符串将被收藏并存储在其他位置。 我有两个问题。 我现在所拥有的是什么问题?因为当您单击按钮时它会崩溃。 您将如何完成将要加载的字符串并将其保存到数组的load array方法,以便用户以后可以看到该数组? 谢谢你的时间!! 原木猫 问题答案: 函数返回。您可能想要像这样使用它: 该数组可以稍后在第二部分中使用。希望这可以