我正在开发一个Web应用程序,该Web应用程序与生产中的桌面应用程序共享数据库(也就是我无法修改数据库,只能尝试模仿行为)。我现在正在使用的模块将在notes
表中将注释存储到该数据库中。我能够使它正常工作,添加了便笺,便笺便出现在桌面应用程序中,然后一段时间后,我意识到便笺的实际便笺文本和说明已被覆盖。在查看数据库中的行时,我注意到已设置modified_by
用户,并告诉我插入时有重复的键,然后进行更新。该表的主键是自动递增,因此我很困惑。经过一些挖掘后,我发现了一个名为counters
的表,该表的一个名为notes
的列的计数与notes
表的当前索引相匹配。在每次对每个插入区的计数器简单地+1之前,我就将Wireshark下载到db服务器上并记录了db端口上的流量,发现了这一点:
(从桌面应用添加便笺的过程)
UPDATE counters SET in_use = 'Y';
SELECT notes FROM counters WHERE key_col = 1;
/* Desktop app uses current count for new index */
UPDATE counters SET notes = /* current count +1 */ WHERE key_col = 1;
UPDATE counters SET in_use = 'N';
/* ...Inserts new note here with explicit ID = current count ... */
现在我更加困惑了。为什么将表格设置为自动递增?其次,在选择计数并添加一个之前,从未对in_use
进行过任何检查...那么in_use
的意义是什么?如果两个用户同时插入,此代码是否会导致覆盖?这样做的正确方法不是为每个操作锁定counters
表吗?我可以尝试一下,但是我不确定桌面应用程序将如何处理遇到的锁定(基于经验-致命错误)。
除了精确地重复此过程并希望获得最佳结果外,我不确定从何而来。一种想法是:
<?php
const MAX_ATTEMPTS = 3;
$curKey;
for($i = 0; $i < MAX_ATTEMPTS; $i++){
/*
SELECT in_use, notes from counters where key_col = 1;
...
*/
if( 'N' === $result['in_use'] ){
$curKey = $result['notes'];
/* INSERT count here - $curKey++ */
break;
}
/* Sleep for .25 seconds to allow for current operation to finish */
usleep(250000);
}
if( null == $curKey ){
throw \Exception('Could not insert note because counter table locked after '. MAX_ATTEMPTS .' attempts');
}
/* INSET note code here... */
这似乎可以,但仍可能会覆盖,因为a)选择计数和插入新计数之间的时间b)桌面应用似乎没有进行任何检查。
有什么想法/建议吗?
编辑:进行存储过程以在选择和插入期间进行检查。
DELIMITER $$
CREATE DEFINER=`testUser`@`%` FUNCTION `getNextNoteIndex`(appKey INTEGER) RETURNS int(11)
BEGIN
SELECT IF(`in_use` = 'N', `notes`, NULL) INTO @curIndex FROM `counters` WHERE `app_key` = appKey;
IF @curIndex IS NOT NULL
THEN
SET @newIndex = @curIndex + 1;
UPDATE `counters` SET `notes` = @newIndex WHERE `app_key` = appKey AND `in_use` = 'N' AND `notes` = @curIndex;
IF ROW_COUNT() = 1
THEN
RETURN @newIndex;
END IF;
END IF;
RETURN NULL;
END
用法:
SELECT testDB.getNextNoteIndex(1) AS $index;
答案 0 :(得分:0)
我不知道他们需要创建一个可以自动递增的表格的目的,这听起来不像是一种标准的解决方案。
我对可以更改和不能更改的内容(数据库,后端代码等)感到困惑:
如果您在内部,您是否无法询问构建该中间增量表的开发人员的用途,并可能在那里弄清楚或完全绕开它。
如果您不在外面,向他们询问API并使用他们给您的端点是否有意义?然后,由覆盖引起的任何问题都将落到法院。