Access VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


456 / 2272 ツリー ←次へ | 前へ→

【11601】MDBの分離 と レコード操作 pon 10/4/9(金) 15:26 質問[未読]
【11602】Re:MDBの分離 と レコード操作 pon 10/4/9(金) 15:40 発言[未読]
【11603】Re:MDBの分離 と レコード操作 247b 10/4/12(月) 10:16 発言[未読]
【11604】Re:MDBの分離 と レコード操作 pon 10/4/12(月) 18:16 質問[未読]
【11605】Re:MDBの分離 と レコード操作 247b 10/4/12(月) 23:07 発言[未読]
【11606】Re:MDBの分離 と レコード操作 pon 10/4/14(水) 18:37 質問[未読]
【11607】Re:MDBの分離 と レコード操作 247b 10/4/14(水) 19:26 発言[未読]
【11608】Re:MDBの分離 と レコード操作 pon 10/4/15(木) 14:27 発言[未読]
【11609】Re:MDBの分離 と レコード操作 247b 10/4/15(木) 17:10 発言[未読]
【11627】Re:MDBの分離 と レコード操作 pon 10/4/21(水) 18:27 質問[未読]
【11628】Re:MDBの分離 と レコード操作 247b 10/4/22(木) 4:44 発言[未読]
【11631】Re:MDBの分離 と レコード操作 pon 10/4/22(木) 16:13 発言[未読]
【11638】Re:MDBの分離 と レコード操作 247b 10/4/23(金) 20:18 発言[未読]
【11632】Re:MDBの分離 と レコード操作 pon 10/4/22(木) 16:13 発言[未読]

【11601】MDBの分離 と レコード操作
質問  pon  - 10/4/9(金) 15:26 -

引用なし
パスワード
   こんにちは よろしくお願いいたします

サーバーにDT.MDB
ローカルPC 1人だけに、APP1_DT更新.MDB
ローカルPC 10人程度に、APP2_参照.MDB
で運用したいと思っています


Q1
下記コード(APP1_DT更新.MDB)で、
追加のみ dbs.Execute "INSERT INTO
がエラーは出ないのですが、レコード追加できません 
注)追加クエリの実行は出来ています
どうしたらよいでしょうか

上記は
ローカルのテーブルのレコードをサーバーに追加しています


Private Sub Test2()

  Dim dbs As DAO.Database
  Dim RT As Recordset
  
   On Error Resume Next
   'Set dbs = OpenDatabase("F:\db1.mdb")
   'Set dbs = OpenDatabase(LC_get_path, True, False)
   'Set dbs = OpenDatabase(LC_get_path, True)
   Set dbs = OpenDatabase(LC_get_path, Options:=True)
  
  
   Select Case Err.Number
  
    'エラーなし
    Case 0
      
      Set RT = dbs.OpenRecordset("DT02_PJ_DT", dbOpenTable)
      
      '追加1
      '下記成功
      'RT.AddNew
      '  RT![id] = "999777"
      'RT.Update
      'RT.Close
      
      
      '追加2
      'INSERT INTO DT02_PJ_DT IN '\\sv\PJ_DT.mdb' SELECT TmpT_PJ_DT.* FROM TmpT_PJ_DT;
      'dbs.Execute "DELETE DT02_PJ_DT.*, DT02_PJ_DT.id FROM DT02_PJ_DT IN '\\sv\PJ_DT.mdb' WHERE DT02_PJ_DT.id="1132002"; INSERT INTO Customers SELECT * FROM [New Customers];"
      '追加クエリはOKだが下記はSCCESSだが実際は駄目 ←Q1
      'dbs.Execute "INSERT INTO DT02_PJ_DT IN '\\sv\PJ_DT.mdb' SELECT TmpT_PJ_DT.* FROM TmpT_PJ_DT;"
      '仕方がないので 追加したが 警告ダイアログがでる
      Application.Echo False
      DoCmd.OpenQuery "追加クエリ1"
      Application.Echo True
      
      'レコード削除
      'DELETE DT02_PJ_DT.*, DT02_PJ_DT.id FROM DT02_PJ_DT IN '\\sv\PJ_DT.mdb' WHERE DT02_PJ_DT.id="1132002";
      '下記成功
      'dbs.Execute "DELETE DT02_PJ_DT.*, DT02_PJ_DT.id FROM DT02_PJ_DT IN '\\sv\PJ_DT.mdb' WHERE DT02_PJ_DT.id='1132003';"


      Debug.Print "success"
    
    '排他モードで開かれていた場合
     Case 3045
       'MsgBox Err.Description
       Debug.Print Err.Description
      
       GoTo ExitProc
      
    'その他のエラー
     Case Else
       'MsgBox Err.Description
       Debug.Print Err.Description
      
       GoTo ExitProc
   End Select
   On Error GoTo 0
  
ExitProc:
  
  dbs.Close

  Set dbs = Nothing

End Sub


Q2 
追加クエリを
      Application.Echo False
      DoCmd.OpenQuery "追加クエリ1"
      Application.Echo True
としているのですが
レコード追加の警告が出てしまいます
どうせれば出なくなりますか


Q3 Test2のサーバーMDBにレコード追加する APP1_DT更新.MDBは
   1人しか使用しません
  APP2_参照.MDBでは、リンクテーブルではなく
  フォームのレコードソースに
  DB.OpenRecordset(strSql, dbOpenSnapshot)
  で参照のみでの使用となっています
  
  このような運用であれば、破損の心配は無いような気もしますが
  どうなんでしょう
  注意点等あればアドバイスよろしくお願いいたします

【11602】Re:MDBの分離 と レコード操作
発言  pon  - 10/4/9(金) 15:40 -

引用なし
パスワード
   途中報告です

>Q2 
>追加クエリを
>      Application.Echo False
>      DoCmd.OpenQuery "追加クエリ1"
>      Application.Echo True
>としているのですが
>レコード追加の警告が出てしまいます
>どうせれば出なくなりますか

      DoCmd.SetWarnings False
      DoCmd.OpenQuery "追加クエリ1"
      DoCmd.SetWarnings True

で、警告だけは抑えることが出来ました

【11603】Re:MDBの分離 と レコード操作
発言  247b  - 10/4/12(月) 10:16 -

引用なし
パスワード
   こんにちは。

Q1
事例に該当するか分かりませんが、トランザクションを仕掛けてみてはどうでしょうか。
dbs.Executeの前に、WorkSpaces(0).BeginTrans
後にWorkSpaces(0).CommitTrans
エラー処理にWorkSpaces(0).Rollback
でトランザクションを仕掛けられます。

Q3
フォームのプロパティウィンドウの、「データ」タブに、
更新の許可
削除の許可
追加の許可
などのプロパティがありますので、これらを「いいえ」にすれば、ユーザーは参照できても更新できないはずです。

プログラムソースでは、スナップショット型のレコードセットを使用しているようですが、うろ覚えですが、スナップショット型は、レコードセットをオープンしたときのデータを保持するので、その後の最新状態を参照できない問題が起こりえると思います。
最新状態を表示するシステム上の必要性がある場合は、上記のようなフォームのプロパティで更新をコントロールしたほうが良いと思います。

【11604】Re:MDBの分離 と レコード操作
質問  pon  - 10/4/12(月) 18:16 -

引用なし
パスワード
   247b さん ありがとうございます


>Q1
>でトランザクションを仕掛けられます。
申し訳ないですが
こちらについては排他処理が完了してから試してみたいと思います
(取りあえず、追加クエリの発行で動作しますので)


