- PR -

トランザクション中でも他の接続からはSELECTできないのでしょうか。

1
投稿者投稿内容
McLaren
ぬし
会議室デビュー日: 2002/01/15
投稿数: 784
お住まい・勤務地: 東京
投稿日時: 2006-06-12 13:59
Win2000Pro + Access2000+SQLSV2000を使用しております。

 一つのテーブルに対してUPDATE文でデータを更新してトランザクションをかけている最中に
他のマシンから同じテーブルにSELECTをかけるとwaitがかります。

 そしてコネクション時に設定したタイムアウトを過ぎるとタイムアウトのエラーになりますが、
タイムアウトだけではなくて「他でトランザクション中だったのでタイムアウトでした!」
というエラーを取得するににはどうすればよろしいでしょうか。。

 何卒ご教授願います。

例)
■PC1
Cnnectionオープン
トランザクションBegin
SQL文実行 "UPDATE T1 ・・・"

MsgBox "TESTのため待ちましょう"

トランザクションCommit
Cnnectionクローズ

■PC2
'PC1でMsgBoxが表示されている間に
Cnnectionオープン
SQL文実行 "SELECT * FROM T1 ・・・"

(この時点でタイムアウトになるまでwaitがかかります。)



あるいはPC2側でT1に更新はかけれないが、SELECTはできる!などはできないでしょうか。
合わせてご教授のほどよろしくお願いいたします。
burton999
ぬし
会議室デビュー日: 2003/10/06
投稿数: 898
お住まい・勤務地: 東京
投稿日時: 2006-06-12 14:13
SQL Developer Center - Columns: トランザクション分離レベルの選択とデッドロックの問題
http://www.microsoft.com/japan/msdn/sqlserver/columns/webtech/webtech3.asp
McLaren
ぬし
会議室デビュー日: 2002/01/15
投稿数: 784
お住まい・勤務地: 東京
投稿日時: 2006-06-12 16:25
ご返信ありがとうございました。
ご教授いただいたサイトを拝見させていただきました。

IsolationLevelかなと思い、実験してみましたが
やはり他のマシンからはSELECTできませんでした。


Set objCn = New ADODB.Connection
With objCn
.ConnectionString = strProv
.ConnectionTimeout = lngTmOut
.IsolationLevel = adXactReadUncommitted
.Open
.BeginTranse
.Execute "UPDATE T1 SET ・・・"

MsgBox "テスト:ちょっと待ちましょう。"

.CommitTranse
End With


なんとかSELECT(ダーティリードと言うのでしょうか・・)を許すことはできないでしょうか。

何卒ご教授のほどよろしくお願いいたします。
burton999
ぬし
会議室デビュー日: 2003/10/06
投稿数: 898
お住まい・勤務地: 東京
投稿日時: 2006-06-12 16:47
これですかね。

[INFO] COM+、MTS のトランザクション分離レベルの設定
http://support.microsoft.com/?scid=kb;ja;215520&spid=2852&sid=1086
McLaren
ぬし
会議室デビュー日: 2002/01/15
投稿数: 784
お住まい・勤務地: 東京
投稿日時: 2006-06-13 08:21
お世話になります。うまくいきました!
が・・・気になることこが残りました。

Accessプロジェクト(.adpファイル)で作成してみましたところ
SQL文を直書きしないと駄目でした。

Set objCn = Application.CurrentProject.Connection
  Application.CurrentProject.Connection.IsolationLevel =adXactReadUncommitted

では駄目で


Set objCn = Application.CurrentProject.Connection
objCn.Execute "SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED"

だとうまくいきました。

何故
  Application.CurrentProject.Connection.IsolationLevel =adXactReadUncommitted

でうまくいかないのかがわかりませんが、 
objCn.Execute "SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED"
でうまくいったのでとりあえずこれで動かしたいと思います。


 さて、これでトランザクション中に別マシンからSELECTはできるようになったのですが、更新をかけようとすると希望通りwaitがかかります。
そこで首記の質問とダブりますが、

「他でトランザクション中だったのでタイムアウトでした!」

というエラーを取得するににはどうすればよろしいでしょうか。。
今のところ通常のタイムアウトとトランザクションのタイムアウトの区別がつきませんので、タイムアウトを短くして

「サーバーがこけているか、他で同じレコードを更新中のため、アクセスできませんでした」

とメッセージを出すしかございません。

 何卒ご教授たまりますようよろしくお願いいたします。
めだか
大ベテラン
会議室デビュー日: 2004/11/11
投稿数: 109
投稿日時: 2006-06-13 08:43
そういう事ならロック識別用のテーブル作って
アプリ側で判定したほうがいいような気がしますが
いーた
大ベテラン
会議室デビュー日: 2004/07/12
投稿数: 154
お住まい・勤務地: 東京
投稿日時: 2006-06-13 09:13
またはロック識別用のカラムを追加するか。

そもそもの話になりますが、未コミット状態のレコードを参照できるのは問題ないですか?
McLaren
ぬし
会議室デビュー日: 2002/01/15
投稿数: 784
お住まい・勤務地: 東京
投稿日時: 2006-06-13 10:20
皆様ご返信ありがとうございます。
未コミットのデータを元に在庫データを加算するなどの処理をしていないため、たまたまアプリの性質上問題は発生しませんでした。アドバイスありがとうございました。

またロック識別用のテーブル及びカラムを追加してアプリで処理する場合、ロックフラグを立てた状態でアプリが落ちた場合に、ロックされたままになりましてタイマーで消しに行くのも・・・

 あ!ロックフラグの書き込み自体も本件のようにトランザクションでBeginして書きこんでCommitしなければいいんですよね!
そして他からは常にフラグをダーティリードするようにすればいいんですよね!

 そうすれば万が一フラグを立ててアプリが落ちてもCommitしていないのでセッションが切れてフラグは元に戻るのではないでしょうか。
怪しい案かもしれませんが一度やってみます。

1

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