Java 如何在竞争条件下向表中插入主键值?

Java 如何在竞争条件下向表中插入主键值?,java,sql,multithreading,postgresql,Java,Sql,Multithreading,Postgresql,我们有一个代码,它将一个新值插入作为主键的表列中。 首先,我们进行选择,如果该值不存在,那么我们进行插入 query = "SELECT AValue from ATableCache WHERE AValue=" + avalue; ResultSet rs = stmt.executeQuery(query); if (!rs.next()) { query = "INSERT INTO ATableCache (AValue) VALUES ('" + avalue + "')"

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

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错误。其中一个选项是同步,但这会降低执行速度。请注意,插入很少发生。有更有效的算法吗?

没有那么多选项:

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

  • 让数据库处理生成密钥的操作

  • 捕获异常并处理它(不推荐)


  • 没有那么多选择:

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

  • 让数据库处理生成密钥的操作

  • 捕获异常并处理它(不推荐)


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

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


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

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


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


    我认为如果你尝试这种方法,这会有所帮助。

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

    query = "INSERT INTO ATableCache (AValue) select '" + avalue +
    "' where not exists (select 1 from ATableCache where AValue = '"+avalue +"')";
    

    我认为如果您尝试这种方法,这会有所帮助。

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

    query = "INSERT INTO ATableCache (AValue) select '" + avalue +
    "' where not exists (select 1 from ATableCache where AValue = '"+avalue +"')";
    
    对于序列,它很简单,下面是文档:。缺点是您需要在插入中使用nextval(),但您可以选择要缓存的值的数量

    您的另一个选项是将主键设置为一种串行类型。这些文件和一个很好的链接上的输入和输出序列


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

    Postgresql使用序列生成键,也可以使用Serial数据类型

    对于序列,它很简单,下面是文档:。缺点是您需要在插入中使用nextval(),但您可以选择要缓存的值的数量

    您的另一个选项是将主键设置为一种串行类型。这些文件和一个很好的链接上的输入和输出序列


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

    您的方法是同步的吗?如果插入很少发生,为什么您会担心同步会降低执行速度?那么为什么不尝试无条件地插入它呢?检查错误代码==密钥冲突,以确定其是否有效/失败。您的方法是否已同步?如果插入很少发生,为什么您担心同步会降低执行速度?那么为什么不尝试无条件地插入它呢?检查错误代码==密钥冲突是否有效/失败。为什么不建议使用选项3?@anarinsky这取决于您如何处理它,如果您尝试用另一个值重新插入,到那时,另一个线程可能也添加了该值。@anarinsky如果是那种竞争条件,则是,很好。为什么不推荐选项3?@anarinsky这取决于你如何处理它,如果你尝试用另一个值重新插入,到那时,另一个线程可能也添加了该值。@anarinsky如果是那种竞争条件,那么是,很好。@anarinsky只是一个虚拟的
    select
    for
    不存在
    check。我能看到实际的查询吗,例如avalue='RGG'?插入到ATableCache(avalue)选择不存在的'RGG'(从ATableCache中选择1,其中avalue='RGG')@anarinsky只是一个虚拟的
    select
    for
    不存在
    检查。我可以看到实际的查询吗,例如avalue='RGG'?插入到ATableCache(avalue)选择不存在的“RGG”(从ATableCache中选择1,其中avalue='RGG')