>Q3
>最新状態を表示するシステム上の必要性がある場合は、上記のようなフォームのプロパティで更新をコントロールしたほうが良いと思います。

についてなんですが
Set RS = DB.OpenRecordset(strSql, dbOpenSnapshot)
Set RS = DB.OpenRecordset(strSql, dbOpenDynaset)
どちらも
forms("メインフォーム").Controls("サブフォーム").requery
で、更新データを表示することは出来ました
これを
タイマー等で動作させる
という理解でよろしいでしょうか


お詫び

Private Sub Test2()
では、排他チェックが出来ていませんでした
色々試している内に、出来ているのかと錯覚してしまいました

また、希望の操作は
>Q3 Test2のサーバーMDBにレコード追加する APP1_DT更新.MDBは
>   1人しか使用しません
でなくて
複数のAPP.MDBからDT.MDBを編集したい
となりました

APP.MDBから
DT.MDBを編集時のみ、排他で開いて、直ぐ閉じる
DT.MDBを開きに行って排他だったら、少し待機し再チャレンジ
みたいにすれば可能かなと思っています 
こんなことが出来るが自信がありませんが・・・

取りあえず、
サーバー上のDT.MDBが排他状態か取得してみようと下記試しましたが
うまく出来ません

アドバイスよろしくお願いいたします

MSの
[AC97]排他的に開かれたデータベースかどうかを判定する方法
tp://support.microsoft.com/default.aspx?scid=kb;ja;117539
を試してみました

'戻り値:データベースが排他モードで開かれている場合 = -1
'    データベースが共有モードで開かれている場合 = 0

Option Explicit

Declare Function SetCurrentDirectory Lib "Kernel32" Alias _
    "SetCurrentDirectoryA" (ByVal lopathname As String) As Long

