2016-08-11 10 views
1

PostgreSQLでは、トランザクションでエラーが発生した場合(たとえば、挿入文が一意制約に違反した場合など)、トランザクション全体が中止され、コミットできず、行も挿入されません。PostgeSQLとOracleのデフォルトトランザクション管理

database=# begin; 
BEGIN 
database=# insert into table (id, something) values ('1','whatever'); 
INSERT 0 1 
database=# insert into table (id, something) values ('1','whatever'); 
ERROR: duplicate key value violates unique constraint "table_id_key" 
Key (id)=(1) already exists. 
database=# insert into table (id, something) values ('2','whatever'); 
ERROR: current transaction is aborted, commands ignored until end of transaction block 
database=# rollback; 
database=# select * from table; 
id | something | 
-----+------------+ 

(0 rows) 

あなたはそのあとに、エラーを無視して、複数の挿入を行うコミットのみに成功し、取引終了後にテーブルの行を挿入していることができ、「オン」または「インタラクティブ」にON_ERROR_ROLLBACKを設定することであることを変更することができます。オラクルで

database=# \set ON_ERROR_ROLLBACK interactive 

、これは私に驚き、デフォルトトランザクション管理行動、です。これは完全に直観的で危険なものではありませんか?

私はトランザクションを開始するときに、すべてのステートメントが成功したことを確認したいと思います。私の複数の挿入物が何らかの種類のオブジェクトまたはデータ構造を含む場合はどうでしょうか?私はデータベース内のデータ状態を完全に認識しなくなり、コミット後にそれをチェックする必要があります。 挿入のいずれかが失敗した場合は、最初のエラーの後に他の挿入がロールバックされるか評価されないようにしたいと思います。これはPostgreSQLでの処理方法とまったく同じです。

Oracleにはこのようなトランザクション管理方法がデフォルトとして組み込まれているのはなぜですか?なぜ、それは良い方法であると考えられますか?例えば

、いくつかのランダムな男here in comments

これは非常に巧妙な機能です。

私も、このことを理解していない:

「通常、あなたが作る任意のエラーが 例外をスローし、現在のトランザクションがアボート としてマークされるようになりますこれは...行動SANEと期待されています」

いいえ、それは本当にありません。 Oracleはこのように動作しませんし、MySQLも動作しません。私は MSSQLまたはDB2の経験がありませんが、私はそれぞれ のいずれかの方法で動作しない1ドルを賭けるでしょう。構文 のエラーやそれ以外のエラーが原因でトランザクションが中止されるという直感的な理由はありません。 この動作が必要なPostgres にはいくつかの制限があります。あるいは、他の誰もが無視できないようなSQL標準の一部であるわかりにくい に準拠していると思います。 API/UXの理由で、このように動作する理由はありません。

我々は、この病理学的挙動について を開発したすべての回避策を誇りに思うべきではありません。それはITストックホルム症候群のようなものです。

取引の定義さえ違反していませんか?

トランザクションは、データベース内で実行さ 各作業単位はその 全体が完全または全く効果がありませんしなければならないのいずれかと述べて、「オール・オア・ナッシング」の命題を提供しています。

答えて

3

私はあなたに同意します。私はtx全体を中断しないことが間違いだと思う。しかし、人々はそれに慣れているので、合理的で正しいと思います。MySQLを使用する人々のように、DBMSは日付として0000-00-00を受け入れるべきだと考えるか、Oracleを使用している人は'' IS NULLを期待します。

構文エラーと他の何かが明確に区別されているという考えには欠陥があります。

私は

BEGIN; 

CREATE TABLE new_customers (...); 

INSET INTO new_customers (...) 
SELECT ... FROM customers; 

DROP TABLE customers; 

COMMIT; 

を記述する場合、私はそれは私が私のデータを失うことが原因構文エラーが生じタイプミスだと気にしません。私は、トランザクションがすべてのステートメントを正常に実行しなかったものの、まだコミットしていないことに気付きました。

PostgreSQLでソフトローバックを許可するのは技術的に実現可能ですが、実際にはステートメントによって行が実際に書き込まれる前に実行されることになります。したがって、解析およびパラメータのバインディング段階での失敗は、txが中止されないようにする可能性があります。クリーンアップに使用できる文のメモリコンテキストがあります。

ただし、文の変更が開始されると、tx内の以前の文と同じトランザクションIDを持つディスク上で行が変更されます。だからあなたはtx全体をロールバックせずにロールバックすることはできません。文のロールバックを許可するには、Pgは新しいサブトランザクションIDを割り当てる必要があります。そのためにはリソースが必要です。 SAVEPOINTを使用して明示的に行うことができます。内部ではpsqlの処理を行います。理論的には、パフォーマンス・コストだけでステートメント・ロールバックを実装するために、各ステートメントに対してこれを暗黙的に行うことをサーバーに許可することができます。しかし、PostgreSQLチームの大部分が(「IMOは合理的に」)「トランザクションが壊れても、やり続けるだろうが」トランザクションのセマンティクスが好きではないため、これを実装するパッチは少なくとも多くは議論の余地がないとは思えない。

+0

良い点!たぶん、それをやり遂げるための議論があるかもしれません。ただ、私はOracleの方法では「利便性」を除いて何も表示されません。 – Snifff

+0

_人がOracleを使用するとNULL = NULLが真ではないと予想しています。 –

+0

@コンスタンチンソロキンいいえ、私は間違っていました。私が考えていたのは、Oracle 9iでは '' 'IS NULL'です。 http://stackoverflow.com/q/13278773/398670。私はDBMSが 'NULL = NULL'が真だった場所を覚えていません...古いMS SQL? Microsoft Access/JETエンジン?古いMYSQL? –

関連する問題