JYX*_*JYX 5 mysql sql triggers jmeter jenkins
我\xe2\x80\x99已经得到了一个带有开始和结束时间的预订表,并且两个预订不能重叠。
\n\n我需要检查新预订是否不会与任何现有预订重叠。然而,我们\xe2\x80\x99的负载非常高,因此存在\xe2\x80\x99的竞争条件:两个重叠的预订都可以成功插入,因为第一个预订是在第二个预订检查重叠之后插入的。
\n\nI\xe2\x80\x99m 尝试通过使用 BEFORE INSERT 数据库触发器锁定相关资源来解决此问题。
\n\nDELIMITER //\n\nCREATE TRIGGER booking_resource_double_booking_guard BEFORE INSERT ON booking_resource\nFOR EACH ROW BEGIN\n DECLARE overlapping_booking_resource_id INT DEFAULT NULL;\n DECLARE msg VARCHAR(255);\n\n -- Take an exclusive lock on the resource in question for the duration of the current\n -- transaction. This will prevent double bookings.\n DECLARE ignored INT DEFAULT NULL;\n SELECT resource_id INTO ignored\n FROM resource\n WHERE resource_id = NEW.resource_id\n FOR UPDATE;\n\n -- Now we have the lock, check for optimistic locking conflicts:\n SELECT booking_resource_id INTO overlapping_booking_resource_id\n FROM booking_resource other\n WHERE other.booking_from < NEW.booking_to\n AND other.booking_to > NEW.booking_from\n AND other.resource_id = NEW.resource_id\n LIMIT 1;\n\n IF overlapping_booking_resource_id IS NOT NULL THEN\n SET msg = CONCAT('The inserted times overlap with booking_resource_id: ', overlapping_booking_resource_id);\n SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = msg;\n END IF;\n END\n//\nRun Code Online (Sandbox Code Playgroud)\n\n如果我将此触发器放入数据库中并从命令行异步插入两个预订,则此触发器会成功阻止重叠预订。我\xe2\x80\x99已经尝试过在触发器中的最后一个IF语句之前放置SLEEP,以确保锁确实已被取出。
\n\n但是,我在 Jenkins 中有一个负载测试环境,它使用 jMeter 同时运行大量预订。当我将此触发器放在那里并运行负载测试时,不会捕获重叠的预订,即进行双重预订。
\n\n我完成了一些检查:
\n\n我\xe2\x80\x99m想知道锁是否只在触发器结束时才被取出,并且触发器结束和实际插入表之间仍然存在竞争条件。然而,这并不能解释为什么没有重叠的预订被捕获。
\n\n我\xe2\x80\x99m 现在真的卡住了。有人对我做错了什么有任何想法吗?
\n小智 0
一种不太优雅但更可靠的方法是使用用于锁定整个系统记录的表。
DELIMITER //
CREATE TRIGGER booking_resource_double_booking_guard BEFORE INSERT ON booking_resource
FOR EACH ROW BEGIN
DECLARE overlapping_booking_resource_id INT DEFAULT NULL;
DECLARE msg VARCHAR(255);
-- Take an exclusive lock on the resource in question for the duration of the current
-- transaction. This will prevent double bookings.
---CHANGED HERE
REPEAT
BEGIN
DECLARE CONTINUE HANDLER FOR SQLWARNING
BEGIN
SET locked = FALSE;
END;
locked=TRUE;
INSERT INTO lockresource values(NEW.resource_id);
END;
UNTIL LOCKED END REPEAT;
---TIL HERE
-- Now we have the lock, check for optimistic locking conflicts:
SELECT booking_resource_id INTO overlapping_booking_resource_id
FROM booking_resource other
WHERE other.booking_from < NEW.booking_to
AND other.booking_to > NEW.booking_from
AND other.resource_id = NEW.resource_id
LIMIT 1;
IF overlapping_booking_resource_id IS NOT NULL THEN
SET msg = CONCAT('The inserted times overlap with booking_resource_id: ', overlapping_booking_resource_id);
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = msg;
END IF;
END
//
---ADDED FROM HERE
DELIMITER //
CREATE TRIGGER booking_resource_double_booking_guard_after AFTER INSERT ON booking_resource
FOR EACH ROW BEGIN
DECLARE CONTINUE HANDLER FOR SQLWARNING BEGIN END;
delete from lockresource where lockid=NEW.resource_id;
END
//
Run Code Online (Sandbox Code Playgroud)
不管怎样,这就是想法,并且肯定会防止任何锁定丢失,直到完成验证。
| 归档时间: |
|
| 查看次数: |
1847 次 |
| 最近记录: |