Public Function IsCurDBExclusive2(tg_f As String) As Integer
  Dim db As Database
  Dim hFile As Integer
  hFile = FreeFile
  
  'カレントドライブ移動 下記2行、api宣言 途中追加
  SetCurrentDirectory Left(tg_f, InStrRev(tg_f, "\") - 1)
  Debug.Print CurDir
  
  Set db = DBEngine.Workspaces(0).Databases(0)
  'If Dir$(db.Name) <> "" Then
  If Dir$(tg_f) <> "" Then

   On Error Resume Next
    Open tg_f For Binary Access Read Write Shared As hFile

    Select Case Err.Number
      Case 0
        IsCurDBExclusive2 = 0  'False
        Debug.Print "0 共有モード"
        
      Case 70
        IsCurDBExclusive2 = -1 'True
        Debug.Print "-1 排他モード"
        
      Case Else
        IsCurDBExclusive2 = Err.Number
        Debug.Print Err.Number & "" & Err.Description
        
    End Select

    Close hFile
    On Error GoTo 0
  Else
     'MsgBox db.Name & "は、見つかりません。"
     Debug.Print tg_f & "は、見つかりません。"
     
  End If
End Function

下記では、デイレクトリ移動はしていません(↓以下で ドライブ移動追加)
自pcで開いているMDBでは
call IsCurDBExclusive2("C:\cp2\2010\201003\LDB Viewer Form\PJ_DT.mdb")
0 共有モード /PJ_DT.mdbを閉じている特
-1 排他モード /PJ_DT.mdbを開いている特
C:\cp2\2010\201003\LDB Viewer Form\PJ_DT2.mdbは、見つかりません。 /無いファイル指定時
と動作できましたが

ファイルサーバー上のMDBを開いてテストすると
call IsCurDBExclusive2("\\sv\test02_リンク無\PJ_DT.mdb")
0 共有モード /PJ_DT.mdbを閉じている特
0 共有モード /PJ_DT.mdbを開いている特
\\Tar-fs-dfs\dfs\083見積部共同作業\方針シート\test02_リンク無\PJ_DT2.mdbは、見つかりません。

排他モードが取得できていません


↓以下で ドライブ移動追加
接続先がネットワークということで
  'カレントドライブ移動 ファイルのパス取得して引数にしています
  SetCurrentDirectory Left(tg_f, InStrRev(tg_f, "\") - 1)
をしてみましたが
call IsCurDBExclusive2("\\sv\PJ_DT.mdb")
\\sv
0 共有モード
となってしまいます

もう一度時PCでPJ_DT.mdbを開いて試すと
call IsCurDBExclusive2("C:\cp2\2010\201003\LDB Viewer Form\PJ_DT.mdb")
C:\cp2\2010\201003\LDB Viewer Form
0 共有モード
となってしまいました ??
Open tg_f の指定はあっていると思うのですが・・・・

ちなみに
このAPP.MDBはマイドキュメントにあります
どうすれば、ファイルサーバー上のMDBが排他で開いているか判定できるでしょうか

わかり難いと思いますがよろしくお願いいたします

【11605】Re:MDBの分離 と レコード操作
発言  247b  - 10/4/12(月) 23:07 -

引用なし
パスワード
   こんばんわ。

>>Q3
>>最新状態を表示するシステム上の必要性がある場合は、上記のようなフォームのプロパティで更新をコントロールしたほうが良いと思います。
>
>についてなんですが
>Set RS = DB.OpenRecordset(strSql, dbOpenSnapshot)
>Set RS = DB.OpenRecordset(strSql, dbOpenDynaset)
>どちらも
>forms("メインフォーム").Controls("サブフォーム").requery
>で、更新データを表示することは出来ました
>これを
>タイマー等で動作させる
>という理解でよろしいでしょうか

タイマー、もしくはイベントでリクエリするのでよいと思います。
リクエリのタイミングや必要性は業務用件に関わってくるため、こちらからはなんとも言えませんが。


排他チェックについてですが、
 MDBファイルレベルの排他と
 ページレベルの排他
が考えられます。

的外れだったらすみません。

MDBファイルレベルの排他は、OpenDatabaseメソッドでMDBをオープンする際の引数optionsに
Trueを設定することで行います。この場合、他のユーザーがDBオープンしようとするとエラーとなるそうです。詳しくはOpendatabaseメソッドのヘルプを参照してください。
上記の方式でDBをオープンするようにしてからもう一度試してみてください。

ページレベルの排他は、必ず1行がロックされるわけではないので使用は控えた方が良いようです。
1行単位にロックをかけたい場合は、テーブルにロックのためにカラムを設け、たとえば
0だったらロックされていない、1だったらロックされているという仕様にします。
その上で、各APP.DBがデータにアクセスするとき、対照のデータのロックステータスを確認し、
1だったら待機、0だったら1に更新して、処理終了後0に戻す
などが考えられます。
1、0をユーザーID、NULLに置き換えることも設計上は可能です。プログラムが増えることと、チェックロジックのために処理が若干遅くなる事が考えられます。

【11606】Re:MDBの分離 と レコード操作
質問  pon  - 10/4/14(水) 18:37 -

引用なし
パスワード
   247b さん ありがとうございます


別件で遅くなりました

>タイマー、もしくはイベントでリクエリするのでよいと思います。
>リクエリのタイミングや必要性は業務用件に関わってくるため、
>ちらからはなんとも言えませんが。

了解です
ありがとうございます


>上記の方式でDBをオープンするようにしてからもう一度試してみてください。
ありがとうございます

これについては
DT.MDBを開くときは
手動で
「ファイル」→「開く」を選択
MDBファイルを選択
「開く」ボタンの右にある「▼」ボタンをクリックし、「排他モードで開く」を
選択
で開いて、その上でテストしていました

また、上記で開いた状態で
別PCから上記を開くと、開けませんメッセージが出るのを確認しています
ので、排他で開いているのは間違いないと思っています・・・
頂いたアドバイスを試してみてないので申し訳ないのですが
下記の確認をしてから試してみようと思ったのですが
この辺のチェックが一杯々で・・・、一歩づつで無いと手が出ません m(_ _)m
(理解不足が複合的に交錯しているように思えるため・・・)


APP1_入力.MDB
APP2_参照.MDB
DT.MDB
現状の動作確認をしてみました


APP2_参照.MDBのフォームのサブフォームデータシート形式
のレコードソースは
フォームロード時に
  Set dbs = OpenDatabase(LC_get_path, Options:=True) '排他で開く
  Me.CNB01_拠点.RowSource = "SELECT ・・・;"
で設定しています

APP2_参照.MDBのフォームが開いていないときには
APP1_入力.MDBからレコードの追加は出来ましが
APP2_参照.MDBのフォームが開いているとレコードの追加が出来ませんでした
(今回、気が付きました)

APP2_参照.MDB を 開いただけでは、DT.MDBのDT.LDBは作成されていませんでしたが
APP2_参照.MDBのフォーム(サブフォームデータシート形式)を開くと
DT.MDBのDT.LDBが作成されました←フォームを開いたので連結コントロールになってしまったようだ

この状態で
APP1_入力.MDBからDT.MDBにレコード登録するために
Set dbs = OpenDatabase(LC_get_path, Options:=True)
で、排他で開こうとするとエラーとなり
Err.Number
3356
Err.Description
このデータベースは、マシン 'hoge' のユーザー 'Admin' が排他的に開いています。
データベースが使用可能になった時点で、再度実行してください。
と、なる気がします

そこで
APP1_入力.MDBからレコード追加するときに

   'Set dbs = OpenDatabase(LC_get_path, Options:=True)

   Set dbs = OpenDatabase(LC_get_path)
とすると、レコードが追加できるようになりました

これから
Set dbs = OpenDatabase(LC_get_path, Options:=True) は
既に、DT.MDBのDT.LDBが存在するのに排他で開こうとしてエラーになっている
Set dbs = OpenDatabase(LC_get_path) は
排他管理をアクセス任せにしている状態になっている

と勝手な理解に至りました・・・ 合っているか不明ですが・・

他に
MDBを多重起動していて、同一レコード選択時、一方でレコード編集をすると
ほかのユーザーによってロックされているので、保存できませんでした。
に遭遇することがありますが
これもアクセス任せの排他管理ではと勝手に思っています

あいまいな理解ばかりでなんとも情け無いのですが
元々基本的な知識が無いので・・・・・ (~_~;)

当初は、排他制御のほうが楽なような気がしていましたが
上記のような状況では、アクセス任せの管理のほうが
簡単なような気がしてきました

頂いたアドバイス
>上記の方式でDBをオープンするようにしてからもう一度試してみてください。
は、この辺のロジックが正しくないとうまくテストできないような気がしています
どうなんでしょう・・・


<ADOを使ったレコード単位の排他ロックについて>
tp://www5f.biglobe.ne.jp/~f-lap/tips_adolock.htm
なんて見つけたのですが
まだ、理解できていない状態ですが
なんとなく
これがアクセス任せの排他制御のような気がしています

DAOでもいけそうな気がして、理解して試してみたいと思っています
がどうでしょう

わかりにくいと思いますが
本人自体??の状況ですのでご容赦よろしくお願い致します

アドバイス頂けると助かります
よろしくお願い致します

【11607】Re:MDBの分離 と レコード操作
発言  247b  - 10/4/14(水) 19:26 -

引用なし
パスワード
   こんばんは。おつかれさまです。

念のため確認1
アクセス任せの排他制御と、そうでない排他制御の違いを教えてください。
どうも、この辺にお互いの認識相違があるように思われます。

念のため確認2
参照.MDBからDT.MDBを参照するとき、リンクテーブルは使ってないんですよね?

>現状の動作確認をしてみました
この文以降の説明内容を拝見する限り、設定内容に不整合がないような気がします=プログラムとその処理結果が正しい。
逆に、入力.MDBでDT.MDBを開いた時に排他モードにして、参照.MDBで開く時に共有モードで開く(Option引数をつけない)というようにしてはどうでしょうか。


><ADOを使ったレコード単位の排他ロックについて>
>tp://www5f.biglobe.ne.jp/~f-lap/tips_adolock.htm
拝見しました。
使えるのではないかと思います。
が、実際にはレコード単位ではなく、ページ単位だったはずで、レコードのサイズにもよるのですが、場合によってはロックしたいレコードの前後のレコードもロックされるということが発生すると記憶しています。それで問題なければ使えると思います。

【11608】Re:MDBの分離 と レコード操作
発言  pon  - 10/4/15(木) 14:27 -

引用なし
パスワード
   247b さん ありがとうございます

>念のため確認1
>アクセス任せの排他制御と、そうでない排他制御の違いを教えてください。
>どうも、この辺にお互いの認識相違があるように思われます。
                   
改めて聞かれると・・・・
>>アクセス任せの排他制御
これだけであいまいな理解であることが明白みたいな・・・です

排他については
Set dbs = OpenDatabase(LC_get_path, Options:=True) '排他で開く
でMDBそのものがロックされ、他の人は開けない
(今回初めて体験しました)
アクセス任せの排他制御 は、それ以外みたいな・・・ (^_^;;;
認識でした

当初は間違ったテストと間違った理解で
APP1_入力.MDBからDT登録時、コード上でDT.MDBを排他で開いて、直ぐ閉じるのであれば、
APP2_参照.MDBから、DT.MDBのTBLをスナップショット系からみることは出来る
みたいな理解でした

今回の 念のため確認1 を頂き、再度、排他について調べてみました

VBA の Recordset オブジェクトで共有データをロックする
tp://msdn.microsoft.com/ja-jp/library/cc376533.aspx
なんてありました


以下抜粋

排他モードは、データのロック方法の中では最も制限レベルが高いもので、ほかのすべての
ユーザーはデータベースを開くことができず、データベース内のデータへアクセスできなくなります。

共有モードでデータベースを開くと、複数ユーザーが同時にアクセスでき、
Jet データベース エンジンによりユーザー間の競合が処理されます。

Recordset オブジェクトでは、次の 4 つのレベルでデータをロックします。

  * 排他モード  データベース全体を他のユーザーが使えないようにし、
  制限レベルが最も高くなります。
  * レコードセット ロック  Recordset オブジェクトのテーブルをロックします。
  * ページ レベル ロック  編集中のデータが保存されている 4096 バイト (4K) の
  ページ全体をロックします。
  * レコード レベル ロック  現在編集中のレコードのみをロックします。

ページ レベル ロックあるいはレコードセット ロックを使用した場合は、現在編集中の
レコードが含まれるページおよびレコードのみがロックされ、制限レベルとしては最も
低いものとなります。この場合、ほかのユーザーはページまたはレコードからデータを
取得できますが、変更はできません。

レコード レベル ロックは ADO および DAO Recordset オブジェクトの既定値です。
また、ページ レベル ロックは ADO Command オブジェクトまたは DAO QueryDef
オブジェクトを使用する SQL DML ステートメント (UPDATE、DELETE、および
INSERT INTO ステートメントなどの大規模な操作) の既定値となっています。

ページ レベルまたはレコード レベルでデータをロックする Recordset オブジェクトを
操作する場合は、ペシミスティック ロックまたはオプティミスティック ロックの
どちらかを選択

ADO Recordset オブジェクトのロック タイプを設定するには、Recordset オブジェクトに
用意されている Open メソッドの LockType 引数にある adLockPessimistic 定数または
adLockOptimistic定数を指定します。 DAO Recordset オブジェクトの場合は、LockEdits
プロパティを設定してロック タイプを変更できますが、ADO Recordset オブジェクトを
開いた後にロック タイプを変更することはできません。

ペシミスティック ロックでは、レコードの編集を開始するとそのレコードまたはレコードが
あるページがロック処理中はページ全体がロックされるため、ロックが解除されるまで他の
ユーザーがそのページのレコードを変更できない

オプティミスティック ロックでは、新規レコードへ移動、または Update メソッドを
使用してレコードへの変更を保存する際に、レコードまたはページがロックレコードの
編集中に正しい更新を確認できないことです。ほかのユーザーが最初にレコードを更新
した場合、レコード編集の更新は行われません。

抜粋 以上


文言的にはだいぶ理解できたつもりですが、コードはまだ??です (^^;) 

>念のため確認2
>参照.MDBからDT.MDBを参照するとき、リンクテーブルは使ってないんですよね?
今回の作業を始める前に一応下調べはしたのですが
リンクテーブルは駄目だとか、あってもよいとかの書き込みがあって
よく理解できなかったので、
取りあえずリンクテーブルはやめ、また、DT.MDBのDTを表示するコントロールも
非連結にしましたが、
結局、フォームを開くとき、
コントロールのレコードソースを設定しているのでリンクテーブル有り同じことに
なっているのではと思っています

>逆に、入力.MDBでDT.MDBを開いた時に排他モードにして、参照.MDBで開く時に共有モードで開く
>(Option引数をつけない)というようにしてはどうでしょうか。
のアドバイスなんですが

>>でなくて
>>複数のAPP.MDBからDT.MDBを編集したい
>>となりました

APP1_入力.MDB
APP2_参照.MDB
DT.MDB

APP2_参照.MDB からも DT.MDB へ入力したいと思っています
動作的には
APP2_参照.MDB から 選択したブックを 編集更新したら 更新日時をDT.MDBに書き込む
で、最終的には、エクセルから DT.MDB に書き込むつもりでいるのですが
今回は
便宜的に、APP2_参照.MDBからブックを開いたときに DT.MDB に書き込みたいと思っています

まとめると
APP1_入力.MDB を 使用するのは 1人で、作業時には作業を始めると30分程度は連続使用
APP2_参照.MDBは、10人ぐらいが使用するのですが、起動しっぱなしでもかまわない
DT.MDB 直接の操作は無いと思っていますが、メンテt時等使用する場合は排他で開く
DT.MDBのメンテ時以外は、APP1_入力.MDB、APP2_参照.MDBどちらも同時使用可能
APP2_参照.MDBでの最新DT表示は、最新DT取得ボタン等で表示
APP1_入力.MDB、APP2_参照.MDBはローカルPCで起動、DT.MDBは、ファイルサーバー上に置く
みたいな感じです

なので
入力.MDBでDT.MDBを開いた時に排他モードは、
APP2_参照.MDBから、DT_TABLEを参照出来なくなるため不適、
共有モードでJet データベース エンジンによるユーザー間の競合処理
が希望の操作ではないかと思えます

上記の方針で再度チャレンジしてみようと思います
取りあえずのご報告でした。

【11609】Re:MDBの分離 と レコード操作
発言  247b  - 10/4/15(木) 17:10 -

引用なし
パスワード
   こんにちは。

要件としてはこんな感じでしょうか。
・データ入力は入力.MDB、参照.MDB双方から行われる。
・入力.MDBの入力は30分程度の間、1人のみが作業可能。
・参照.MDBの入力は常時10人程度が作業可能。
・入力.MDBからの入力には排他制御が必要。
・参照.MDBからの入力には排他制御が必要。
・入力MDBと参照MDBで排他制御)の優先(入力作業の優先)はない。
・入力.MDBと参照.MDBはローカルPCに配置する。
・DT.MDBはサーバーに配置する。

なので、いわゆる排他制御が必要ということですね。
であれば、前回挙げておられたURLのプログラムソースが参考になると思います。

DT.MDBがサーバー配置になるなら、確かにリンクテーブルの使用は微妙なラインです。

レコードロックですが、Office2000以降だとできるんですね。
ページロックまでしかできない認識でした。すみません。
以下の資料を見つけました。
tp://msdn.microsoft.com/ja-jp/library/cc376645.aspx

【11627】Re:MDBの分離 と レコード操作
質問  pon  - 10/4/21(水) 18:27 -

引用なし
パスワード
   遅くなりました
247b さん ありがとうございます


>DT.MDBがサーバー配置になるなら、確かにリンクテーブルの使用は微妙なラインです。
なんですが
>>非連結にしましたが、
>>結局、フォームを開くとき、
>>コントロールのレコードソースを設定しているのでリンクテーブル有り同じことに
>>なっているのではと思っています
やはり、上記のような理解になってしまうのですが
別途何か注意事項等あればコメント頂けるとうれしいです
よろしくお願いいたします


>要件としてはこんな感じでしょうか。
ありがとうございます
勉強になります


>なので、いわゆる排他制御が必要ということですね。
>であれば、前回挙げておられたURLのプログラムソースが参考になると思います。

>><ADOを使ったレコード単位の排他ロックについて>
>>tp://www5f.biglobe.ne.jp/~f-lap/tips_adolock.htm
ですが、いまいち・・・?で

ページ レベル ロックとレコード レベル ロック
tp://msdn.microsoft.com/ja-jp/library/cc376645.aspx
ありがとうございます

等あたり他見ているうちに
VBA の Recordset オブジェクトで共有データをロックする
tp://msdn.microsoft.com/ja-jp/library/cc376533.aspx

排他モード
共有モード
レコードセット ロック
レコード レベル ロックまたはページ レベル ロック
のサンプルコードがありました

上記について一応動作させることだけは出来たのですが下記よくわかりません

アドバイス頂けると助かります
よろしくお願いいたします


レコードセット ロック DAOOpenTableExclusive
についてですが

DT.MDBが編集中で無ければ問題は無く、テーブル排他で開けましたが
DT.MDBの競合テーブルが編集中の場合(手動で開いて編集)
   Set rst = dbs.OpenRecordset(strRstSource, _
     dbOpenTable, dbDenyRead + dbDenyWrite)
でとまってしまいました
そこで下記のようにエラー処理を追加してみました

Call DAOOpenTableExclusive("\\hoge\DT.mdb","テーブル名")
で実行

Function DAOOpenTableExclusive(strDBPath As String, _
                strRstSource As String) As DAO.Recordset
  Dim dbs As DAO.Database
  Dim rst As DAO.Recordset
 
  Dim cnt As Integer '登録チャレンジ回数 
  cnt = 0

  On Error GoTo ErrorHandler

  ' DAOOpenDBShared を呼び出して
  ' データベースを共有モードで開きます。
  Set dbs = DAOOpenDBShared(strDBPath)

  ' データベースが共有モードで開いたことを確認します。
  ' 開いた場合、指定したテーブルを排他的に開きます。
 
  If Not dbs Is Nothing Then
   '※追記1
   'strRstSourceが開かれていると
   '実行時エラー '3262': テーブル 'DT' は、マシン 'huga' のユーザー 'Admin' によって使用されているので、ロックできませんでした。
   'で停止してしまう
   '↓ココでエラーで止まる!!
   Set rst = dbs.OpenRecordset(strRstSource, _
     dbOpenTable, dbDenyRead + dbDenyWrite)
   ' レコードセットが開いたことを確認します。開いた場合、
   ' Recordset オブジェクトを返します。開かなかった場合、Nothing を返します。
   If Not rst Is Nothing Then
     Set DAOOpenTableExclusive = rst  'レコードセット ロックで開いている
     ※追記2
     '追加しないと ldb.MDBが残る
     Set rst = Nothing
     Set dbs = Nothing
    
   Else
   
     Set DAOOpenTableExclusive = Nothing
     Set rst = Nothing
     Set dbs = Nothing
    
   End If
  Else
   'Set OpenTableExclusive = Nothing
    Set DAOOpenTableExclusive = Nothing
    Set rst = Nothing
    Set dbs = Nothing
  End If
 
 
Exit Function

ErrorHandler:
  If Err.Number = 3262 Then  
    'MsgBox "エラーです"
    'MsgBox "ターゲットテーブルは排他ONで使用中です"
    'MsgBox Err.Description 'テーブル 'DT' は、マシン 'hoge' のユーザー 'Admin' によって使用されているので、ロックできませんでした。
    '動作良好そう
    'ループかタイマで待機 駄目なら 時間を置いて と 思うが 動作的に 複数台のPCが ココでバッティングしたらどうなるのか自信がない
    '排他で開いていたら3回チャレンジして中止
     If cnt = 4 Then    
      Set rst = Nothing
      Set dbs = Nothing
      MsgBox "ファイルが使用中か不具合が発生している可能性があります 時間を置いて登録できないときは管理者に連絡してください"
      Exit Function      
     End If    
     cnt = cnt + 1    
  Else  
    MsgBox "エラー " & Err.Number & " _ " & Err.Description & " が発生しました"
    Set rst = Nothing
    Set dbs = Nothing
    Exit Function          
  End If 
  Resume 
End Function

Function DAOOpenDBShared(strDBPath As String) As DAO.Database
  ' このプロシージャには、Micrsoft DAO 3.6 オブジェクト ライブラリへの参照が
  ' 必要です。このプロシージャは、データベースを共有モードで開けるかどうかを
  ' 調べます。開けない場合は Nothing を返します。
  ' レコードセット ロックをインプリメントする場合、このプロシージャで
  ' データベースを共有モードで開くことができます。
  '
  ' 引数 :
  '  strDbPath : データベースへのパスです。
  '
  ' 戻り値 :
  '  共有モードで開かれているデータベースを参照する Database オブジェクトです。
  
  Dim dbs As DAO.Database

  On Error Resume Next
  ' データベースを開きます。
  Set dbs = DAO.OpenDatabase(strDBPath, False)
  
  ' エラーを確認します。
  If Err <> 0 Then
    MsgBox "Cannot open database in shared mode. " & _
      vbCr & Err.Description
    ' Nothing を返します。
    Set DAOOpenDBShared = Nothing
  Else
    ' データベースへの参照を返します。
    Set DAOOpenDBShared = dbs
  End If
End Function

Q1-1
上記で一応動作するのですが、エラー処理等自信がありません
添削、アドバイス等頂けるとうれしいです

Q1-2
下記レコード レベル ロックまたはページ レベル ロックの動作が理解しきれていないので
場合によってはこのコードでもいけそうな気がしています
多分、更新作業も瞬時だろうし、テーブル排他のため、データの競合も発生しないので
よさげな気がしますが、APP.MDBからのフォームの参照が切れてしまうような気がしますが
まだ試していません
この辺、駄目とかいけそうとかアドバイス頂けると助かります
よろしくお願いいたします


レコード レベル ロックまたはページ レベル ロック UpdateUnitsInStock
についてですが

アクセス付録のNwind.mdbをコピーして使用
サンプルコード内でNwind.mdbフルパス、テーブル名指定

Function UpdateUnitsInStock(strProduct As String, _
              intUnitsInStock As Integer, _
              intMaxTries As Integer) As Boolean

strProduct は Product Name 列で 商品選択
Units In Stock は 更新DT値 
intMaxTries は 回数 指定
CALL UpdateUnitsInStock("Chang","33","5")
で実行

Q2-1
うまく intMaxTries の動作を チェックすることが出来ません
intMaxTries の デバッグ を するにはどうすればいいでしょうか

Q2-2
別マシンでDT.MDBのProductsを開いていても
上記を実行すると数秒、別マシンのレコードが自動更新されて再表示されます

次に、別マシンでDT.MDBのProductsを開いて Units In Stock を 編集し
上記を実行し、別レコードに移動すると
データの競合 の ダイアログが表示され
"レコードの保存"、"クリップボードにコピー"、または "他のユーザーによる変更を反映"
のオプションが表示されます
これは
>><ADOを使ったレコード単位の排他ロックについて>
>>tp://www5f.biglobe.ne.jp/~f-lap/tips_adolock.htm
でも同じ動作になりした
別マシン側ででDT.MDBのProducts で 処理選択するか
レコード移動しなくてはいけない状況のように思われます

イメージ的には、
Function UpdateUnitsInStock
の動作の中で、編集中です とか 待機、ループで自動処理
できないものかと思っています
要領を得ない質問のような気がしますが、アドバイス頂けるとうれしいです
よろしくお願いいたします

Q3
MDB破損の話はよく見かけるのですが
今回のように、APP.MDB、DT.MDBを分離しても同じでしょうか
壊れる、運用可 のいろんな書き込みがあってよく理解できていません
実際にはどうなんでしょう?
アドバイスよろしくお願いいたします
(SQLサーバーについては、今後の目標にしています)

【11628】Re:MDBの分離 と レコード操作
発言  247b  - 10/4/22(木) 4:44 -

引用なし
パスワード
   ▼pon さん:
>遅くなりました
>247b さん ありがとうございます
>
>
>>DT.MDBがサーバー配置になるなら、確かにリンクテーブルの使用は微妙なラインです。
>なんですが
>>>非連結にしましたが、
>>>結局、フォームを開くとき、
>>>コントロールのレコードソースを設定しているのでリンクテーブル有り同じことに
>>>なっているのではと思っています
>やはり、上記のような理解になってしまうのですが
>別途何か注意事項等あればコメント頂けるとうれしいです
>よろしくお願いいたします

経験的(感覚的には)リンクテーブルの方が動作は遅いような気がします。
注意事項としては、Access2000時代の話なので大丈夫だと思いますが、レコードソースプロパティを直接変更するタイプのプログラムを作って、MDBファイルがクラッシュした経験があります。事象としては、実体は数件しかデータが無いのに、数百万件データがあると認識されてしまうというものです。
こうなると、そのMDBファイルは使い物になりません。
が、稀な事象のようなので、今後のこともあるので、念のための情報として挙げておきます。

>DT.MDBが編集中で無ければ問題は無く、テーブル排他で開けましたが
>DT.MDBの競合テーブルが編集中の場合(手動で開いて編集)
>   Set rst = dbs.OpenRecordset(strRstSource, _
>     dbOpenTable, dbDenyRead + dbDenyWrite)
>でとまってしまいました
>そこで下記のようにエラー処理を追加してみました
>
>Call DAOOpenTableExclusive("\\hoge\DT.mdb","テーブル名")
>で実行
>
>Function DAOOpenTableExclusive(strDBPath As String, _
>                strRstSource As String) As DAO.Recordset
>  Dim dbs As DAO.Database
>  Dim rst As DAO.Recordset
> 
>  Dim cnt As Integer '登録チャレンジ回数 
>  cnt = 0
>
>  On Error GoTo ErrorHandler
>
>  ' DAOOpenDBShared を呼び出して
>  ' データベースを共有モードで開きます。
>  Set dbs = DAOOpenDBShared(strDBPath)
>
>  ' データベースが共有モードで開いたことを確認します。
>  ' 開いた場合、指定したテーブルを排他的に開きます。
> 
>  If Not dbs Is Nothing Then
>   '※追記1
>   'strRstSourceが開かれていると
>   '実行時エラー '3262': テーブル 'DT' は、マシン 'huga' のユーザー 'Admin' によって使用されているので、ロックできませんでした。
>   'で停止してしまう
>   '↓ココでエラーで止まる!!
>   Set rst = dbs.OpenRecordset(strRstSource, _
>     dbOpenTable, dbDenyRead + dbDenyWrite)
>   ' レコードセットが開いたことを確認します。開いた場合、
>   ' Recordset オブジェクトを返します。開かなかった場合、Nothing を返します。
>   If Not rst Is Nothing Then
>     Set DAOOpenTableExclusive = rst  'レコードセット ロックで開いている
>     ※追記2
>     '追加しないと ldb.MDBが残る

Nothingにする前に念のためCloseしてください。

>     Set rst = Nothing
>     Set dbs = Nothing
>    
>   Else
>   
>     Set DAOOpenTableExclusive = Nothing
>     Set rst = Nothing
>     Set dbs = Nothing    
>   End If
>  Else
>   'Set OpenTableExclusive = Nothing
>    Set DAOOpenTableExclusive = Nothing
>    Set rst = Nothing
>    Set dbs = Nothing
他者のロックで開けなかった場合、ここに来るはずなので、
ユーザーに再度実行を促し、一旦処理終了する。
何回かリトライする
のいづれかの対処ができると思います。


>  End If
> 
> 
>Exit Function
>
>ErrorHandler:
>  If Err.Number = 3262 Then  
>    'MsgBox "エラーです"
>    'MsgBox "ターゲットテーブルは排他ONで使用中です"
>    'MsgBox Err.Description 'テーブル 'DT' は、マシン 'hoge' のユーザー 'Admin' によって使用されているので、ロックできませんでした。
>    '動作良好そう
>    'ループかタイマで待機 駄目なら 時間を置いて と 思うが 動作的に 複数台のPCが ココでバッティングしたらどうなるのか自信がない
>    '排他で開いていたら3回チャレンジして中止
>     If cnt = 4 Then    
>      Set rst = Nothing
>      Set dbs = Nothing

レコードセットとデータベースを片付ける場合は、If not rst Is Nothing Then
でオブジェクトが入っていることを確認した上で、Closeを呼び出した方が無難です。

>      MsgBox "ファイルが使用中か不具合が発生している可能性があります 時間を置いて登録できないときは管理者に連絡してください"
>      Exit Function      
>     End If    
>     cnt = cnt + 1 

Resumeはここにあるべきでは?
   
>  Else  
>    MsgBox "エラー " & Err.Number & " _ " & Err.Description & " が発生しました"
>    Set rst = Nothing
>    Set dbs = Nothing
>    Exit Function          
>  End If 
>  Resume 

ここに Resumeがあると、どんなエラーが発生しても実行再開してしまいますが、それで問題ないですか?

>End Function
>
>Function DAOOpenDBShared(strDBPath As String) As DAO.Database
>  ' このプロシージャには、Micrsoft DAO 3.6 オブジェクト ライブラリへの参照が
>  ' 必要です。このプロシージャは、データベースを共有モードで開けるかどうかを
>  ' 調べます。開けない場合は Nothing を返します。
>  ' レコードセット ロックをインプリメントする場合、このプロシージャで
>  ' データベースを共有モードで開くことができます。
>  '
>  ' 引数 :
>  '  strDbPath : データベースへのパスです。
>  '
>  ' 戻り値 :
>  '  共有モードで開かれているデータベースを参照する Database オブジェクトです。
>  
>  Dim dbs As DAO.Database
>
>  On Error Resume Next
>  ' データベースを開きます。
>  Set dbs = DAO.OpenDatabase(strDBPath, False)
>  
>  ' エラーを確認します。
>  If Err <> 0 Then
>    MsgBox "Cannot open database in shared mode. " & _
>      vbCr & Err.Description
>    ' Nothing を返します。
>    Set DAOOpenDBShared = Nothing
>  Else
>    ' データベースへの参照を返します。
>    Set DAOOpenDBShared = dbs
>  End If
>End Function
>
>Q1-1
>上記で一応動作するのですが、エラー処理等自信がありません
>添削、アドバイス等頂けるとうれしいです

インラインで追記しました。

>
>Q1-2
>下記レコード レベル ロックまたはページ レベル ロックの動作が理解しきれていないので
>場合によってはこのコードでもいけそうな気がしています
>多分、更新作業も瞬時だろうし、テーブル排他のため、データの競合も発生しないので
>よさげな気がしますが、APP.MDBからのフォームの参照が切れてしまうような気がしますが
>まだ試していません
>この辺、駄目とかいけそうとかアドバイス頂けると助かります
>よろしくお願いいたします

排他制御も最終的には、業務要件によってどれだけシビアなものが要求されるかが決まります。
業務上、更新作業がほとんど重ならない程度の頻度であれば、プログラムを作り込みすぎても
重武装になるだけでメンテナンスが大変になります。
レコードのロック制御
ロックの解除制御
他人にロックされた場合の対処方法(リトライするとか、メッセージを表示するとか。処理終了するタイミングなど)
が明確になっていて、且つ実装されていれば大丈夫ではないでしょうか。
その意味では、現在作っている処理を様々なパターンでテストしてみてはいかがでしょうか。
動いているところを見ていないので、なんとも言えない部分もあるのですが。

>
>レコード レベル ロックまたはページ レベル ロック UpdateUnitsInStock
>についてですが
>
>アクセス付録のNwind.mdbをコピーして使用
>サンプルコード内でNwind.mdbフルパス、テーブル名指定
>
>Function UpdateUnitsInStock(strProduct As String, _
>              intUnitsInStock As Integer, _
>              intMaxTries As Integer) As Boolean
>は
>strProduct は Product Name 列で 商品選択
>Units In Stock は 更新DT値 
>intMaxTries は 回数 指定
>CALL UpdateUnitsInStock("Chang","33","5")
>で実行
>
>Q2-1
>うまく intMaxTries の動作を チェックすることが出来ません
>intMaxTries の デバッグ を するにはどうすればいいでしょうか

CALL UpdateUnitsInStock("Chang","33","5")
の行を選択して、「F9」キーを押し、ブレークポイントを置きます。(茶色になる)
プログラムを実行すると、このブレークポイントで処理が止まるので、あとは
ステップインして、「F8」でステップ実行で動きを確認できます。
ステップインは、ツールバーの「デバッグ」にボタンがあります。
あと、UpdateUnitsInStockの第2、3引数は数値型なので、ダブルクォーテーションは不要です。

>
>Q2-2
>別マシンでDT.MDBのProductsを開いていても
>上記を実行すると数秒、別マシンのレコードが自動更新されて再表示されます
>
>次に、別マシンでDT.MDBのProductsを開いて Units In Stock を 編集し
>上記を実行し、別レコードに移動すると
>データの競合 の ダイアログが表示され
>"レコードの保存"、"クリップボードにコピー"、または "他のユーザーによる変更を反映"
>のオプションが表示されます
>これは
>>><ADOを使ったレコード単位の排他ロックについて>
>>>tp://www5f.biglobe.ne.jp/~f-lap/tips_adolock.htm
>でも同じ動作になりした
>別マシン側ででDT.MDBのProducts で 処理選択するか
>レコード移動しなくてはいけない状況のように思われます
>
>イメージ的には、
>Function UpdateUnitsInStock
>の動作の中で、編集中です とか 待機、ループで自動処理
>できないものかと思っています
>要領を得ない質問のような気がしますが、アドバイス頂けるとうれしいです
>よろしくお願いいたします

この質問が状況が読めないのですが、レコードセットにRequeryをかけたらうまくいきませんか?


>
>Q3
>MDB破損の話はよく見かけるのですが
>今回のように、APP.MDB、DT.MDBを分離しても同じでしょうか
>壊れる、運用可 のいろんな書き込みがあってよく理解できていません
>実際にはどうなんでしょう?
>アドバイスよろしくお願いいたします
>(SQLサーバーについては、今後の目標にしています)

経験的な情報なので、確実ではないと思いますが、データベースの最適化を頻度高く行うと長持ちするように思います。このシステムの場合、特にDT.MDBの方が必要です。
また、残念ながら、MDBファイルは壊れるもの、という前提で運用する方が無難なので、バックアップ運用をすることが望ましいと思います。これも業務要件によるのですが、3〜5日分のバックアップを持っておけば、いざ壊れても復旧はしやすいはずです。

【11631】Re:MDBの分離 と レコード操作
発言  pon  - 10/4/22(木) 16:13 -

引用なし
パスワード
   247b さん お手数かけます
わかり難い書込みのなか、回答ありがとうございます

10000文字超えのため、2度に分けました

>>DT.MDBがサーバー配置になるなら、確かにリンクテーブルの使用は微妙なラインです
詳細な説明ありがとうございます
勉強になります


Q1-1
添削頂きありがとうございます
サンプルコードが完全には理解出来ていないため
ldbが残りそうなところに
  Set rst = Nothing
  Set dbs = Nothing
を設けました

>レコードセットとデータベースを片付ける場合は、If not rst Is Nothing Then
>でオブジェクトが入っていることを確認した上で、Closeを呼び出した方が無難です。
了解です
上記
  If Not rst Is Nothing Then
    rst.Close
    Set rst = Nothing
  End If
  dbs.Close
  Set dbs = Nothing
に置き換えました

>ここに Resumeがあると、どんなエラーが発生しても実行再開してしまいますが、
>それで問題ないですか?
了解です
ありがとうございました


VBA の Recordset オブジェクトで共有データをロックする
tp://msdn.microsoft.com/ja-jp/library/cc376533.aspx

エラーのチェック
なんてありましたが、なかなか難しいです

>他者のロックで開けなかった場合、ここに来るはずなので、
>ユーザーに再度実行を促し、一旦処理終了する。
>何回かリトライする
>のいづれかの対処ができると思います。

これなんですが
下記コードに記載しましたが
    'ここは、
    'dbs Is Nothing の時 ・・・・では?
と思いますが・・・
 のでここには排他エラーが無いような気がしますが違っていますか?
(手動で開いて編集中、また、
別APP.MDBでSet DAOOpenTableExclusive = rst 中 共、どちらも同じで
   '↓ココでエラーで止まる!!
   Set rst = dbs.OpenRecordset(strRstSource, _
     dbOpenTable, dbDenyRead + dbDenyWrite)
となってしまいました
但し、どちらも先行命令が完了すれば、後攻命令も問題なく完了します)


>排他制御も最終的には、業務要件によってどれだけシビアなものが要求されるかが決まります。
勉強になります
ありがとうございます

>その意味では、現在作っている処理を様々なパターンでテストしてみてはいかがでしょうか。
この辺の対応どのようにして作りこむのか良くわかりません・・・難しいです・・
配布後、苦情の嵐とかに遭遇しそうな・・・・

DAOのロック系のエラーを調べてみたのですが
どのエラーが
>他者のロックで開けなかった場合、ここに来るはずなので、
となるのかわからなかったので

DAOのエラー定数一覧
tp://homepage2.nifty.com/Dee/vb/tips/daoerrorlist.html
(MSサイトでは見つけられませんでした)

エラー番号    エラーメッセージ
3006    データベース <データベース名> は排他ロックされています。
3008    テーブル <テーブル名> は排他ロックされています。
3009    テーブル <テーブル名> は現在使用されているため、ロックできませんでした。
3046    他のユーザーによってロックされているため、保存できませんでした。
3158    他のユーザーによってロックされているため、レコードは保存できませんでした。
3186    マシン <マシン名> のユーザー <ユーザー名> によってロックされているため、保存できませんでした。
3187    マシン <マシン名> のユーザー <ユーザー名> によってロックされているため、読み取れませんでした。
3188    このマシンの他のセッションによってロックされているため、更新できませんでした。
3189    テーブル <テーブル名> は、マシン <マシン名> のユーザー <ユーザー名> によって排他ロックされています。
3202    他のユーザーによってロックされているため、保存できませんでした。
3211    テーブル <テーブル名> は現在使用されているため、ロックできませんでした。
3212    テーブル <テーブル名> は、マシン <マシン名> のユーザー <ユーザー名> によって使用されているため、ロックできませんでした。
3218    ロックされているため、更新できませんでした。
3260    マシン <マシン名> のユーザー <ユーザー名> によってロックされているため、更新できませんでした。
3261    テーブル <テーブル名> は、マシン <マシン名> のユーザー <ユーザー名> によって排他ロックされています。
3262    テーブル <テーブル名> は、マシン <マシン名> のユーザー <ユーザー名> によって使用されているため、ロックできませんでした。

をエラー処理の対象にしてしまえばいいかなと組み込んでしまいました・・・
邪道みたいな気もするのですが・・・・
遭遇するエラーは何とか処理の記載は出来る気もするのですが・・・
未遭遇のもの、特に今回の場合??です
というわけでこんなハズカシコードになってしまいました (~_~;)
何かアドバイス有りましたらよろしくお願い致します

修正コード

Function DAOOpenTableExclusive(strDBPath As String, _
                strRstSource As String) As DAO.Recordset
  Dim dbs As DAO.Database
  Dim rst As DAO.Recordset 
  Dim cnt As Integer '登録チャレンジ回数
 
  cnt = 0
  On Error GoTo ErrorHandler

  ' DAOOpenDBShared を呼び出して
  ' データベースを共有モードで開きます。
  Set dbs = DAOOpenDBShared(strDBPath)

  ' データベースが共有モードで開いたことを確認します。
  ' 開いた場合、指定したテーブルを排他的に開きます。
 
  If Not dbs Is Nothing Then 
   'strRstSourceが開かれていると
   '実行時エラー '3262': テーブル 'DT02_PJ_DT' は、マシン 'K000040827' のユーザー 'Admin' によって使用されているので、ロックできませんでした。
   'で停止してしまう
   'DAOOpenTableExclusive2で、エラー処理組み込みテスト
   '↓ココでエラーで止まる!!
   Set rst = dbs.OpenRecordset(strRstSource, _
     dbOpenTable, dbDenyRead + dbDenyWrite)
   ' レコードセットが開いたことを確認します。開いた場合、
   ' Recordset オブジェクトを返します。開かなかった場合、Nothing を返します。
   If Not rst Is Nothing Then
     Set DAOOpenTableExclusive = rst  'レコードセット ロックで開いている
    
     '追加しないと ldb.MDBが残る
     '更新処理!!
    
     If Not rst Is Nothing Then
      rst.Close
      Set rst = Nothing
     End If
     dbs.Close
     Set dbs = Nothing    
     MsgBox "登録完了"
    
   Else   
     Set DAOOpenTableExclusive = Nothing    
     'ldbが残るとやなので、下記Nothingしています!!!!!    
     If Not rst Is Nothing Then
      rst.Close
      Set rst = Nothing
     End If
     dbs.Close
     Set dbs = Nothing    
   End If
  Else
 
    '他者のロックで開けなかった場合、ここに来るはずなので、
    'ユーザーに再度実行を促し、一旦処理終了する。
    '何回かリトライする
    'のいづれかの対処ができると思います。
 
          ’ここは、
          ’dbs Is Nothing の時 ・・・・
 
 
   'Set OpenTableExclusive = Nothing
    Set DAOOpenTableExclusive = Nothing    
    
     If Not rst Is Nothing Then
      rst.Close
      Set rst = Nothing
     End If
     dbs.Close
     Set dbs = Nothing
    
  End If
 
 
Exit Function
ErrorHandler:


  'If Err.Number = 3262 Then
  Select Case Err.Number
  
    Case 3006, 3008, 3009, 3046, 3158, 3186, 3187, 3188, 3189, 3202, 3211, 3212, 3218, 3260, 3261, 3262
  
      'MsgBox "エラーです"
      'MsgBox "ターゲットテーブルは排他ONで使用中です"
      'MsgBox Err.Description 'テーブル 'DT02_PJ_DT' は、マシン 'K000040827' のユーザー 'Admin' によって使用されているので、ロックできませんでした。
      '動作良好そう
      'ループかタイマで待機 駄目なら 時間を置いて と 思うが 動作的に 複数台のPCが ココでバッティングしたらどうなるのか自信がない
          
       '排他で開いていたら3回チャレンジして中止
       If cnt = 4 Then
      
        '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        'レコードセットとデータベースを片付ける場合は、If not rst Is Nothing Then
        'でオブジェクトが入っていることを確認した上で、Closeを呼び出した方が無難です。
        '----------------------------------------------------
      
        If Not rst Is Nothing Then
          rst.Close
          Set rst = Nothing
        End If
        dbs.Close
        Set dbs = Nothing
        
        MsgBox "ファイルが使用中か不具合が発生している可能性があります 時間を置いて登録できないときは管理者に連絡してください"
        
        
        Exit Function
        
       End If
      
       cnt = cnt + 1
      
      '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      'Resumeはここにあるべきでは?
      '----------------------------------------------------
      Resume
      
      '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      
    'Else
    Case Else
    
      MsgBox "エラー " & Err.Number & "" & Err.Description & " が発生しました"
      
       If Not rst Is Nothing Then
        rst.Close
        Set rst = Nothing
       End If
       dbs.Close
       Set dbs = Nothing
      
      Exit Function
            
  'End If
  End Select
 
  'Resume
 
End Function


Function DAOOpenDBShared(strDBPath As String) As DAO.Database
  ' このプロシージャには、Micrsoft DAO 3.6 オブジェクト ライブラリへの参照が
  ' 必要です。このプロシージャは、データベースを共有モードで開けるかどうかを
  ' 調べます。開けない場合は Nothing を返します。
  ' レコードセット ロックをインプリメントする場合、このプロシージャで
  ' データベースを共有モードで開くことができます。
  '
  ' 引数 :
  '  strDbPath : データベースへのパスです。
  '
  ' 戻り値 :
  '  共有モードで開かれているデータベースを参照する Database オブジェクトです。
  
  Dim dbs As DAO.Database

  On Error Resume Next
  ' データベースを開きます。
  Set dbs = DAO.OpenDatabase(strDBPath, False)
  
  ' エラーを確認します。
  If Err <> 0 Then
    MsgBox "Cannot open database in shared mode. " & _
      vbCr & Err.Description
    ' Nothing を返します。
    Set DAOOpenDBShared = Nothing
  Else
    ' データベースへの参照を返します。
    Set DAOOpenDBShared = dbs
  End If
End Function


今回は、取合えずテーブルロックで大丈夫そうな気がするのと
レコードレベルでの操作は荷が過ぎそうなので
テーブルロックで進めてみようと思います

【11632】Re:MDBの分離 と レコード操作
発言  pon  - 10/4/22(木) 16:13 -

引用なし
パスワード
   続きです


>>Q2-1
>CALL UpdateUnitsInStock("Chang","33","5")
>の行を選択して、「F9」キーを押し、ブレークポイントを置きます。(茶色になる)
ありがとうございます
この辺の操作は、通常デバッグツールバーで操作できています

>うまく intMaxTries の動作を チェックすることが出来ません
今日、下記のようにして動作確認することが出来ました

PC1号機で、サーバー上のDT.MDB(NWIND.MDB)を開いておいて
PC2号機で
APP1.MDB と それをコピーしたAPP2.MDB を 両方とも開いておきます
APP1.MDB 、 APP2.MDB 各のモジュール共

   .Update ←ここにブレークポイント設定
   UpdateUnitsInStock = True

APP1.MDBで
call UpdateUnitsInStock("Chang",11,5)
を実行
APP2.MDBで
call UpdateUnitsInStock("Chang",22,5)
を実行

で、APP1.MDBを先行しブレークポイントで停止、
APP2.MDBを後攻で実行し、APP1を追い越して実行すると
エラー処理の動作を確認することが出来ました
ただ、動作の理解がまだなのでもう少し試してみたいと思います
こちらのレコードロックについても出来れば理解したいと思っています


>また、残念ながら、MDBファイルは壊れるもの、という前提で運用する方が無難なので>、バックアップ運用をすることが望ましいと思います。これも業務要件によるのです
>が、3〜5日分のバックアップを持っておけば、いざ壊れても復旧はしやすいはずです。
詳細な解説ありがとうございました
了解です

次の書込みは来週終わりになってしまうと思います
完成報告か、続けてQになってしまうかわかりませんが・・・・

今回の追加Qについて何か有りましたらコメント頂けると嬉しいです
よろしくお願い致します

【11638】Re:MDBの分離 と レコード操作
発言  247b  - 10/4/23(金) 20:18 -

引用なし
パスワード
   >これなんですが
>下記コードに記載しましたが
>    'ここは、
>    'dbs Is Nothing の時 ・・・・では?
> と思いますが・・・
> のでここには排他エラーが無いような気がしますが違っていますか?
そうですね、DAOOpenDBSharedの戻り値がNothingの時はつまり誰かが排他モードでDT.DBを開いていると考えたのですが、そもそも排他では誰も開かない仕様ですね。すみません。

>>その意味では、現在作っている処理を様々なパターンでテストしてみてはいかがでしょうか。
>この辺の対応どのようにして作りこむのか良くわかりません・・・難しいです・・
>配布後、苦情の嵐とかに遭遇しそうな・・・・
とりあえず、2つのPCを使って、どなたかに協力いただいて、一方が先に更新、もう一方が後に更新などの動作チェックをしてみるだけでも安心感が増すと思います。さらにできれば負荷テストとして5〜6人で一気に更新してみるというのも有りだと思います。一応、参考まで

>で
>DAOのロック系のエラーを調べてみたのですが
>どのエラーが
>>他者のロックで開けなかった場合、ここに来るはずなので、
>となるのかわからなかったので

出典は忘れましたが、ありうるエラーを想定してそれに対処する方策を攻撃的エラートラップといいます。ですので、方策としては問題ないと思います。

456 / 2272 ツリー ←次へ | 前へ→
ページ:  ┃  記事番号:
1078193
(SS)C-BOARD v3.8 is Free