1

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

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

4

5 回答 5

3

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

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

使用 Spring JDBC batchUpdate 时是否有获取生成的密钥?

于 2013-10-10T17:24:16.933 回答
2
query = "INSERT INTO ATableCache (AValue) select '" + avalue +
"' where not exists (select 1 from ATableCache where AValue = '"+avalue +"')";
于 2013-10-10T17:30:01.177 回答
1

没有那么多选择:

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

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

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

于 2013-10-10T17:20:43.127 回答
0

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

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

于 2013-10-10T17:27:36.753 回答
0

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

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

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

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

于 2013-10-10T18:07:30.307 回答