间歇性地从 mysql innodb 查询中获取旧数据
Intermittently getting old data from mysql innodb queries
我们有各种 table 来表示各种类型的数据。每个 table 都有相应的修订 table 来跟踪此数据的历史记录。每个修订版(修订版 table 中的条目)都有一个唯一的编号。此数字存储在更改元数据 table 中。这些 table 中的每一个都引用了一个 parent_id。在我们对 table 进行任何更改之前,我们将父行锁定为 SELECT ... FOR UPDATE.
在进行 update/insert 之后,我们还会增加更改编号并将该编号写入更改元数据 table。为此,我们对更改元数据编号执行 SELECT MAX,然后递增。
我们看到的问题是,交易以某种方式从 select max 语句中获取旧的更改编号。举例说明:
交易 1:
开始交易
锁定更新
做事...
获取最新更改编号 (9)
插入编号为 10 的修订
提交
交易 2:
开始交易
锁定更新
做事...
获取最新更改编号 (7)
插入编号为 8 的修订本
提交
这会导致事务 2 的修订插入失败,因为更改编号是唯一键。我倾向于它是 repeatable 读取的问题,但我不确定旧数据如何以这种方式跨事务持续存在。对于每个事务都有一个 START TRANSACTION 语句,然后立即使用 FOR UPDATE 锁定父 ID。我们有一个具有多个并发事务的高流量站点。任何时候都可能有很多人在等待锁。我很乐意澄清任何一点,并感谢任何人提供的任何见解。
SELECT MAX on the change metadata number
那也需要 FOR UPDATE
。
另一种方法:
有一个"sequence number generator"table.
CREATE TABLE Sequence (
pk TINYINT NOT NULL,
seq INT UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY(pk), -- For ON DUPLICATE KEY UPDATE
INDEX(seq) -- Sufficient for AUTO_INCREMENT
);
唯一的动作(一旦初始化)应该是
INSERT INTO Sequence (pk, seq) VALUE (1, 0)
ON DUPLICATE KEY UPDATE seq := LAST_INSERT_ID(seq+1);
这将自动更新一行。然后(在同一连接中)执行此操作以获得新的 seq
:
SELECT LAST_INSERT_ID();
该声明与连接相关联,因此其他人不可能获得您的号码。
我们有各种 table 来表示各种类型的数据。每个 table 都有相应的修订 table 来跟踪此数据的历史记录。每个修订版(修订版 table 中的条目)都有一个唯一的编号。此数字存储在更改元数据 table 中。这些 table 中的每一个都引用了一个 parent_id。在我们对 table 进行任何更改之前,我们将父行锁定为 SELECT ... FOR UPDATE.
在进行 update/insert 之后,我们还会增加更改编号并将该编号写入更改元数据 table。为此,我们对更改元数据编号执行 SELECT MAX,然后递增。
我们看到的问题是,交易以某种方式从 select max 语句中获取旧的更改编号。举例说明:
交易 1:
开始交易
锁定更新
做事...
获取最新更改编号 (9)
插入编号为 10 的修订
提交
交易 2:
开始交易
锁定更新
做事...
获取最新更改编号 (7)
插入编号为 8 的修订本
提交
这会导致事务 2 的修订插入失败,因为更改编号是唯一键。我倾向于它是 repeatable 读取的问题,但我不确定旧数据如何以这种方式跨事务持续存在。对于每个事务都有一个 START TRANSACTION 语句,然后立即使用 FOR UPDATE 锁定父 ID。我们有一个具有多个并发事务的高流量站点。任何时候都可能有很多人在等待锁。我很乐意澄清任何一点,并感谢任何人提供的任何见解。
SELECT MAX on the change metadata number
那也需要 FOR UPDATE
。
另一种方法:
有一个"sequence number generator"table.
CREATE TABLE Sequence (
pk TINYINT NOT NULL,
seq INT UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY(pk), -- For ON DUPLICATE KEY UPDATE
INDEX(seq) -- Sufficient for AUTO_INCREMENT
);
唯一的动作(一旦初始化)应该是
INSERT INTO Sequence (pk, seq) VALUE (1, 0)
ON DUPLICATE KEY UPDATE seq := LAST_INSERT_ID(seq+1);
这将自动更新一行。然后(在同一连接中)执行此操作以获得新的 seq
:
SELECT LAST_INSERT_ID();
该声明与连接相关联,因此其他人不可能获得您的号码。