1

主キーを持つ単純なテーブルがあります。読み取り操作のほとんどは、キーの正確な値によって 1 つの行をフェッチします。

各行のデータは、キーの順序でその前後の行と何らかの関係を維持しています。したがって、新しい行を挿入するときは、間に入る2行を読み取り、計算を行ってから挿入する必要があります。

懸念事項は、明らかに、別の接続が同じ間隔でキー値を持つ行を同時に追加する可能性があることです。2 番目の挿入が失敗するのとまったく同じキーの値である場合はカバーされますが、キーの値が異なるが同じ間隔である場合、関係が壊れる可能性があります。

解決策は、新しい行を追加することを決定したときに書き込み用にテーブル全体をロックするか、(可能であれば、疑わしい) キー値の間隔をロックすることです。それでも、その時点で読み取り専用トランザクションがブロックされないようにしたいと思います。

クライアント プログラムと IBM DB2 フリー エディションで C++ 用の libodbc++ ラッパーを使用して ODBC を使用しています (ただし、DB の選択は変更される可能性があります)。これは私がやろうと思ったことです:

  • 自動コミットとデフォルトの分離モードで接続を開始します
  • 新しい行を追加する必要がある場合は、auto-commit を false に設定し、分離モードを serialized に設定します
  • 新しいキー値の前後の行を読み取る
  • 新しい行を計算して挿入する
  • 専念
  • 自動コミットとデフォルトの分離モードに戻る

これは仕事をしますか?他のトランザクションは同時に読み取ることができますか? それを行う他の/より良い方法はありますか?

ところで、libodbc++ i/fa で読み取り専用トランザクションを指定する方法がわかりません。odbcで可能ですか?

編集:非常に有用な回答をありがとう、私は1つを選択するのに苦労しました.

4

3 に答える 3

2

データベースが SERIALIZABLE モードの場合、問題はまったくありません。キー K が与えられた場合、前のキーと次のキーを取得するには、次のクエリを実行する必要があります。

select key from keys where key > K order by key limit 1;      # M?
select key from keys where key < K order by key desc limit 1; # I?

上記はMySQLで動作します。この同等のクエリは DB2 で機能します (コメントから):

select key from keys where key = (select min(key) from keys where key > K);
select key from keys where key = (select max(key) from keys where key < K);

最初のクエリは、他のトランザクションが K より大きく M 以下のキーを挿入できないようにする範囲ロックを設定します。

2 番目のクエリは、他のトランザクションが K 未満で I 以上のキーを挿入できないようにする範囲ロックを設定します。

主キーの一意のインデックスにより、K が 2 回挿入されるのを防ぐことができます。だからあなたは完全に覆われています。

これがトランザクションです。データベース全体がロックされているかのようにコードを記述できます。

注: これには、真のシリアル化可能性をサポートするデータベースが必要です。幸いなことに、DB2 にはあります。真のシリアル化可能性をサポートするその他の DBMS: SQLServer、および MySQL/InnoDB。そうでない DBMS: Oracle、PostgreSQL!

于 2010-11-11T20:50:06.187 に答える
1

あなたの一般的なアプローチは正しいです。ただし、2つの行とその間のすべての可能な行をカバーするSELECTステートメントを使用する必要があります。例えば:

SELECT * FROM MYTABLE WHERE PKCOL BETWEEN 6 AND 10

悲観的なロックとシリアル化可能なトランザクション分離レベルを備えたデータベースシステムでは、このSELECTステートメントは、SELECTの結果を変更する新しい行が挿入されるのを防ぐ必要があります。

于 2010-11-11T14:39:40.883 に答える
1

データベースとストレージエンジンで許可されている場合は、SELECT FOR UPDATE間に挿入しようとしている両方の行に対して発行する必要があります。

これは、同時実行と競合しますSELECT FOR UPDATE

欠点は、行1012(挿入する)のロックによって、と(挿入する)の11選択も妨げられることです。8109

InnoDBinは、インデックスにロックをMySQL設定することもできます。つまり、インデックスレコードのロックと、次のレコード間のギャップです。next-key

この場合、SELECT FOR UPDATE最初の行でのみ発行する必要があるため、その前に行を同時に挿入する必要があります。

ただし、これにはインデックスを強制rangeし、クエリに応じて可能な場合とできない場合があるインデックスの条件を提供する必要があります。

于 2010-11-11T14:21:11.093 に答える