使用ibatis检索新插入的ID时的并发问题

我正在使用iBatis / Java和Postgres 8.3。 当我在ibatis中插入时,我需要返回id。
我使用下表来描述我的问题:
CREATE TABLE sometable ( id serial NOT NULL, somefield VARCHAR(10) );
序列sometable_id_seq通过运行create语句自动生成。

目前我使用以下sql map:

  INSERT INTO sometable ( somefield ) VALUES ( #value# );  SELECT last_value AS id FROM sometable_id_seq   

看来这是检索新插入的id的ibatis方式。 Ibatis首先运行INSERT语句,然后询问序列的最后一个id。
我怀疑这将适用于许多并发插入。

这会引起问题吗? 喜欢返回错误插入的id?

(另请参阅我的相关问题,了解如何让ibatis使用INSERT .. RETURING ..语句 )

这绝对是错误的。 使用:

 select currval('sometable_id_seq') 

或者更好的是:

 INSERT INTO sometable ( somefield ) VALUES ( #value# ) returning id 

这会返回你插入的id。

这是一个简单的例子:

  INSERT INTO objects(expression, meta, title, usersid) VALUES (#expression#, #meta#, #title#, #usersId#) RETURNING id  

在Java代码中:

 Integer id = (Integer) executor.queryForObject("addObject", object); object.setId(id); 

我有另一个想法。 ibatis调用insert方法委托Class: com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate,with the code如下:

  try { trans = autoStartTransaction(sessionScope, autoStart, trans); SelectKeyStatement selectKeyStatement = null; if (ms instanceof InsertStatement) { selectKeyStatement = ((InsertStatement) ms).getSelectKeyStatement(); } // Here we get the old value for the key property. We'll want it later if for some reason the // insert fails. Object oldKeyValue = null; String keyProperty = null; boolean resetKeyValueOnFailure = false; if (selectKeyStatement != null && !selectKeyStatement.isRunAfterSQL()) { keyProperty = selectKeyStatement.getKeyProperty(); oldKeyValue = PROBE.getObject(param, keyProperty); generatedKey = executeSelectKey(sessionScope, trans, ms, param); resetKeyValueOnFailure = true; } StatementScope statementScope = beginStatementScope(sessionScope, ms); try { ms.executeUpdate(statementScope, trans, param); }catch (SQLException e){ // uh-oh, the insert failed, so if we set the reset flag earlier, we'll put the old value // back... if(resetKeyValueOnFailure) PROBE.setObject(param, keyProperty, oldKeyValue); // ...and still throw the exception. throw e; } finally { endStatementScope(statementScope); } if (selectKeyStatement != null && selectKeyStatement.isRunAfterSQL()) { generatedKey = executeSelectKey(sessionScope, trans, ms, param); } autoCommitTransaction(sessionScope, autoStart); } finally { autoEndTransaction(sessionScope, autoStart); } 

您可以看到insert和select运算符位于Transaction中 。 所以我认为插入方法没有一致性问题。