我有一个表,其中插入的有效性是表中所有其他行的函数。该表管理资源的日期期间,并且仅当没有其他行与同一资源重叠时,新行才有效。
所以表是
resource_id INT
start_date DATE
end_date DATE
从概念上讲,如果以下查询的结果为 0,则可以插入一行(其中 newResourceId、newStartDate、newEndDate 是要插入的元组)
select count(entity_id) from mytable where resource_id = newResourceId and start_date < newEndDate and end_date > newStartDate;
问题是如何确保正确处理并发插入?我需要一些方法来确保在执行上述选择和随后的插入之间没有插入任何行。所以并发操作应该阻塞上面的选择,直到第一个操作提交。为此,我使用以下存储过程:
DELIMITER //
drop procedure if exists rp_insert //
create procedure rp_insert
(
IN p_resource_id INT(10),
IN p_start_date DATE,
IN p_end_date DATE,
OUT result INT
)
BEGIN
DECLARE num_conflicts INT;
DECLARE conflicts CURSOR FOR SELECT entity_id from mytable WHERE start_date < p_end_date and end_date > p_start_date and resource_id = p_resource_id FOR UPDATE;
START TRANSACTION;
OPEN conflicts;
SELECT FOUND_ROWS() into num_conflicts;
if num_conflicts = 0 then
insert ignore into mytable (resource_id, start_date, end_date) values (p_resource_id, p_start_date, p_end_date);
set result = LAST_INSERT_ID();
COMMIT;
else
set result = -2;
ROLLBACK;
end if;
END //
DELIMITER ;
因此,如果有人能告诉我这是否是处理并发的正确方法,我将不胜感激,特别是:
选择游标上的“更新”是否意味着具有重叠 where 条件的并发操作将在选择上阻塞,直到第一个事务提交/回滚?
在相同的并发场景中,第二个操作 SELECT 是否会看到第一个操作插入的行(假设插入将在第二个事务开始后提交,但在第二个 select 执行之前)?
智能数据库引擎是否会意识到我永远不会更新选择返回的任何行并决定不强制选择更新(例如,很容易看到事务中没有更新语句)
关于性能的任何其他评论,是否有更好的方法等?
有关信息,我决定反对:
将表锁定为矫枉过正(例如,如果选择结果中有重叠,则第二个操作只需要阻塞)。在 mysql 存储过程中似乎也不允许使用锁
用 PHP 编码而不是存储过程(没有理由进行 db 往返,因为我不需要知道冲突是什么,只需知道插入是否成功)。