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

时间:2009-11-20 10:27:36

标签: java postgresql ibatis

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

目前我使用以下sql map:

<insert id="insertValue" parameterClass="string" >
 INSERT INTO sometable ( somefield ) VALUES ( #value# );
 <selectKey keyProperty="id" resultClass="int">
  SELECT last_value AS id FROM sometable_id_seq
 </selectKey>
</insert>

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

这会引起问题吗?就像返回错误插入的id一样?

(另请参阅我关于how to get ibatis to use the INSERT .. RETURING .. statements的相关问题)

3 个答案:

答案 0 :(得分:2)

这绝对是错误的。使用:

select currval('sometable_id_seq')

或更好:

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

将返回您插入的ID。

答案 1 :(得分:0)

我有另一个想法。 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);
    }

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

答案 2 :(得分:0)

这是一个简单的例子:

<statement id="addObject"
        parameterClass="test.Object"
        resultClass="int">
        INSERT INTO objects(expression, meta, title,
        usersid)
        VALUES (#expression#, #meta#, #title#, #usersId#)
        RETURNING id
</statement>

在Java代码中:

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