【问题标题】:avoid key duplication for database insertion避免数据库插入的密钥重复
【发布时间】:2016-03-01 06:53:15
【问题描述】:

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

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

在业务方面,该过程通过 2 个步骤完成: 1.client点击book id,这样他/她就有了钥匙。 2.client填写其余信息并保存,这样就在A表中插入了一个新行。

可能有多个客户同时使用系统,所以他们中的两个可能会预订相同的价值

假设 user1 book 500,然后 user2 book 500(user1 还没有使用它,所以 user2 将使用相同的 key),然后 user1 在 table A 中插入行,然后 user2 在 tableA 中插入行

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

你能建议一个解决方案吗

【问题讨论】:

    标签: database concurrency insert key unique


    【解决方案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,然后将其插入到您需要的表中。

    【讨论】:

    • 好吧,我说的唯一键不是主键,表 A 已经有 Id 主键列。清楚一点,A 是某种业务流程的表,它需要一个唯一的合同编号
    • @Heba :那么最好创建一些虚拟表,该表仅用于生成人造密钥,然后将其插入表中。或者在支持它的数据库中 - 你可以只使用序列生成器。规则始终相同 - 将其留给数据库,一般而言,在集群方面不可能在客户端可靠地执行此操作。
    • 感谢您的建议,这将是一个不错的解决方案,但在我的情况下,它不适用于某些业务流程的复杂性
    【解决方案2】:

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

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

    理论相当简单,但实现起来可能需要一些时间。您还应该知道,您很可能会在您的一系列 ID 中出现“漏洞”。这意味着如果用户 A 预订 id 500 和用户 B 预订 ID 501,然后用户 A 在没有创建记录的情况下取消预订,则不会有 id 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 脚本来解决这个问题。 IE:创建一个存储过程来创建记录并为其获取新的视觉 ID。您仍然需要使用严格的事务。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-02-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多