这是我当前数据库的摘录(更改了表名以便于理解):
Pet(ownerFK, id, name, age)
Owner(id, name)
Whereid
总是一个代理键,用auto_increment
.
我想让代理键Pet.id
被“限定”Pet.ownerFK
或换句话说,有一个复合键[ownerFk, id]
作为我的最小键。我希望表的行为如下:
INSERT Pet(1, ?, "Garfield", 8);
INSERT Pet(1, ?, "Pluto", 12);
INSERT Pet(2, ?, "Mortimer", 1);
SELECT * FROM Pet;
RESULT:
Pet(1, 1, "Garfield", 8)
Pet(1, 2, "Pluto", 12)
Pet(2, 1, "Mortimer", 1)
我目前正在使用MyISAM 的此功能,其中“您可以AUTO_INCREMENT
在多列索引中的辅助列上指定。在这种情况下,该AUTO_INCREMENT
列的生成值计算为MAX(auto_increment_column) + 1 WHERE prefix=given-prefix
。当您要将数据放入有序组时,这很有用。”
但是,由于各种(也许是显而易见的)原因,我想从 MyISAM 切换到 InnoDB,因为我需要在某些地方进行事务。
有什么方法可以用InnoDB达到这个效果吗?
我发现了一些关于这个问题的帖子,其中许多建议在插入之前对表进行写锁定。我对此不是很熟悉,但是对于这个来说,这不会是一个表写锁的大修吗?如果可能的话,我宁愿考虑使用写安全事务(我以前从未做过)——将 aOwner.current_pet_counter
作为辅助字段。
所以另一个可接受的解决方案是......
实际上,我不需要“作用域”ID 成为实际密钥的一部分。我实际的数据库设计使用了一个单独的“永久链接”表,它使用了这个“功能”。我目前使用它作为丢失交易的解决方法。我想到了以下替代方案:
Pet(id, ownerFK, scopedId, name, age), KEY(id), UNIQUE(ownerFK, scopedId)
Owner(id, name, current_pet_counter)
START TRANSACTION WITH CONSISTENT SNAPSHOT;
SELECT @new=current_pet_counter FROM Owner WHERE id = :owner_id;
INSERT Pet(?, :owner_id, @new, "Pluto", 21);
UPDATE Owners SET current_pet_counter = @new + 1 WHERE id = :owner_id;
COMMIT;
我还没有在 MySQL 中使用过 transactions/transactionvars,所以我不知道这个是否会有严重的问题。
注意:我不想重复使用id
曾经给宠物的 s。这就是为什么我不使用MAX()
. 这个解决方案有什么注意事项吗?