尝试通过 ADODB/SQLiteODBC 更改 SQLite 数据库的日志模式时,Excel/VBA 挂起
Posted
技术标签:
【中文标题】尝试通过 ADODB/SQLiteODBC 更改 SQLite 数据库的日志模式时,Excel/VBA 挂起【英文标题】:Excel/VBA hangs when trying to change journal mode of an SQLite database via ADODB/SQLiteODBC 【发布时间】:2022-01-12 16:17:24 【问题描述】:下面的代码在 Temp 文件夹中创建一个新的空白 SQLite 数据库,创建一个表,填充它,然后暂停。然后在DB Browser for SQLite中交互式地打开数据库,并更改一个值,但未提交更改。恢复执行,Excel/VBA 挂起约 1.5 分钟,然后在尝试通过 ADODB/SQLiteODBC 更改日志模式时引发“数据库已锁定”错误。
为了澄清,此代码专门用于重现问题。很清楚为什么会引发错误。问题在于所需的等待时间。
Private Sub ConnectSQLiteAdoCommandSource()
Dim Driver As String
Driver = "SQLite3 ODBC Driver"
Dim Database As String
Database = Environ("Temp") & "\" & CStr(Format(Now, "yyyy-mm-dd_hh-mm-ss.")) _
& CStr((Timer * 10000) Mod 10000) & CStr(Round(Rnd * 10000, 0)) & ".db"
Debug.Print Database
Dim Options As String
Options = "JournalMode=DELETE;SyncPragma=NORMAL;FKSupport=True;"
Dim AdoConnStr As String
AdoConnStr = "Driver=" & Driver & ";" & "Database=" & Database & ";" & Options
Dim SQLQuery As String
Dim RecordsAffected As Long
Dim AdoCommand As ADODB.Command
Set AdoCommand = New ADODB.Command
With AdoCommand
.CommandType = adCmdText
.ActiveConnection = AdoConnStr
.ActiveConnection.CursorLocation = adUseClient
End With
'''' ===== Create Functions table ===== ''''
SQLQuery = Join(Array( _
"CREATE TABLE functions(", _
" name TEXT COLLATE NOCASE NOT NULL,", _
" builtin INTEGER NOT NULL,", _
" type TEXT COLLATE NOCASE NOT NULL,", _
" enc TEXT COLLATE NOCASE NOT NULL,", _
" narg INTEGER NOT NULL,", _
" flags INTEGER NOT NULL", _
")" _
), vbLf)
With AdoCommand
.CommandText = SQLQuery
.Execute RecordsAffected, Options:=adExecuteNoRecords
End With
'''' ===== Insert rows into Functions table ===== ''''
SQLQuery = Join(Array( _
"INSERT INTO functions", _
"SELECT * FROM pragma_function_list" _
), vbLf)
With AdoCommand
.CommandText = SQLQuery
.Execute RecordsAffected, Options:=adExecuteNoRecords
End With
'@Ignore StopKeyword
Stop '''' Lock Db. For example, open in GUI admin tool and start a transaction
'''' ===== Try changing journal mode ===== ''''
On Error Resume Next
With AdoCommand
.CommandText = "PRAGMA journal_mode = 'WAL'"
.Execute RecordsAffected, Options:=adExecuteNoRecords
End With
If Err.Number <> 0 Then
Debug.Print "Error: #" & CStr(Err.Number) & ". " & vbNewLine & _
"Error description: " & Err.Description
End If
On Error GoTo 0
AdoCommand.ActiveConnection.Close
End Sub
【问题讨论】:
您发布的代码未运行然后在 DB Browser for SQLite 中打开数据库。如果在处理此 VBA 子期间发生这种情况,则应引发 数据库已锁定。运行像PRAGMA
这样的系统级调用应该在独占访问模式下完成,而不是在读/写操作期间。
@Parfait,不,它没有。 DB Browser for SQLite 是一个交互式使用的 GUI 管理工具。我知道为什么会引发“数据库被锁定”。创建此代码是为了以交互方式重现问题。错误不是问题。超时的长度是。它不应将 Excel/VBA 挂起 1.5 分钟左右。
知道了。尝试 single error handling 在 sub 末尾使用块而不是 On Error Resume Next
或 On Error Goto 0
。其他进程是否在 CPU 上运行? 1.5 分钟。可能只是你的环境。可以在其他地方测试吗?
【参考方案1】:
ADODB 连接和命令有超时设置,默认为 30 秒。更改此默认值不会产生明显的影响。实际超时时间为 100 秒,这个数字来自 SQLiteODBC 源。驱动程序必须有一个错误。它具有默认超时值,从连接字符串中获取自定义值,但忽略通过 ADODB 库设置的值。因此,添加“超时=XXX;”连接字符串选项可以完成这项工作。似乎将其设置为 0 意味着无限等待,但将其设置为 1 ms 可以解决超时问题。另一个默认关闭的选项 - StepAPI - 应该默认使用。这是另一个驱动程序错误或限制:启用 StepAPI 时,未设置忙处理程序,并且超时问题也消失了,无论“超时 = XXX;”如何选项。
【讨论】:
以上是关于尝试通过 ADODB/SQLiteODBC 更改 SQLite 数据库的日志模式时,Excel/VBA 挂起的主要内容,如果未能解决你的问题,请参考以下文章
当我尝试通过更改 `extra.symfony.require` 来升级 Symfony 时,为啥会出现此错误?
尝试通过部署后脚本添加列(更改表)并尝试将数据添加到新创建的列中抛出错误
尝试通过使用rest api从TFS票证中读取缺陷历史来获取TFS错误状态更改日期
消息:错误:轮询更改失败:通过 Selenium 和 FirefoxProfile 下载文件时尝试获取资源时出现 NetworkError
尝试通过 liquibase、postgresql、spring boot 创建新数据库。结果->“数据库更改日志”不存在