避免数据库插入的密钥重复

时间:2016-03-01 06:53:15

标签: database concurrency insert key unique

我不确定标题是否描述了我的问题, 我有表A需要对每条记录使用唯一键,如下所示:

1.it从名为counter的表中获取密钥(假设其为500)。 2.it检查表A中是否真正使用了最后一个值(这是因为有人可能会预订该值然后没有完成使用它),(如果使用则增加值,否则接受它)

商业明智,该过程通过两个步骤完成: 1.客户点击书籍ID,以便他/她有钥匙。 2.client填充其余信息并保存,以便将新行插入表A。

多个客户端可能同时使用该系统,因此其中两个可能会预订相同的值

假设user1预订500,然后user2预订500(user1尚未使用它,所以user2将采用相同的密钥),然后user1将行插入表A,然后user2将行插入tableA

这种情况会导致严重问题,因为两者都使用了应该是唯一的相同密钥

请您为此建议解决方案

2 个答案:

答案 0 :(得分:1)

通常,最好的选择是在最终将项目插入数据库时​​分配密钥。

具体而言,数据库为此提供了良好可靠的机制 - 在大多数数据库中称为自动增量或串行。在插入中,您只需避免指定串行列的值,它将由数据库引擎生成。例如在mysql(full description)中:

CREATE TABLE Person (
     personId int NOT NULL AUTO_INCREMENT,
     name varchar(64) NOT NULL,
);

INSERT INTO Person (name) VALUES ('MyName');

SELECT last_insert_id(); -- outputs 1, 2, 3...

ORM框架也允许相同的内容。例如JPA:

@Id @GeneratedValue(strategy=GenerationType.SEQUENCE)
Long personId;

如果它不是表的id,你可以考虑使用一些虚拟表或序列来生成人工id,然后将其插入到你需要的表中。

答案 1 :(得分:0)

首先,我会重新考虑您的解决方案的架构,但由于答案太无聊,我也会尝试更具建设性。

您想要研究的是“交易”。事务锁定表以供其他人使用,然后启动事务。这在用于座位数量有限的预订系统以及系统可能缺货的在线商店等解决方案中被大量使用。

理论相当简单,但实施可能需要一些才能正确。您还应该意识到,您很可能会在您的ID系列中出现“漏洞”。意思是如果用户A预订了标识500而用户B预订了标识号501,然后用户A取消预订而不创建记录则不会标识为500。

我认为我对你的问题的解决方法是

1:用户在目标表中创建记录,并获得正常的主键增量ID。

2:创建记录并保存您的逻辑请求您描述的ID表中的“可视”ID。这是使用事务来确保可视ID是唯一的。

在实际创建记录之前,您没有真正有效的理由预订/创建ID。

根据您的环境,事务的实现方式不同。例如在MySQL中你会做这样的事情。

START TRANSACTION;
SELECT @A:=SUM(salary) FROM table1 WHERE type=1;
UPDATE table2 SET summary=@A WHERE type=1;
COMMIT;

但是如果您使用的是像Active Record这样的ORM,那么应该有一种方便的方法。

您也可以使用纯SQL脚本解决此问题。 I.E:创建一个存储过程,创建记录并为其获取新的可视ID。您仍然需要使用严格的交易。