使用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中 。 所以我认为插入方法没有一致性问题。