【问题标题】:How to insert a primary key value into a table under race conditions?如何在竞争条件下将主键值插入表中?
【发布时间】:2013-10-18 14:10:29
【问题描述】:

我们有一个代码可以将一个新值插入到作为主键的表列中。 首先,我们进行选择,如果该值不存在,则进行插入。

query = "SELECT AValue from ATableCache WHERE AValue=" + avalue;
ResultSet rs = stmt.executeQuery(query);
if (!rs.next()) 
{
    query = "INSERT INTO ATableCache (AValue) VALUES ('" + avalue + "')";
    stmt.executeUpdate(query);
}

在竞争条件下,当插入一个刚刚被另一个线程插入的值时,此算法可能会导致 SQL 错误。选项之一是同步,但这会减慢执行速度。请注意,插入很少发生。有没有更高效的算法?

【问题讨论】:

  • 你的方法同步了吗?
  • 如果插入很少发生,为什么还要担心同步会减慢执行速度?
  • 那么为什么不尝试无条件地插入呢?检查错误代码是否 == 密钥违规以确定它是否有效/失败。

标签: java sql multithreading postgresql


【解决方案1】:

Postgresql 使用序列来生成密钥,或者您可以使用串行数据类型。

对于序列,它很简单,这里是文档:http://www.postgresql.org/docs/8.1/static/sql-createsequence.html。缺点是您需要在插入时使用 nextval(),但您可以获得诸如能够选择要缓存多少值的功能。

您的另一个选择是将主键设置为其中一种序列类型。文档和关于连续剧来龙去脉的良好链接。

Serial 将创建主键,您无需在插入中指定它。

【讨论】:

    【解决方案2】:

    我会让数据库生成密钥并确保事务是可序列化的。您需要正确设置数据库连接的隔离级别。

    也许可以使用 PostgreSQL,但是根据这个答案,保证适用于所有 JDBC 驱动程序的通用解决方案已经避开了 Spring:

    Is there anyway to get the generated keys when using Spring JDBC batchUpdate?

    【讨论】:

      【解决方案3】:
      query = "INSERT INTO ATableCache (AValue) select '" + avalue +
      "' where not exists (select 1 from ATableCache where AValue = '"+avalue +"')";
      

      【讨论】:

      • @anarinsky 只是 select 用于检查 not exists 的假人。
      • 我能看到实际的查询吗,例如avalue='RGG'?
      • INSERT INTO ATableCache (AValue) SELECT 'RGG' where not exists (select 1 from ATableCache where AValue = 'RGG' )
      【解决方案4】:

      我在您的帖子中看到了 postgresql 标签。在这种情况下,我建议您将主键设置为自动生成并注意将其放入您的插入语句中。

      如果您尝试这种方法,我认为post 可以提供帮助。

      【讨论】:

        【解决方案5】:

        没有那么多选择:

        1. 您的avalue 生成代码将需要以原子方式创建唯一键。这将需要同步,以便线程不会共享该值。

        2. 让数据库处理生成密钥。

        3. 捕获异常并处理它(不推荐)。

        【讨论】:

        • 为什么选择 NO。 3不推荐?
        • @anarinsky 这取决于你如何处理它,如果你尝试用另一个值重新插入,到那时,另一个线程可能也添加了那个值。
        • @anarinsky 如果是那种比赛条件,那么是的,你很高兴。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-03-30
        • 2022-01-23
        • 2021-12-21
        • 1970-01-01
        • 2017-02-10
        • 1970-01-01
        • 2012-12-09
        相关资源
        最近更新 更多