- PR -

UPDATE処理

投稿者投稿内容
なし
会議室デビュー日: 2004/09/17
投稿数: 17
投稿日時: 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/17
投稿数: 667
投稿日時: 2004-09-19 13:54
引用:

BEGIN TRANSACTION
UPDATE テーブル WITH (ROWLOCK) SET フィールド = 値 WHERE 条件;
IF(@@ERROR!=0)
 ROLLBACK TRANSACTION
COMMIT TRANSACTION

と記述すると思いますが、


トランザクションが 1ステートメントで構成されているときに、こんな書き方しないでしょ。

引用:

VB側では、ADOのレコードセットを見て
成功したか失敗したかを判断しなければなりません。


んなこたーない。挿入に失敗すればエラーが発生するから、それを補足すればいい。

引用:

失敗した場合は、再書き込みする処理をすると
何度もADOでSQLを実行することになるので
リソース面で不安が出てきます。


なんで失敗したのに再書き込みするの?
失敗となった原因は取り除けたという保証があるの?
無限ループになってしまったりはしないの?

引用:

そこで、TSQL内でループを使用して
失敗したら何度も再書き込みする処理にしようと思うのですが、
それによって起こる問題などあるでしょうか?
また、もっとよいやり方があるとしたらご指摘をお願いします。


そもそも「失敗」って何を想定しているの?
制約違反による失敗であれば、リトライするだけ無駄。
ロックタイムアウトであれば、時間を延ばすとか、ブロッキング要因を取り除くように努力するとか。
予期せぬネットワークエラーであれば、リトライ中に復帰する可能性は低いだろうし…。

「失敗したら何度も再書き込みする処理にしようと思う」こと自体が誤りだと思うけど。
なし
会議室デビュー日: 2004/09/17
投稿数: 17
投稿日時: 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/17
投稿数: 667
投稿日時: 2004-09-22 11:07
引用:

しかし、UPDATE処理対象が複数ひっかかった場合
数件は更新処理に成功、数件は更新に失敗
といった状況で、更新前に戻る時はこの記述でも良いのかと思いますがどうでしょうか?


1ステートメント全体が(暗黙の)トランザクションになりますので、部分的に更新が成功するということはありません。

引用:

エラー想定は、他者が更新、読み込み処理でレコードをロックしている際
更新処理を行おうとした場合を想定しておりました。
他者の処理が終わり次第、こちらの更新処理するよう
ループをかけようと思ったのですが、(もちろん、タイムアウト処理込み)


タイムアウトを 30秒に設定してアプリケーションで最大5回リトライするくらいなら、タイムアウトを 150秒に設定したほうが楽。無限にリトライするくらいなら、タイムアウトを無制限にしたほうが楽。

そもそも、トランザクション中にユーザーインターフェイスを挟まなければ、ブロッキング時間は一定に抑えることができるので問題になることはないと思いますが?
なし
会議室デビュー日: 2004/09/17
投稿数: 17
投稿日時: 2004-09-22 11:35
引用:

1ステートメント全体が(暗黙の)トランザクションになりますので、部分的に更新が成功するということはありません。



Accessのクエリーと同じように処理されと思ってました^^;

引用:

タイムアウトを 30秒に設定してアプリケーションで最大5回リトライするくらいなら、タイムアウトを 150秒に設定したほうが楽。無限にリトライするくらいなら、タイムアウトを無制限にしたほうが楽。



なるほど、とても参考になります。
早速試してみることにします。

ご教授ありがとうございました。
えんぞ@?
ぬし
会議室デビュー日: 2004/07/06
投稿数: 271
お住まい・勤務地: はまっこ
投稿日時: 2004-09-22 12:01
(勘違いでしたら、すみません)
引用:

他者の処理が終わり次第、こちらの更新処理するよう


C/S(クラサバ)とは書いてないのでなんともですが・・・、
・C/Sであったら
 仕様的に問題はないのか?と疑問を感じました。
 物理的(トランザクション)にて排他をかけるのはもちろんですが、論理排他を行う必要はないのかなと。
  AさんとBさんがデータを参照し、Aさんが参照したデータを元に更新
  Bさんも参照したデータを元に更新
 となると...、論理排他が必要なのでは。
 かつ、Bさんが更新を行おうとしても古いデータの為、Bさんの更新を取りやめてエラーメッセージ等を表示する

余計な世話だったかな(^^;
未記入
ぬし
会議室デビュー日: 2004/09/17
投稿数: 667
投稿日時: 2004-09-22 12:56
引用:

物理的(トランザクション)にて排他をかけるのはもちろんですが、


トランザクションのことを勘違いされていませんか? トランザクションが保証するのは原子性であり、排他制御は無関係です。排他制御はロック機構によって行われます。

通常、確実な更新を目的とする場合は更新ロックを獲得させます。これを悲観的ロックと言います。えんぞ@見習さんがおっしゃっている処理は楽観的ロックと呼ばれるものです。楽観的ロックについては、ADO などのミドルウェアによって実装されており、「更新を行おうとしても古いデータの為、更新を取りやめてエラーメッセージ等を表示する」という機能を備えています。

「物理排他」「論理排他」という言葉については分かりません。
なし
会議室デビュー日: 2004/09/17
投稿数: 17
投稿日時: 2004-09-22 13:44
えんぞさん、未記入さんありがとうございます。


誤解のないよう私がやりたい、大まかな内容を記入します。

ズバリ、えんぞさんがおっしゃた通り
C/S設計で、クライアントが2,3名でネットワークは、
普通のLANを使用する小規模なものです。


1オペレーションの流れは、
(1) サーバーからデータを読み込む (TSQL)
(2) データの修正         (ユーザー)
(3) サーバーにデータを書き込む  (TSQL)

といった、単純なものです。
ただ、読み込みと書き込みの間にユーザー処理を挟むため
データの整合性がとれなくなります。

そこで、書き込みを行う前に
再度、サーバーからデータを読み込み
最初に読み込んだデータと一致するか照合します。
照合が一致すれば、修正データを書き込み
一致しなければ、エラーメッセージ表示をします。

サーバーにアクセスする
全てのTSQLは、分離レベル4

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

を設定します。

えんぞさんは、こういったことを心配して下さったと思い、追記しておきます。

スキルアップ/キャリアアップ(JOB@IT)