いつもお世話になっております。
開発環境は
・Windows XP
・VB6.0(SP6)
・Access2003
です。
ACCESSに複数のユーザが同時にアクセスし
データの追加・削除・更新を行う処理を作っております。
ソースは、以下の通りです。
------------------------------------------------------------
'// データベースをオープンする
Set cnConnection = New ADODB.Connection
cnConnection.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=\\Bfduser\S-Designer\SDesigner.mdb;" & _
"Jet OLEDB:Database Locking Mode=1;"
cnConnection.CursorLocation = adUseClient
cnConnection.Open
'// 更新対象のレコードをロックする(その1)
sSQL = "SELECT *"
sSQL = sSQL & " FROM [T_XXXXX]"
sSQL = sSQL & " WHERE ID = '99999'"
Set rdRecordset = New ADODB.Recordset
With rdRecordset
.ActiveConnection = cnConnection
.Properties("Jet OLEDB: Locking Granularity") = 2 (★)
.LockType = adLockOptimistic
.CursorType = adOpenKeyset
.Source = sSQL
.Open
End With
'// 更新対象のレコードをロックする(その2)
sSQL = "SELECT *"
sSQL = sSQL & " FROM [T_XXXXX]"
sSQL = sSQL & " WHERE ID = '99999'"
Set rdRecordset = New ADODB.Recordset
Call rdRecordset.Open(sSQL, cnConnection, adOpenKeyset, adLockOptimistic, adCmdTableDirect)
------------------------------------------------------------
ロック方法「その1」では、★印の部分でエラーになってしまいます。
ロック方法「その2」では、特に問題ないく処理は行われるのですが、ロックがかかりません。
VBからAccessに対しレコードロックを行う事自体無理なのでしょうか?
色々調べましたが分かりませんでした。
ご存じの方がおいででしたら、ご教授お願い致します。
アルカトラズモードにしたまでは良いですが、カーソルの選定で失敗しています。
> ロック方法「その1」では、★印の部分でエラーになってしまいます。
理由は2つ。
クライアントカーソルモードを採用している事と、
スペルミス(空白が余計)が含まれている事が原因です。
サーバカーソルにした上で、コロンの後の空白を除去しましょう。
> ロック方法「その2」では、特に問題ないく処理は行われるのですが、ロックがかかりません。
そもそもクライアントカーソルで、キーセットタイプは選択できません。
Open 後に、CursorType プロパティの内容などをチェックしておきましょう。
魔界の仮面弁士さん、ありがとうございます!!
ご教授頂いた通りに行った所、正常に動作しました。
が、自分が思っていたレコードロックでは無かったので
再度、ご質問させてください。
行いたいレコードロック処理は、
1.他の利用者に操作されないようレコードをロックする。
2.レコードロックすると同時に既に誰かにロックされているかを復帰値で判断し、
ロック中であれば「他の利用者が・・・」といったメッセージを表示する。
です。
SQL Server では、出来たので Access でも出来るのかなと安易に考えておりました。
なお、SQL Server では次のようなソースコードで処理を行っておりました。
------------------------------------------------------------
sSQL = "SET LOCK_TIMEOUT 0"
sSQL = sSQL & " SELECT *"
sSQL = sSQL & " FROM [T_XXXXX]"
sSQL = sSQL & " WHERE ID = '99999'"
On Error Resume Next
cnConnection.Execute sSQL
For lIndex = 0 To cnConnection.Errors.Count - 1
If (cnConnection.Errors(lIndex).NativeError = 1222) Then
MsgBox "他の利用者が・・・"
Exit For
End If
Next lIndex
------------------------------------------------------------
そもそも Access に対しては、このようなレコードロックは行えないのでしょうか?
ご存じの方がおいででしたら、ご教授お願い致します。
> 1.他の利用者に操作されないようレコードをロックする。
リードロックですか? ライトロックですか? リードライトロックですか?
また、それは絶対にレコードロックでなければいけないのでしょうか?
> 2.レコードロックすると同時に既に誰かにロックされているかを復帰値で判断し、
> ロック中であれば「他の利用者が・・・」といったメッセージを表示する。
Jet OLEDB:Locking Granularity ダイナミックプロパティで設定されるのは、
LockType プロパティ(DAO でいう LockEdits)のロック粒度を決めるための物です。
表現が難しいのですが、以下、RS1 と RS2 が別アプリのコネクションだとすると、
ADO では下記のような同時実行制御が行われます。既にご存知かも知れませんけれども。
《ペシミスティックの場合》
RS1.Collect("Col1") = "XYZ" 'ロック取得
RS2.Collect("Col1") = "ABC" 'エラー発生
RS.Update 'ロック解放
《オプティミスティックの場合》
RS1.Collect("Col1") = "XYZ"
RS2.Collect("Col1") = "ABC"
RS.Update 'ロックの取得と解放
RS.Update 'エラー発生
トランザクション制御も忘れずに。
http://www.canalian.com/workshop/access/JetCache.html
魔界の仮面弁士さん、ご回答ありがとうございます。
返信が大変遅くなって申し訳ございません。m(_ _)m
> リードロックですか? ライトロックですか? リードライトロックですか?
リードロックです。
> また、それは絶対にレコードロックでなければいけないのでしょうか?
はい。レコードロックでなければなりません。
> 表現が難しいのですが、以下、RS1 と RS2 が別アプリのコネクションだとすると、
> ADO では下記のような同時実行制御が行われます。
ご説明ありがとうございます。
やはり Access の場合、UpDate するまで誰かがロックしている事が分からないという事ですね…
レコード情報にフラグ持たせそれを判断するなどの対応で回避したいと思います。
今回も勉強させて頂きました。ありがとうございます。