
エクセルVBAで、アクセスファイルとデータをやりとりするシステムを作成して使用しています。
このシステムで、使用開始1年ほどでエラーが出るようになり、何となく解決したのですがこれでよかったのか、エラーの理由はなんだったと考えられるのか、本来行うべきだった解決法は他にあるのか、等を質問させてください。
以下のように、アクセスファイルとの接続部分だけ別プロシージャとして作成しています。
Public gCON As ADODB.Connection 'アクセスファイルとの接続 Public Function DbOpen() As Long On Error GoTo DbOpen_e Dim sConStr As String sConStr = "Provider =Microsoft.ACE.OLEDB.12.0;Data Source = C:\データ.accdb" If gCON Is Nothing Then Set gCON = New ADODB.Connection gCON.Open sConStr End If Exit Function DbOpen_e: DbOpen = ERR.Number MsgBox "[" & ERR.Number & "]" & ERR.Description Call DbDispose End Function '接続解除 Public Sub DbClose() If Not gCON Is Nothing Then On Error Resume Next gCON.Close End If Call DbDispose End Sub Public Sub DbDispose() If Not gCON Is Nothing Then Set gCON = Nothing End If End Sub
実際にデータファイルと接続してデータを取得したり編集する場面は以下のようなものです。
Public Sub DataEdit() On Error GoTo ERR Dim rsC As New ADODB.Recordset, strQ As String Dim ws As Worksheet,RowCnt As Long, tgtId As Long Set ws = ThisWorkbook.Worksheets("リスト") 'Accessデータベースに接続 call DbOpen RowCnt = 2 Do tgtId = ws.Cells(RowCnt, 1) 'RSCと接続 strQ = "SELECT * FROM tblBasic WHERE 顧客ID = " & tgtId 'テーブルを取得 rsC.Open strQ, gCON, adOpenKeyset, adLockOptimistic If Not ((rsC.EOF) And (rsC.BOF)) Then ws.Cells(RowCnt, 3) = rsC.Fields("名前") End If Set rsC = Nothing RowCnt = RowCnt + 1 If RowCnt > 1000 Then Exit Do Loop If Not (rsC Is Nothing) Then Set rsC = Nothing End If Call DbClose Exit Sub ERR: If Not (rsC Is Nothing) Then Set rsC = Nothing End If Call DbClose Application.Cursor = xlDefault MsgBox ERR.Description End Sub
このようなコードなのですが、使用開始後1年くらいの頃、急にエラーがでるようになりました。
決まって206行目でテーブルの取得(rsC.Open)ができなくなるんです。
SQLの内容(tgtIDの番号)が何番であろうと変わらずループ206番目でだめになります。
そこで、いろいろ試すうちに、何の根拠もなくただの勘で、データセットを取得するたびにその前にdbOpenを実行し、データセットをNothingにするたびにその直後にDbCloseを実行するようにしたところ、問題が発生しなくなりました。
教えていただきたいのですが、そもそも、これは解決法として妥当だったのでしょうか?
こういう場合、ループ内で毎回データファイルとの接続と解除を行うべきなのでしょうか?
接続はそのままでデータセットの取得と放棄だけを繰り返すのは何か問題なのでしょうか?
追記
iruyas様、enii様から、adLockOptimisticの使い方に問題があるのではないか、というご指摘がありました。
たしかに私は、この、レコードセットの取得方法について何も考えずにコピペしたコードですませていたのですが、今回のエラーの原因がこの取得タイプの間違いによるものであるのかどうか、まだ理解しきれていません。
私が作ったコードのながれは、
- (1)データベースファイルと接続する
- (2)接続したデータベースから、SQLを発行してレコードセットを取得する(adLockOptimistic指定)
- (3)取得したレコードセットからフィールドの値を取り出してセルに書き出す
- (4)レコードセットを手放す(set RS = nothing)
- (5)データベースファイルとの接続を切断する
という流れのなかで、(2)から(4)をループさせていました。
これがうまくいかなくなって(1)から(5)までをループさせたらうまくいったという状態です。
「一度に持てるデータの量は決まっている。無駄にデータを持たせないように、ReadOnlyでいいのかLockしかないのか考えるべき」というご指摘でしたが、
私としては、レコードセットを1ループごとに取得してはすぐ解放してるのだから、1度に持っているデータは1レコードセット分だけなのに、と考えてしまいます。
取得したレコードセットからひとつフィールドの値をもらったらすぐにそのレコードセットを手放してるつもりなのですが、そうなってはない=つまり(4)でレコードセットを手放しているつもりでも、実は何かが手元に残っているということでしょうか?元のデータベースとの接続じたいを一旦切ってしまうか、あるいはReadOnlyで取得したレコードセットならちゃんと手から離れてくれる、ということなのでしょうか?



回答1件
あなたの回答
tips
プレビュー