PostgreSQLとGenerationType.IDENTITYではまる。

Seasar2.2.40、PostgreSQL8.4/PostgreSQL8.3系で次のようなエラー。

  • idは、SERIAL型。
  • Entityクラスでは、@GeneratedValue(strategy = GenerationType.IDENTITY)を利用。

で、次のようなExceptionはいて落ちる。テーブル自体は、insertされているので、try/catchすれば気にならない...か(?)

Exception in thread "main" org.seasar.framework.exception.SQLRuntimeException: [ESSR0072]SQLで例外(SQL=[select currval('EMPLOYEE_ID_seq')], Message=[[ESSR0072]SQLで例外(SQL=[select currval('EMPLOYEE_ID_seq')], Message=[0], ErrorCode=55000, SQLState={3})が発生しました : [SQLで例外(Message=[ERROR: currval of sequence "employee_id_seq" is not yet defined in this session], ErrorCode=0, SQLState=55000)が発生しました。], [ERROR: currval of sequence "employee_id_seq" is not yet defined in this session], ErrorCode=0, SQLState=55000)が発生しました
	at org.seasar.framework.util.PreparedStatementUtil.executeQuery(PreparedStatementUtil.java:51)
	at org.seasar.extension.jdbc.id.IdentityIdGenerator.getGeneratedId(IdentityIdGenerator.java:119)
	at org.seasar.extension.jdbc.id.IdentityIdGenerator.postInsert(IdentityIdGenerator.java:78)
	at org.seasar.extension.jdbc.query.AutoInsertImpl.postExecute(AutoInsertImpl.java:250)
	at org.seasar.extension.jdbc.query.AbstractAutoUpdate.executeInternal(AbstractAutoUpdate.java:126)
	at org.seasar.extension.jdbc.query.AbstractAutoUpdate.execute(AbstractAutoUpdate.java:90)
	at test.a.AMain.run(AMain.java:29)
	at test.a.AMain.main(AMain.java:50)
Caused by: org.seasar.framework.exception.SSQLException: [ESSR0072]SQLで例外(SQL=[select currval('EMPLOYEE_ID_seq')], Message=[0], ErrorCode=55000, SQLState={3})が発生しました
	at org.seasar.extension.jdbc.impl.PreparedStatementWrapper.wrapException(PreparedStatementWrapper.java:72)
	at org.seasar.extension.jdbc.impl.PreparedStatementWrapper.wrapException(PreparedStatementWrapper.java:67)
	at org.seasar.extension.jdbc.impl.PreparedStatementWrapper.executeQuery(PreparedStatementWrapper.java:83)
	at org.seasar.framework.util.PreparedStatementUtil.executeQuery(PreparedStatementUtil.java:49)
	... 7 more
Caused by: org.postgresql.util.PSQLException: ERROR: currval of sequence "employee_id_seq" is not yet defined in this session
	at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2062)
	at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1795)
	at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:257)
	at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:479)
	at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:367)
	at org.postgresql.jdbc2.AbstractJdbc2Statement.executeQuery(AbstractJdbc2Statement.java:271)
	at org.seasar.extension.jdbc.impl.PreparedStatementWrapper.executeQuery(PreparedStatementWrapper.java:81)
	... 8 more

エラーは、currvalが設定されていないよーというエラー。仕様的(PostgreSQLの)には、currvalする前にnextvalしないといけないのでnextvalをしていないと仮定するならば、納得がいくけど…。

サンプルコード

package test.a;

import java.io.*;
import java.util.*;

import org.seasar.extension.jdbc.*;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.SingletonS2ContainerFactory;

public class AMain
{
	public JdbcManager jdbcManager;
	
	public void run()
	{
		Employee emp1 = new Employee();
		emp1.name = "HelloWorld!!!";

		jdbcManager.insert(emp1).execute();
		jdbcManager.insert(emp1).execute();

	};
	
	public static void main(String args[])
	{
		SingletonS2ContainerFactory.init();
		S2Container container = SingletonS2ContainerFactory.getContainer();
		AMain amain = (AMain) container.getComponent(AMain.class);
		amain.run();
		container.destroy();
 	};
};

とりあえず、解放が見つからないのでGenerationType.SEQUENCEで試すかな...。

追記

トランザクション制御を忘れていたのが原因。

<component name="AMain" class="text.a.AMain">
     <aspect>j2ee.requiredTx</aspect>
</component>

あー。疲れた。