Sybaseでの、動きがイマイチかもしれない件について
SybaseとS2DAOの間に何やら問題があるっぽいです。
正直に言って、この話を聞くまで、
プロダクトを知ってる程度だったので、全容が掴みきれていません。
どんな些細な事でも、構いません。情報のある方、トラックバックかコメントを下さい。
よろしくお願いします。
後、ずらずらと並べている事に間違いがあれば、是非ご指摘下さい。
現象について
Service AdministratorでDBに接続して、トランザクション内で、S2DAOを動かすと以下のエラーが発生する。
DEBUG 2005-04-26 00:06:12,250 [main] トランザクションを開始しました DEBUG 2005-04-26 00:06:13,140 [main] 物理的なコネクションを取得しました DEBUG 2005-04-26 00:06:13,171 [main] 論理的なコネクションを取得しました DEBUG 2005-04-26 00:06:13,359 [main] トランザクションをロールバックしました DEBUG 2005-04-26 00:06:13,437 [main] 物理的なコネクションを閉じました org.seasar.framework.exception.SQLRuntimeException: [ESSR0071]SQLで例外が発生しました。 理由はcom.sybase.jdbc3.jdbc.SybSQLException: The 'CREATE TABLE' command is not allowed within a multi-statement transaction in the 'tempdb' database. at org.seasar.framework.util.DatabaseMetaDataUtil.addPrimaryKeys(DatabaseMetaDataUtil.java:59) at org.seasar.framework.util.DatabaseMetaDataUtil.getPrimaryKeySet(DatabaseMetaDataUtil.java:37) at org.seasar.dao.impl.BeanMetaDataImpl.setupPrimaryKey(BeanMetaDataImpl.java:307) at org.seasar.dao.impl.BeanMetaDataImpl.setupDatabaseMetaData(BeanMetaDataImpl.java:300) at org.seasar.dao.impl.BeanMetaDataImpl.(BeanMetaDataImpl.java:67) at org.seasar.dao.impl.BeanMetaDataImpl. (BeanMetaDataImpl.java:54) at org.seasar.dao.impl.DaoMetaDataImpl. (DaoMetaDataImpl.java:89) at org.seasar.dao.impl.DaoMetaDataFactoryImpl.getDaoMetaData(DaoMetaDataFactoryImpl.java:42) at org.seasar.dao.interceptors.S2DaoInterceptor.invoke(S2DaoInterceptor.java:36) at examples.dao.DepartmentDao$$EnhancedByS2AOP$$134e4fb$$MethodInvocation$$insert1.proceed(MethodInvocationClassGenerator.java) at org.seasar.extension.tx.RequiredInterceptor.invoke(RequiredInterceptor.java:25) at examples.dao.DepartmentDao$$EnhancedByS2AOP$$134e4fb$$MethodInvocation$$insert1.proceed(MethodInvocationClassGenerator.java) at examples.dao.DepartmentDao$$EnhancedByS2AOP$$134e4fb.insert(DepartmentDao$$EnhancedByS2AOP$$134e4fb.java) at examples.dao.DepartmentDaoClient.main(DepartmentDaoClient.java:19) Caused by: com.sybase.jdbc3.jdbc.SybSQLException: The 'CREATE TABLE' command is not allowed within a multi-statement transaction in the 'tempdb' database. at com.sybase.jdbc3.tds.Tds.processEed(Tds.java:2942) at com.sybase.jdbc3.tds.Tds.nextResult(Tds.java:2246) at com.sybase.jdbc3.jdbc.ResultGetter.nextResult(ResultGetter.java:69) at com.sybase.jdbc3.jdbc.SybStatement.nextResult(SybStatement.java:220) at com.sybase.jdbc3.jdbc.SybStatement.nextResult(SybStatement.java:203) at com.sybase.jdbc3.jdbc.SybStatement.queryLoop(SybStatement.java:1698) at com.sybase.jdbc3.jdbc.SybCallableStatement.executeQuery(SybCallableStatement.java:103) at com.sybase.jdbc3.jdbc.SybDatabaseMetaData.returnResults(SybDatabaseMetaData.java:2543) at com.sybase.jdbc3.jdbc.SybDatabaseMetaData.getPrimaryKeys(SybDatabaseMetaData.java:2061) at org.seasar.framework.util.DatabaseMetaDataUtil.addPrimaryKeys(DatabaseMetaDataUtil.java:53) ... 13 more Exception in thread "main"
ポイントは、全てを単一のトランザクション下で動かさなければ、サックリと動く所かなぁ…。
環境について。
- J2SDK 1.4.2_02
- S2は2.2.6
- S2DAOは、1.0.23
- Sybaseは、Adaptive Server Enterprise 12.5.2
- JDBCドライバは、jConnect6.0
- 使用しているユーザは、Service Administrator(権限に関する問題は無いかなぁ…とか…)
- テーブルは、デフォルトで作成されるmodelカタログのdboスキーマ。
- テーブルのクリエイトスクリプト
create table dept (deptno numeric(2) not null primary key, dname varchar(14) null, loc varchar(13) null, versionno numeric(8) null); insert into dept values (10, 'accounting', 'new york', 0); insert into dept values (20, 'research', 'dallas', 0); insert into dept values (30, 'sales', 'chicago', 0); insert into dept values (40, 'operations', 'boston', 0);
Sybaseは、テーブル名で大文字小文字を区別するし、nullって指定しないと、カラムにnullがはいりゃあしねぇし…
public class Department implements Serializable { public static final String TABLE = "dbo.dept"; // ここより下は同じまま。s
.diconファイルの設定は以下の通り。
- j2ee.dicon
"com.sybase.jdbc3.jdbc.SybDriver" "jdbc:sybase:Tds:fuelzark:5000/model" "sa" "" 600 10
- DepartmentDao.dicon
j2ee.requiredTx dao.interceptor
考えている対応方針について
DaoMetaDataFactoryの新しい実装を作ろうかなぁ…と思っています。
S2Containerの初期化時に.diconファイルに登録されている全てのDaoの必要なメタデータを全部集めてしまう感じ。
metaタグで、s2-daoって記述してあるか、
アスペクトとして、S2DaoInterceptorと互換性のある型のクラスを指定しているものを、処理の対象とする感じ。
これなら、別にSybase対応では無く、単なる設定上の選択肢の1つになるだけなので、良いかなぁ…と。
コードなんて書かなくても、問題無く設定の方法を知ってる方、大募集です。
人から聞いたので裏が取れていない話
- そもそも、単一のトランザクション内で、SELECTとtempdbに対するCREATE TABLEを発行してはいけない。別な予めテーブルを作らなければいけない。
- 但し、オプションで、非推奨だが、それを可能にする設定方法もある。
この話は、僕の個人的な感覚から言うと、ちょっと納得できていません。
何故なら、tempdbに作成されるテーブルが、ORDER BY や GROUP BYの為の一時表領域であるならば、
「tempdbに対するCREATE TABLE」って、DBで勝手に発行しているコマンドだからです。
それを、ダメって言われても…。実際、今回検証に使ったコードの中でも、CREATE TABLEなんて発行してないし。
作成される可能性のある一時表は、全て先に作っとけ。って事なんでしょうか…。何だか無茶な気がします。
この辺にある筈なんですが、どうにも読み方が甘いのか見つかりません。
*1:これがダメな理由だったり…