Ответ 1
Я думаю, я не могу объяснить, почему некоторые ваши "обновления скриптов" не всегда срабатывают. Это странное поведение, которое иногда происходит, а иногда и нет. Я не могу увидеть весь ваш script, но я могу показать вам, как я принял ваш код и сделал его работу каждый раз.
Примечание: ваш вопрос каким-то образом связан с ExecuteComplete Событие подключения ADODB, не запущенное с помощью параметра adAsyncExecute
Я добавил 3 хранимых процедуры на моем SQL-сервере; sp_WaitFor5
, sp_WaitFor10
, sp_WaitFor20
, чтобы имитировать задержку времени выполнения запроса.
Проще, чем
CREATE PROCEDURE sp_WaitFor5
AS
WAITFOR DELAY '00:00:05'
для всех 3 задержек.
Затем в моем Module1
я добавил очень простой код для вызова пользовательского класса
Option Explicit
Private clsTest As TestEvents
Sub Main()
Cells.ClearContents
Set clsTest = New TestEvents
Call clsTest.StartingPoint
End Sub
Затем я переименовал модуль класса в TestEvents
и добавил немного измененную версию вашего кода
Option Explicit
Private WithEvents cnA As ADODB.Connection
Private WithEvents cnB As ADODB.Connection
Private WithEvents cnC As ADODB.Connection
Private i as Long
Public Sub StartingPoint()
Dim connectionString As String: connectionString = "Driver={SQL Server};Server=MYSERVER\INST; UID=username; PWD=password!"
Debug.Print "Firing cnA query(10 sec): " & Now
Set cnA = New ADODB.Connection
cnA.connectionString = connectionString
cnA.Open
cnA.Execute "sp_WaitFor10", adExecuteNoRecords, adAsyncExecute
Debug.Print "Firing cnB query(5 sec): " & Now
Set cnB = New ADODB.Connection
cnB.connectionString = connectionString
cnB.Open
cnB.Execute "sp_WaitFor5", adExecuteNoRecords, adAsyncExecute
Debug.Print "Firing cnC query(20 sec): " & Now
Set cnC = New ADODB.Connection
cnC.connectionString = connectionString
cnC.Open
cnC.Execute "sp_WaitFor20", adExecuteNoRecords, adAsyncExecute
End Sub
Private Sub cnA_ExecuteComplete(ByVal RecordsAffected As Long, ByVal pError As ADODB.Error, adStatus As ADODB.EventStatusEnum, ByVal pCommand As ADODB.Command, ByVal pRecordset As ADODB.Recordset, ByVal pConnection As ADODB.Connection)
Debug.Print vbTab & "cnA_executeComplete START", Now
For i = 1 To 55
Range("A" & i) = Rnd(1)
Next i
Debug.Print vbTab & "cnA_executeComplete ENDED", Now
End Sub
Private Sub cnB_ExecuteComplete(ByVal RecordsAffected As Long, ByVal pError As ADODB.Error, adStatus As ADODB.EventStatusEnum, ByVal pCommand As ADODB.Command, ByVal pRecordset As ADODB.Recordset, ByVal pConnection As ADODB.Connection)
Debug.Print vbTab & "cnB_executeComplete START", Now
For i = 1 To 1000000
Range("B" & i) = Rnd(1)
Next i
Debug.Print vbTab & "cnB_executeComplete ENDED", Now
End Sub
Private Sub cnC_ExecuteComplete(ByVal RecordsAffected As Long, ByVal pError As ADODB.Error, adStatus As ADODB.EventStatusEnum, ByVal pCommand As ADODB.Command, ByVal pRecordset As ADODB.Recordset, ByVal pConnection As ADODB.Connection)
Debug.Print vbTab & "cnC_executeComplete START", Now
For i = 1 To 55
Range("C" & i) = Rnd(1)
Next i
Debug.Print vbTab & "cnC_executeComplete ENDED", Now
End Sub
Я не сильно изменился, кроме дополнительного параметра для Execute
и некоторого кода, который заполняет activesheet только для того, чтобы уделить время.
Теперь я могу запускать различные варианты/конфигурации. Я могу повернуть время выполнения для объектов соединения. Я могу иметь cnA
5 сек, cnB
10сек, cnC
20 сек. Я могу менять/корректировать время выполнения для каждого из событий _ExecuteComplete
.
От тестирования самостоятельно могу заверить, что все 3 выполняются всегда.
Здесь некоторые журналы основаны на конфигурации, похожей на вашу
Firing cnA query(10 sec): 24/02/2014 12:59:46
Firing cnB query(5 sec): 24/02/2014 12:59:46
Firing cnC query(20 sec): 24/02/2014 12:59:46
cnB_executeComplete START 24/02/2014 12:59:51
cnB_executeComplete ENDED 24/02/2014 13:00:21
cnA_executeComplete START 24/02/2014 13:00:21
cnA_executeComplete ENDED 24/02/2014 13:00:21
cnC_executeComplete START 24/02/2014 13:00:22
cnC_executeComplete ENDED 24/02/2014 13:00:22
В приведенном выше примере, как вы можете видеть, все 3 запроса запускаются асинхронно.
cnA
возвращает дескриптор через 5 секунд, что делает cnB
первым, у которого есть событие ('refresh script'), запускается в иерархии, поскольку cnC
занимает самое длинное.
Так как cnB
возвращается первым, он запускает процедуру cnB_ExecuteComplete
события. cnB_ExecuteComplete
сам он должен выполнить некоторое время выполнения (итерации 1 миллион раз и заполняет столбец B случайными числами. Примечание: cnA заполняет столбец A, cnB col B, cnC col C). Глядя на приведенный выше журнал, требуется ровно 30 секунд.
Пока cnB_ExecuteComplete
выполняет свою работу/занимает ресурсы (и, как вы знаете, VBA однопоточно), событие cnA_ExecuteComplete
добавляется в очередь процессов TODO. Таким образом, вы можете думать об этом как о очереди. В то время как кое-что позаботится о следующем, нужно просто ждать своей очереди в конце.
Если я изменю конфигурацию; cnA
5 секунд, cnB
10 секунд, cnC
20 секунд и каждый из "сценариев обновления" повторяется 1 миллион раз, а затем
Firing cnA query(5 sec): 24/02/2014 13:17:10
Firing cnB query(10 sec): 24/02/2014 13:17:10
Firing cnC query(20 sec): 24/02/2014 13:17:10
one million iterations each
cnA_executeComplete START 24/02/2014 13:17:15
cnA_executeComplete ENDED 24/02/2014 13:17:45
cnB_executeComplete START 24/02/2014 13:17:45
cnB_executeComplete ENDED 24/02/2014 13:18:14
cnC_executeComplete START 24/02/2014 13:18:14
cnC_executeComplete ENDED 24/02/2014 13:18:44
Явно доказал свою точку зрения из первого примера.
Кроме того, с помощью cnA
5 секунд, cnB
5 секунд, cnC
5 секунд
Firing cnA query(5 sec): 24/02/2014 13:20:56
Firing cnB query(5 sec): 24/02/2014 13:20:56
Firing cnC query(5 sec): 24/02/2014 13:20:56
one million iterations each
cnB_executeComplete START 24/02/2014 13:21:01
cnB_executeComplete ENDED 24/02/2014 13:21:31
cnA_executeComplete START 24/02/2014 13:21:31
cnA_executeComplete ENDED 24/02/2014 13:22:01
cnC_executeComplete START 24/02/2014 13:22:01
cnC_executeComplete ENDED 24/02/2014 13:22:31
Что также завершает/выполняет все 3.
Как я уже сказал, я не вижу весь ваш код, возможно, у вас есть необработанная ошибка где-то в вашем коде, возможно, что-то вводит вас в заблуждение, думая, что один _ExecuteComplete
не выполняется вообще. Попытайтесь внести изменения в свой код, чтобы отразить то, что я вам дал, и запустить еще один текст самостоятельно. Я буду с нетерпением ждать ваших отзывов.