あやうく予告してあったURLにPDFファイルを置いといて、「これを印刷して手で書いて出してください」っとなるとこだった。。ここ3日間必死になって作ってたWEBアプリの第1フェーズが完成し、利用開始3時間前にリリースという危ない橋を渡った(汗。次また3日間で全部完成予定。
最後の最後、利用開始6時間前ぐらいにH2 Database相手にしかテストしてなかったアプリを本番DBであるPostgreSQLにして突撃したらエラーが出てもうダメかと思った。。
エラーはPostgreSQLで text 型を使っているフィールドに対応するEntityクラスのフィールドに @Lob があったのがいけなかったらしい。それで、今あらためて検索してみたらkoichikさんが関連してる回答をされていた。
- 例外
org.seasar.framework.exception.SQLRuntimeException: [ESSR0072]SQLで例外(SQL=[], Message=[Bad value for type int : user1], ErrorCode=0, SQLState=22003)が発生しました
at org.seasar.extension.jdbc.query.AbstractQuery.handleResultSet(AbstractQuery.java:443)
at org.seasar.extension.jdbc.query.AbstractSelect$6.handle(AbstractSelect.java:413)
at org.seasar.extension.jdbc.query.AbstractSelect$6.handle(AbstractSelect.java:410)
at org.seasar.extension.jdbc.query.AbstractSelect$1.handle(AbstractSelect.java:283)
at org.seasar.extension.jdbc.query.AbstractSelect$1.handle(AbstractSelect.java:281)
at org.seasar.extension.jdbc.manager.JdbcContextImpl.usingPreparedStatement(JdbcContextImpl.java:144)
at org.seasar.extension.jdbc.query.AbstractSelect.processPreparedStatement(AbstractSelect.java:278)
at org.seasar.extension.jdbc.query.AbstractSelect.processResultSet(AbstractSelect.java:407)
at org.seasar.extension.jdbc.query.AbstractSelect.getSingleResultInternal(AbstractSelect.java:232)
at org.seasar.extension.jdbc.query.AbstractSelect.getSingleResult(AbstractSelect.java:177)
at org.example.hoge.entity.AdminUserTest.testFindById(AdminUserTest.java:32)
...
- 対応するEntityのフィールド
/** uidプロパティ */ @Lob @Column(length = 2147483647, nullable = false, unique = true) public String uid;
このEntityはS2JDBC-Genで生成したものですが、ソース見てみたら、org.seasar.extension.jdbc.gen.internal.dialect.PostgreGenDialectの225行目でtext型の時はlobをtrueにしているようです。
private static PostgreColumnType TEXT = new PostgreColumnType("text",
String.class, true);
これをfalseにすれば良いんだろうけど、そうすると、EntityからDBスキーマを生成する時に影響してしまうのかな?
また、そうしたらそうしたらで、H2 DatabaseのCLOB使ってる属性に対応するEntityには@Lobが付くことになるのに、それをそのままPostgreSQLで使えば結局エラーが出るので、そもそも異なるDBサーバをいったりきたりして開発するのが間違いなのかもしれない。
とりあえず仮眠してからまた考えよう。
- [追記 11:46]
- DBスキーマ
CREATE TABLE admin_user ( id BIGSERIAL NOT NULL PRIMARY KEY, uid TEXT NOT NULL UNIQUE );
- レコード例
INSERT INTO admin_user (id, uid) VALUES (1, 'user1');
- Entity全体
@Entity
public class AdminUser {
/** idプロパティ */
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(precision = 19, nullable = false, unique = true)
public Long id;
/** uidプロパティ */
@Lob
@Column(length = 2147483647, nullable = false, unique = true)
public String uid;
}
- 例外が発生するテストケース例
- uidの@Lob外すと例外出ずに正常に実行されるようになります。
public void testFindById() throws Exception {
jdbcManager.from(AdminUser.class).id(1L).getSingleResult();
}
- 実行されたSQL
select T1_.ID as C1_, T1_.UID as C2_ from ADMIN_USER T1_ where T1_.ID = 1
[追記 10/14 11:45]
本件、id:taediumさんとこのPostgreSQLのTEXT型はCLOBか否か?に続きがあり、PostgreSQLのTEXT型では@Lobを付けてはいけないということになりました。修正ありがとうございました。
コメントが付けられなかった件、tDiaryの「ツッコミ中でURLを表す文字の占める割合が70%より高いものはspamとみなす」という設定に引っかかってしまったのではないかと思います、すいません。数値を30%に変えておきました。
[追記 10/29 0:39]
すこし時間空いてしまいましたが、id:taedumさんとこのPostgreSQLのTEXT型はCLOBか否か? その2より、@LobつきStringをOID型ではなくTEXT型にマッピングすることになったそうです。
この記事に関連する別の記事:
- Newer: 第1フェーズ完了
- Older: S2JDBCで複雑なSQLもタイプセーフに流れるようなインターフェースで書いた方が良いと思う理由
コメント:11
- koichik 70-01-01 (木) 0:00
-
> @LOBつきStringのときは、TEXT型から取得するロジックが動くように
PostgreSQL の TEXT は (JDBC 的には) CLOB じゃなみたいだから,(PostgreDialect 直して) StringClobType が使われるようになってもダメじゃないかなぁ?
Gen-Entity で TEXT は @LOB 無しString にマッピング,Gen-Ddl で @LOB 付き String は OID にマッピングすべきってことじゃないかと.
Gen-Entity で OID だと @LOB 付きbyte[] になったりして可逆的じゃなくなるけどそれはしょうがないということで. - taedium 70-01-01 (木) 0:00
-
LOBじゃないですけど、TEXTをCLOB相当とみなしてもいいんじゃないかなと思いました(Hibernateはそうしているようです)。@LobなしStringをVARCHAR型、@LobありStringをTEXT型にマッピングするのはわかりやすいくていいのかな、と。本当はLOBじゃないというのが弱点ですけど。
- taedium 08-09-30 (火) 13:49
-
再現できました。@LOBがあるとOID型から取得しようとするロジックが動作していました。@LOBつきStringのときは、TEXT型から取得するロジックが動くように(StringClobTypeが使われるように)S2JDBC側を直したほうがよさそうです。これについては、コミッタ間で相談してみます。
データによってはTEXT型であっても@LOBつきStringにマッピングできていて、私がこれまで動作確認していたのはそのようなデータを使ったものでした。
- jfut 08-09-30 (火) 14:09
-
確認ありがとうございます。そのように修正していただけると特に変更加えずに使えるようになるので助かります(^^)
- koichik 08-10-01 (水) 2:00
-
> TEXTをCLOB相当とみなしてもいい
PostgreSQL 的には TEXT は長さ制限のない (といっても上限は 1GB らしい?) VARCHAR に過ぎないみたいなので,それはどうなのかなぁ.
@Column の length が指定されたら VARCHAR,されなかったら TEXT というのが妥当なような.
もし OID を CLOB として扱えないなら TEXT を CLOB とみなしてもいいのかもしれないけれど,1GB を超える文字列を扱うには OID にするしかなくて,それを CLOB として扱えるなら,@Lob 付き String は OID にすべきではないかと. - taedium 08-10-05 (日) 10:08
-
> これをfalseにすれば良いんだろうけど、そうすると、EntityからDBスキーマを生成する時に影響してしまうのかな?
DBスキーマ → Entity と Entity → DBスキーマ は別ロジックなので影響しません。
でも、私がテストした限りではtext型は@LobつきのStringにマッピングするで動いていました。
koichikさんが回答しているのはCLOB相当ではなくBLOB相当の話なので直接は関係しないと思います。 - jfut 08-10-05 (日) 11:53
-
> DBスキーマ → Entity と Entity → DBスキーマ は別ロジックなので影響しません。
ご回答ありがとうございます。
> でも、私がテストした限りではtext型は@LobつきのStringにマッピングするで動いていました。
PostgreSQLのバージョンはいくつでテストされてますでしょうか?同じバージョンにしてみたいと思います。こちらはちょっと古いのを使っていてそれが悪いのかもしれませんが、PostgreSQL 8.2.3 + 8.2-508.jdbc3.jarです。8.3-603.jdbc3.jarにすると例外のBad value for type int : user1の部分がBad value for type long : user1になったりしました。また、念のため、Entity全体やテストケースを追記しました。よろしくお願いします。
- koichik 08-10-05 (日) 16:00
-
taedium さん (ひがさんも) 今日から合宿なので返事は遅れるかも.
自分が調べた限りでは,やっぱり TEXT 型は (C)LOB ではないようです.PostgreSQL では唯一 OID 型だけが LOB みたい.なので,String でも @Lob 付けられたら OID にすべきなんでしょうね.
ともあれ (JW),幸い H2 の VARCHAR もサイズの制限はない (メモリの制限内) ので,@Lob を外せばどちらでも動くんじゃないでしょうか. - jfut 08-10-05 (日) 17:15
-
> ともあれ (JW),幸い H2 の VARCHAR もサイズの制限はない (メモリの制限内) ので,@Lob を外せばどちらでも動くんじゃないでしょうか.
アドバイスありがとうございます。そのようにしたいと思います。
また、良く考えたらそもそもDB間またがる時は、TEXT型のようにDB独自の型ではなく汎用性の高そうなVARCHARで定義すべきでしたね。
- taedium 08-10-06 (月) 17:04
-
テストケースありがとうございます。(いまテスト環境がないので明日)試してみます。
- jfut 08-10-06 (月) 19:43
-
よろしくお願いしまーす。
トラックバック:0
- このエントリーのトラックバックURL
- http://jfut.integ.jp/2008/10/10/%E9%96%93%E4%B8%80%E9%AB%AA%E3%83%BB%E3%83%BB%E3%83%BB/trackback/
- Listed below are links to weblogs that reference
- 間一髪・・・ from ふたつの川うるおう日記

