如何在争用条件下将主键值插入表中



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

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

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

使用PostgreSQL可能是可能的,但是根据以下答案,Spring无法保证适用于所有JDBC驱动程序的通用解决方案:

在使用Spring JDBC batchUpdate时,是否有任何方法可以获取生成的密钥?

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

没有那么多选择:

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

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

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

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

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

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

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

另一个选项是将主键设置为串行类型之一。文档和关于串行来龙去脉的良好链接。

  • http://www.postgresql.org/docs/8.1/static/datatype.html#DATATYPE-SERIAL
  • http://www.neilconway.org/docs/sequences/

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

最新更新