- - PR -
ロック処理
1
投稿者 | 投稿内容 | ||||||||
---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2007-06-04 20:51
お世話になっております。
VB.NETでDB(以降テーブルA)からレコードを1件ずつ読み取り、 DB(以降テーブルB)へ出力させるコンソールアプリケーションを作成しています。 テーブルAには処理済フラグの項目があり、処理が完了したレコードに対しては、 その項目を1にするUPDATE処理をします。 ソースはざっくりと下記となります。 'トランザクションの開始 Dim trn As OracleTransaction = cnnBusiness.BeginTransaction 'テーブルAから1レコードずつSELECT Dim reader As OracleDataReader reader = cmdSelect.ExecuteReader() Try While reader.Read() Dim juchuNo As String = reader.GetValue(0) Dim juchuGak As Integer = reader.GetValue(1) paramJuchuNo.Value = juchuNo paramJuchuGak.Value = juchuGak 'テーブルBにMERGE処理 cmdMerge.Parameters.Add(paramJuchuNo) cmdMerge.Parameters.Add(paramJuchuGak) cmdMerge.ExecuteNonQuery() cmdMerge.Parameters.Clear() 'テーブルAのレコードの処理済フラグを1に更新 cmdUpdate.Parameters.Add(paramJuchuNo)・・・★ 'cmdUpdate.CommandTimeout = 30・・・★★ cmdUpdate.ExecuteNonQuery()・・・★★★ cmdUpdate.Parameters.Clear() cnt = cnt + 1 End While trn.Commit() テーブルAのあるレコードがロックされていた場合、VB.NETの処理は★で止まります。 ここで下記3点の質問があります。 1.一定時間処理がとまった場合、テーブルAの最初のレコードからリトライするという要件を入れたい。 2.5回リトライし、それでもロックが解放されなかった場合、そのレコードはスキップしたい 3.スキップしたレコードをlog4netでログファイルに出力したい 1〜3の要件を満たすためにはどのようにコーディングすればよいか 教えていただけないでしょうか? | ||||||||
|
投稿日時: 2007-06-04 22:57
まず問題を切り分けて考えましょう。
1、2、3それぞれを個別に実現するためには何が必要なのか。 それさえ分かれば後はロジックを組むだけです。 それはそれとして、テーブルAのデータを読むときにテーブルAのレコードをロックしてしまえば、 リトライ処理はいらないような気もします。 #なんとなく★の箇所では止まらないような気が。 #★★★の箇所なら分かるんですが。 | ||||||||
|
投稿日時: 2007-06-05 20:37
まさるさん、ご回答ありがとうございます。
>それはそれとして、テーブルAのデータを読むときにテーブルAのレコードをロックて>しまえば、 リトライ処理はいらないような気もします。 テーブルAのレコードをロックできないときに、リトライ処理させたいのです。 >#なんとなく★の箇所では止まらないような気が。 >#★★★の箇所なら分かるんですが。 申し訳ありません。★★★で止まります。 いろいろ調べながらコーディングしたところ、もう一歩のところまで きました。現在のソースは以下の状況です。(かなり省いてます) Dim errorCnt As Integer = 0 While (True) Try cmdSelectLock.Parameters.Add(paramJuchuNo) readerLock = cmdSelectLock.ExecuteReader() cmdSelectLock.Parameters.Clear() Exit While Catch ex As OracleException If (errorCnt = RETRY_COUNT) Then cmdSelectLock.Parameters.Clear() Exit While End If errorCnt = errorCnt + 1 cmdSelectLock.Parameters.Clear() System.Threading.Thread.Sleep(5000) Finally readerLock.Close()・・・★★★★ End Try End While cmdSelectLockに指定してあるSQLはselect 〜 for update nowaitです。 テーブルAのレコードのロックに失敗すればリソース・ビジーとなり、 catch句の中で、5秒スリープさせリトライ処理します。 ここで壁にぶつかったのですが、★★★★でエラーとなります。 原因は、select 〜 for update nowaitでロック失敗した場合、 readerLockはnothingなので、★★★★でエラーになるのです。 ★★★★を省けば、少数レコードの場合は、問題なく動作しますが、 多数のレコードを処理させようとすると、 「ORA-01000: 最大オープン・カーソル数を超えました。」 というエラーが発生します。 ご指導のほどよろしくお願い致します。 | ||||||||
|
投稿日時: 2007-06-06 09:40
ただエラーを回避するだけならば、単純にreaderLockがNothingでない時のみ、 Closeメソッドを呼ぶようにすれば良いだけだと思います。 #どうもオブジェクトの破棄などを考慮されてないような気がします。 #下記サイトを参考にして実装してみてください。 #なお、バージョンを提示されてないので分かりませんが、 #VB 2005ならUsingが使えます。 ですが、どうも最初と要件が変わったように見受けられるのですが。 テーブルAのデータが
とします。そしてID=3のデータの更新でテーブルAのレコードがロックされていたとます。 最初の要件では、一定時間経過してもロックが解除されなかったらID=1,2のデータに対する更新をロールバックし、 もう一度ID=1のデータから更新処理を再開すると思っていました。 しかし、現在はID=3のデータに対して5秒待ってリトライするようになっています。 私、何か勘違いしていますでしょうか? _________________ まさるblog |
1