【问题标题】:SELECT, check and INSERT if condition is met如果满足条件,则选择、检查和插入
【发布时间】:2017-03-09 05:37:53
【问题描述】:

我有以下表格:Tour、Customer、TourCustomerXRef。假设每个巡回赛都有容量上限。现在一个预订请求到达后端。

我需要做的是:

  1. SELECT 和 count() TourCustomerXRef 中 tourid=123 的所有条目
  2. 在程序代码(或查询?)中:如果 count()
  3. 正确:插入到 TourCustomerXRef,返回成功
  4. False:返回错误

但是,后端 api 可能会同时被调用。这可能导致 SELECT 语句返回一个低于最大值的数字。两次容量,导致 INSERT 被执行多次(即使只剩下一个位置)。

对于上述情况,最好的预防措施是什么?设置事务隔离级别可序列化?还是可重复读取?

我担心应用程序逻辑(即使它只是一个简单的 if)会损害性能,因为读写锁不允许 api 执行只想选择数据而不插入任何内容的查询,对吧?

(使用 mariaDB)

【问题讨论】:

  • 听起来你想要一个触发器。这种检查不应该在应用程序级别进行。
  • @GordonLinoff 在我的情况下触发器会做什么?遗憾的是,我想不出在插入之前不需要选择检查的东西

标签: sql database mariadb


【解决方案1】:

您可以尝试在 SELECT(mysql 示例)中使用锁定提示“FOR UPDATE”:

BEGIN TRANSACTION;
SELECT * FROM TourCustomerXRef FOR UPDATE WHERE ...;
INSERT ...;
COMMIT;

【讨论】:

  • 快速提问,当 tourcustomerxref 中没有条目时,例如tourid=1,我使用 SELECT FOR UPDATE for tourid=1 运行两个事务,两者都可以选择。但是在插入时,一个会阻塞,直到另一个提交。这导致一个事务(第一个)成功,另一个返回“错误 1213(40001):尝试获取锁时发现死锁;”这是不可避免的吧?
  • 一些死锁是不可避免的。 (关于这个的细节不够详细。)所以,计划在发生死锁时重新运行事务
猜你喜欢
  • 2019-03-01
  • 2017-01-13
  • 2023-04-05
  • 1970-01-01
  • 1970-01-01
  • 2011-10-16
  • 1970-01-01
  • 2011-03-19
  • 2014-09-21
相关资源
最近更新 更多