[pgsql-jp: 30179] Re: Serial型の列とトランザクション

Jun Kitamura kitamura @ zoozee.jp
2003年 6月 17日 (火) 20:15:35 JST


北村です。

> 初めの誤った挿入をbegin、rollback で囲んだ
> トランザクションにしてやっても、
> シーケンサーは、数を進めてしまいます。
> ちょっと困った感じなのですが、

「連番」を要求しているのであれば、SERIAL型を使う設計が間違っ
ています。

id を int4 などにして、
BEGIN
 テーブルをロック
 最大値+1を取得
 インサート
COMMIT
のトランザクション処理が必要だと思われます。

insert into tb ( id,int,txt )
values (
 (select max(t2.id) + 1 from tb t2),
  11,
  'abc'
);
というようにテーブルロックを使わずに書いてあるのを見たことが
ありますが、どれくらいの確率か解りませんが、タイミングによっ
ては id が競合してしまう(PRIMARY KEY ならエラー)となる「気が
します」。

実際に実験したことがあり、エラーは発生しませんでした。複数の
トランザクションを同時に実行する、というタイミングの取り方が
悪いかもしれない、という疑念が残っているので、私の中では「連
番にならない場合もある」ということにしています。

このあたり、識者の方のご意見を伺いたいです・・・。

> 制約等の制限で挿入ができなかった時は、シーケンサーを進めない、
> あるいは、元に戻す方法は無いのでしょうか?

元に戻すには、setval(text,bigint)関数で値を設定してやれば戻
りますが、今回のケースでは意味なさそうです。

> 「トランザクション」に期待してはだめなのでしょうか?

シーケンスは、1トランザクションにいくつのシリアル値を確保す
るかを設定できます。例えばあるトランザクション(T1)が 1 を確
保した場合、次のトランザクション(T2)は 2 が確保され、T1 がコ
ミットまたはロールバックしても、この値は変わりません。
「シリアル値」を保証するもので、連番を保証するものではありま
せん。





pgsql-jp メーリングリストの案内