- - PR -
UPDATE処理
投稿者 | 投稿内容 | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2004-09-17 11:11
お世話になっています。
素朴な質問ですみませんが 現在、VB6でADOを使い SQL Server 2000に処理をしているのですが、 TSQLでUPDATE処理をかける時、 通常、 BEGIN TRANSACTION UPDATE テーブル WITH (ROWLOCK) SET フィールド = 値 WHERE 条件; IF(@@ERROR!=0) ROLLBACK TRANSACTION COMMIT TRANSACTION と記述すると思いますが、 VB側では、ADOのレコードセットを見て 成功したか失敗したかを判断しなければなりません。 失敗した場合は、再書き込みする処理をすると 何度もADOでSQLを実行することになるので リソース面で不安が出てきます。 そこで、TSQL内でループを使用して 失敗したら何度も再書き込みする処理にしようと思うのですが、 それによって起こる問題などあるでしょうか? また、もっとよいやり方があるとしたらご指摘をお願いします。 | ||||||||||||||||
|
投稿日時: 2004-09-19 13:54
トランザクションが 1ステートメントで構成されているときに、こんな書き方しないでしょ。
んなこたーない。挿入に失敗すればエラーが発生するから、それを補足すればいい。
なんで失敗したのに再書き込みするの? 失敗となった原因は取り除けたという保証があるの? 無限ループになってしまったりはしないの?
そもそも「失敗」って何を想定しているの? 制約違反による失敗であれば、リトライするだけ無駄。 ロックタイムアウトであれば、時間を延ばすとか、ブロッキング要因を取り除くように努力するとか。 予期せぬネットワークエラーであれば、リトライ中に復帰する可能性は低いだろうし…。 「失敗したら何度も再書き込みする処理にしようと思う」こと自体が誤りだと思うけど。 | ||||||||||||||||
|
投稿日時: 2004-09-22 10:47
ご返答ありがとうございました。
説明不備なところが多々あり、すみません。 なに分、TSQLを使うのは初めてなもので BEGIN TRANSACTION UPDATE テーブル WITH (ROWLOCK) SET フィールド = 値 WHERE 条件; IF(@@ERROR!=0) ROLLBACK TRANSACTION COMMIT TRANSACTION と、記述しなければ正しく動作しないものと思っていました。 しかし、UPDATE処理対象が複数ひっかかった場合 数件は更新処理に成功、数件は更新に失敗 といった状況で、更新前に戻る時はこの記述でも良いのかと思いますがどうでしょうか? エラーについては、 VB.NETや、ADO.NETを使えば簡単にできると思いますが、 VB6を使わないといけないため、 エラーが発生する度に、ON ERROR GOTOを使うのに抵抗があります^^; エラー想定は、他者が更新、読み込み処理でレコードをロックしている際 更新処理を行おうとした場合を想定しておりました。 他者の処理が終わり次第、こちらの更新処理するよう ループをかけようと思ったのですが、(もちろん、タイムアウト処理込み) あまり、現実的ではないようでね・・・ 更新に失敗したら、ユーザー側で再度リトライをかける形式に 変更するよう考え直してみようと思います。 | ||||||||||||||||
|
投稿日時: 2004-09-22 11:07
1ステートメント全体が(暗黙の)トランザクションになりますので、部分的に更新が成功するということはありません。
タイムアウトを 30秒に設定してアプリケーションで最大5回リトライするくらいなら、タイムアウトを 150秒に設定したほうが楽。無限にリトライするくらいなら、タイムアウトを無制限にしたほうが楽。 そもそも、トランザクション中にユーザーインターフェイスを挟まなければ、ブロッキング時間は一定に抑えることができるので問題になることはないと思いますが? | ||||||||||||||||
|
投稿日時: 2004-09-22 11:35
Accessのクエリーと同じように処理されと思ってました^^;
なるほど、とても参考になります。 早速試してみることにします。 ご教授ありがとうございました。 | ||||||||||||||||
|
投稿日時: 2004-09-22 12:01
(勘違いでしたら、すみません)
C/S(クラサバ)とは書いてないのでなんともですが・・・、 ・C/Sであったら 仕様的に問題はないのか?と疑問を感じました。 物理的(トランザクション)にて排他をかけるのはもちろんですが、論理排他を行う必要はないのかなと。 AさんとBさんがデータを参照し、Aさんが参照したデータを元に更新 Bさんも参照したデータを元に更新 となると...、論理排他が必要なのでは。 かつ、Bさんが更新を行おうとしても古いデータの為、Bさんの更新を取りやめてエラーメッセージ等を表示する 余計な世話だったかな(^^; | ||||||||||||||||
|
投稿日時: 2004-09-22 12:56
トランザクションのことを勘違いされていませんか? トランザクションが保証するのは原子性であり、排他制御は無関係です。排他制御はロック機構によって行われます。 通常、確実な更新を目的とする場合は更新ロックを獲得させます。これを悲観的ロックと言います。えんぞ@見習さんがおっしゃっている処理は楽観的ロックと呼ばれるものです。楽観的ロックについては、ADO などのミドルウェアによって実装されており、「更新を行おうとしても古いデータの為、更新を取りやめてエラーメッセージ等を表示する」という機能を備えています。 「物理排他」「論理排他」という言葉については分かりません。 | ||||||||||||||||
|
投稿日時: 2004-09-22 13:44
えんぞさん、未記入さんありがとうございます。
誤解のないよう私がやりたい、大まかな内容を記入します。 ズバリ、えんぞさんがおっしゃた通り C/S設計で、クライアントが2,3名でネットワークは、 普通のLANを使用する小規模なものです。 1オペレーションの流れは、 (1) サーバーからデータを読み込む (TSQL) (2) データの修正 (ユーザー) (3) サーバーにデータを書き込む (TSQL) といった、単純なものです。 ただ、読み込みと書き込みの間にユーザー処理を挟むため データの整合性がとれなくなります。 そこで、書き込みを行う前に 再度、サーバーからデータを読み込み 最初に読み込んだデータと一致するか照合します。 照合が一致すれば、修正データを書き込み 一致しなければ、エラーメッセージ表示をします。 サーバーにアクセスする 全てのTSQLは、分離レベル4 SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; を設定します。 えんぞさんは、こういったことを心配して下さったと思い、追記しておきます。 |