我们有一个代码,它将一个新值插入到表列中,该值是主键。首先,我们进行选择,如果此值不存在,则进行插入。
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 +"')";
没有那么多选择:
-
您的
avalue
生成代码需要以原子方式创建唯一密钥。这将需要同步,以便线程不会共享该值。 -
让数据库处理生成密钥。
-
捕获异常并处理它(不推荐(。
我在你的帖子中看到标签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/
串行将创建主键,而无需在插入中指定它。