Почему моя база данных Access не обновляется, когда я читаю ее из другого процесса?

В своем приложении я делаю следующее:

  1. Откройте базу данных Access (.mdb) с помощью Jet / ADO и VB6
  2. Очистить и заново заполнить таблицу новыми данными
  3. Закройте базу данных
  4. Запустите другой процесс, который что-то делает с новыми данными.

Проблема в том, что иногда второй процесс не может найти новые данные. Иногда таблица просто пуста, иногда RecordCount> 0, но EOF истинно, и я не могу выполнить MoveFirst или MoveNext. В двух словах: всякие странности.

Мой текущий обходной путь - добавить задержку между закрытием базы данных и запуском второго процесса.

  • Что здесь происходит?
  • Могу я что-нибудь с этим поделать? (Помимо использования другой базы данных)

person Daniel Rikowski    schedule 28.01.2009    source источник


Ответы (3)


Просто предположение, но я могу быть из-за того, что движок Jet имеет кеш чтения и ленивую запись:

Как реализовать многопользовательские настраиваемые счетчики в Jet 4.0 и ADO 2.1

«Microsoft Jet имеет кэш чтения, который обновляется каждые миллисекунды PageTimeout (по умолчанию 5000 мс = 5 секунд). Он также имеет механизм отложенной записи, который работает в отдельном потоке от основной обработки и, таким образом, записывает изменения на диск асинхронно. Эти два механизмы помогают повысить производительность, но в определенных ситуациях, требующих высокой степени параллелизма, они могут создать проблемы ».

В статье предлагается использовать метод Jet RefreshCache и установить для Jet OLEDB: Transaction Commit Mode значение 1 миллисекунда (одно из преимуществ ADO над DAO для Jet состоит в том, что вы можете изменить этот параметр, не изменяя значение в реестре).

P.S. вам следует подумать о редактировании базы данных Access (.mdb), чтобы вместо этого упоминать 'Jet' и использовать тег 'Jet', иначе вы получите комментарий от определенного пользователя SO, который привередлив в этих вещах :)

person onedaywhen    schedule 28.01.2009
comment
ммххх ..... Думаю, я знаю этого парня .... Однажды, когда будет правильно: будь осторожен, а то тебя выпороть ... - person Philippe Grondier; 28.01.2009
comment
Возможно, вы устанавливаете состояние гонки с настройкой в ​​1 миллисекунду? Назовите меня параноиком (и нескромным!), Но ИМХО мой ответ лучше. - person MarkJ; 28.01.2009
comment
Я имел в виду JET. JET был хорош в свое время. Я проделал много работы с VB6 / JET, но VB6 / SQL Express работает одинаково хорошо, особенно теперь, когда вы можете определять динамическое присоединение в строке подключения. - person AnthonyWJones; 29.01.2009

В этой статье базы знаний Microsoft объясняется, как это сделать.

Вот отрывок с образцом кода. Код использует два соединения от одного процесса, поэтому вам нужно перетащить считывающую часть во второй процесс.

  1. Писатель должен начать транзакцию с помощью ADO Connection.BeginTrans до записи данных.
  2. Писатель должен выполнить обновления базы данных, а затем зафиксировать транзакцию (используя ADO Connection.CommitTrans).
  3. Читатель должен вызвать JRO.JetEngine.RefreshCache, передавая его в соединение, прежде чем пытаться прочитать данные.

Обратите внимание, что JRO.JetEngine включается путем добавления ссылки на Microsoft Jet And Replication Objects 2.1 Library в ваш проект VB.

    Sub SyncReadDemo()
    Dim conn1 As New ADODB.Connection
    Dim conn2 As New ADODB.Connection
    Dim rs As New ADODB.recordset
    Dim JRO As New JRO.JetEngine
    Dim strConnect As String
    Dim i As Long


  ' Set up our connection string (requires a database named c:\db1.mdb).
    strConnect = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\db1.mdb"

    ' Open connection 1 and drop and re-create test table.
    conn1.CursorLocation = adUseServer
    conn1.Open strConnect
    On Error Resume Next
    conn1.Execute "drop table tmpTest", , _
        adExecuteNoRecords + adCmdText
    On Error GoTo 0
    conn1.Execute "create table tmpTest (id long)", , _
        adExecuteNoRecords + adCmdText

    ' Close connection 1 to flush the creation of table tmpTest. 
    conn1.Close

    ' Now open connection 1 and connection 2.
    conn1.Open strConnect
    conn2.Open strConnect

    ' Insert 10 records using connection 1.
    ' Note we must perform all writes inside of a transaction.
    conn1.BeginTrans
    For i = 1 To 10
        conn1.Execute "insert into tmpTest (id) values (1)", , _
            adExecuteNoRecords + adCmdText
    Next i
    conn1.CommitTrans

    ' Refresh cache for reader connection.
    JRO.RefreshCache conn2
    Set rs = conn2.Execute("select * from tmpTest", , adCmdText)

    ' Count records in our table (should be 10).
    i = 0
    While Not rs.EOF
        i = i + 1
        rs.MoveNext
    Wend
    rs.Close

    MsgBox "Read " & i & " records using different connections."

    conn1.Close
    conn2.Close

End Sub
person MarkJ    schedule 28.01.2009
comment
+1 за то, что хвастался, что твоя ссылка на статью MS лучше моей :) - person onedaywhen; 29.01.2009

Поскольку первый процесс - единственный процесс с открытым MDB, он может быть немного ленив при записи материала обратно в файл. Даже после того, как вы завершите процесс, может возникнуть задержка, пока ОС записывает невыполненные страницы, и это может произойти после того, как процесс сигнализирует о своем завершении.

Я бы порекомендовал прекратить использование Access, а вместо этого использовать SQL Server 2008 Express.

person AnthonyWJones    schedule 28.01.2009
comment
-1 В данном случае это ужасный совет и почти никогда не поможет ни в каком другом случае. - person David-W-Fenton; 28.01.2009