[Seasar-user:14718] Re: [dbflute]idの自動採番について

kubo [E-MAIL ADDRESS DELETED]
2008年 6月 16日 (月) 21:08:44 JST


久保です。

植田さん、こんばんは

下記の件、自分も悩んだことがあります。

S2TestCase#readXlsReplaceDb()は利用しておりませんが、
DBFluteのReplaceSchemaを利用してテストデータを投入して
いて、全く同じ現象が発生しました。

 1. replace-schema.batを実行
  1-1. playsql/replace-schema.sqlでCreateTable&Sequence
  1-2. playsql/data配下のデータが登録される
    →ここではSequence利用しないで登録(1,2,3,4,5...)

 2. JUnitからinsert()
  →Sequenceが1から始まるので例外

自分は、この手順の中に
「現在のテーブルに入っているIDのMAXをsetval()」
する処理を含めて回避できました。

 1. replace-schema.batを実行
  1-1. playsql/replace-schema.sqlでCreateTable&Sequence
  1-2. playsql/data配下のデータが登録される
    →ここではSequence利用しないで登録(1,2,3,4,5...)
  1-3. playsql/take-finally.sqlでsetval() {★}
    →「現在のテーブルに入っているIDのMAXをsetval()」
    →テストデータ投入後に実行される(take-finally.sql)

 2. JUnitからinsert()
  →SequenceがMaxの次から始まるので正常動作

そのplaysql/take-finally.sqlは実際にこれです。

// DBFlutePostgreSQLExample
https://www.seasar.org/svn/sandbox/dbflute/trunk/dbflute-postgresql-example/dbflute_exampledb/playsql/take-finally.sql

select setval('member_member_id_seq', (select max(member_id) from member));
select setval('member_login_member_login_id_seq', (select
max(member_login_id) from member_login));
select setval('product_product_id_seq', (select max(product_id) from product));
select setval('purchase_purchase_id_seq', (select max(purchase_id)
from purchase));

※serial型のSequenceを利用しています。


このように
「現在のテーブルに入っているIDのMAXをsetval()」
する処理をreadXlsReplaceDb()を実行したときに
一緒に実行されるように仕掛けることで回避できるかと思います。
S2TestCaseを継承したそのプロジェクト独自の抽象TestCaseを
作成し、そこでこの処理を入れるのが良いかと思います。

(もしくは、手間でなければテストデータを100万台から
 始めるというのも手です。テストを100万回実行しない限り
 落ちることはないはずです。が、ちょっと気持ち悪い気もします)

> 「work」のテーブルの ID のカラムは SERIAL8 で作成し、Sequence設定は行っ
> ておりません。
> 試しにSequence設定で以下のような設定を行いましたが、insert時に振られるID
> はやはり 1 から始まりました。

はい、これに関しては、PostgreSQLのserial型は特別扱いで
Sequence設定を省略できるようにしてあるだけなので、
明示的に設定しても特に何も変わりません。
http://dbflute.sandbox.seasar.org/contents/dbvendor/postgresql.html


2008/6/16 Chihiro Ueta <[E-MAIL ADDRESS DELETED]>:
> 植田と申します。
> いつもお世話になっております。
>
> dbfluteのインサート時のIDの自動割り当てについて質問させてください。
>
> 以下のような環境で使用させて頂いております。
> DB:PostgreSQL8.1
> jdbc:8.3-603.jdbc3
> dbflute:0.7.1
> s2-framework:2.4.24
> s2dao:1.0.47
>
> S2Unitで、S2TestCase#readXlsReplaceDb("エクセルファイル") を利用したテス
> トを行っております。
> 「work」のテーブルのテストを行うためにエクセルファイルには、ID(primary
> key)が 1 から 5 までのテストデータを「work」のテーブルに登録しておりま
> す。テストには「work」テーブルの外部参照テーブルを含めたいため、エクセル
> ファイルにはID(primary key)も指定しております。
> 「work」テーブルに対してdbfluteのWorkBhv#insertのテストを実行した場合
> に、ID が 1 から始まってしまうため、下のようなプライマリキーが重複してい
> るというエラーが発生します。この場合のテストを成功させるために、何か良い
> 方法はないでしょうか?設定内容などについて注意点などが御座いましたらご助
> 言頂けませんでしょうか?
>
> --------エラー内容--------
> org.seasar.framework.exception.SQLRuntimeException: [ESSR0072]SQLで例外
> (SQL=[INSERT INTO work ("省略") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
> ?, ?, ?, ?, ?, ?)], Message=[[ESSR0072]SQLで例外(SQL=[INSERT INTO work
> ("省略") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)],
> Message=[0], ErrorCode=23505, SQLState={3})が発生しました : [SQLで例外
> (Message=[ERROR: duplicate key violates unique constraint "work_pkey"],
> ErrorCode=0, SQLState=23505)が発生しました。], [ERROR: duplicate key
> violates unique constraint "work_pkey"], ErrorCode=0, SQLState=23505)が
> 発生しました
> --------------------------
>
> 再度テストを実行すると、自動で割り当てられるIDは 2 になります。
> これを繰り返すと、IDは1づつ大きくなっていき、6 になったときにテストに成
> 功します。
>
> 「work」のテーブルの ID のカラムは SERIAL8 で作成し、Sequence設定は行っ
> ておりません。
> 試しにSequence設定で以下のような設定を行いましたが、insert時に振られるID
> はやはり 1 から始まりました。
>
> dfprop/sequenceDefinitionMap.dfprop
>
> map:{
>    ; work     = work_id_seq
> }
>
> 以上、宜しくお願い致します。
>
> _______________________________________________
> Seasar-user mailing list
> [E-MAIL ADDRESS DELETED]
> https://ml.seasar.org/mailman/listinfo/seasar-user
>


Seasar-user メーリングリストの案内