【问题标题】:Preventing IIS from keeping a file lock on a SQLite database file防止 IIS 在 SQLite 数据库文件上保持文件锁定
【发布时间】:2023-03-14 05:02:01
【问题描述】:

我们有一个用经典 ASP 编写的旧版 Web 应用程序,目前使用 MS Access 数据库作为其数据存储。通过 Jet OleDB 提供程序与数据库交互:

Provider=Microsoft.JET.OLEDB.4.0;Data Source=database.mdb

与大多数 Web 应用程序一样,CRUD 操作会定期在数据库上执行。

应用程序连接到数据库,执行insertupdatedeleteselect 语句然后关闭连接。连接关闭后,我们可以立即重命名移动 MS Access .mdb 文件而不受惩罚。多年来,我们一直在利用这种行为 - 这对于我们的用例来说是必要的,并且对我们很有帮助。

由于各种原因,我们正在用 SQLite 3 替换 MS Access 数据库。我们通过 ODBC 连接到 SQLite 版本。

与 SQLite 数据库的交互就像以前一样,即连接到数据库,发出 SQL 命令,关闭连接。

问题是 SQLite 数据库文件在连接关闭后保持锁定 60 秒。这可以防止我们重命名或移动数据库文件,因为很有可能在 60 秒内发生另一个连接,因此文件似乎被永久锁定。

我们在 Classic ASP 中创建了一个最小页面来说明行为:

Dim connectionString: connectionString = "DRIVER=SQLite3 ODBC Driver;LongNames=0;Timeout=1000;NoTXN=0;SyncPragma=NORMAL;StepAPI=0;FKSupport=0;NoCreat=1;Database=database.sqlite"

Dim con : Set con = CreateObject("ADODB.Connection")
con.Open connectionString

' Issue some CRUD commands here

con.Close
Set con = Nothing
Response.Write("We are here!!!!!")

为了确定导致锁定的原因,我们构建了一个VBScript 文件(使用上面显示的相同 SQLite 连接字符串)然后我们从命令行运行它(因此根本不涉及 IIS。)

在这种情况下,在连接后,发出任何CRUD 命令,然后关闭数据库,SQLite 文件可以立即访问。因此我们得出结论,IIS 7.5(或更准确地说是W3WP.exe)以某种方式对 SQLite 文件进行了锁定。事实上,如果我们停止网站的 App Pool,文件上的锁就会立即释放。

VBScript文件的代码如下:

Dim connectionString: connectionString = "DRIVER=SQLite3 ODBC Driver;LongNames=0;Timeout=1000;NoTXN=0;SyncPragma=NORMAL;StepAPI=0;FKSupport=0;NoCreat=1;Database=database.sqlite"

Dim con : Set con = CreateObject("ADODB.Connection")
con.Open connectionString

' Issue some CRUD commands here

WScript.Echo "Press [ENTER] to continue..."

' Read dummy input. This call will not return until [ENTER] is pressed.
WScript.StdIn.ReadLine

WScript.Echo "Done."

con.Close
Set con = Nothing

我们可以利用 IIS 中的某种设置来操作 SQLite 数据库,就像我们目前使用 MS Access 一样?

【问题讨论】:

  • 如果它以前在 MSAccess DB 上工作过,您如何得出 IIS 有问题的结论?更有可能是 SQLite 驱动程序是导致该行为的原因,而不是 IIS。
  • @Lankymart 我已经编辑了我的问题,希望能更清楚地说明从 VBScript 文件内部连接到 SQLite 时不会导致文件锁定 60 秒。但是当连接到经典 ASP 文件中的 SQLite 时,会锁定文件 60 秒。两种情况都使用相同的驱动程序和连接字符串。
  • 听起来你在做conn.Close,但没有跟进Set conn = Nothing
  • 可能与连接池有关,尽管对于您使用的 SQLite 驱动程序,默认情况下禁用池。也许 IIS 只是在做自己的事情。发现此链接声称 IIS 仅在 60 秒后释放 ODBC 连接:knowledgebase.progress.com/articles/Article/…
  • @GordThompson 我们实际上是在发出Set conn = Nothing 命令。我编辑了问题以显示代码。

标签: sqlite ms-access iis asp-classic odbc


【解决方案1】:

在发布原始问题大约一年后,我重新审视了这个问题,因为一位同事实际上发现了对我们有用的解决方案,也许它会对其他人有所帮助。

有效的解决方案是对注册表进行一些更改。这与CH Werner SQLIte ODBC Driver 无关。事实上,我们与 CH Werner 本人进行了电子邮件对话,他确认驱动程序不会影响我们描述的数据库锁定。

解决方法是对注册表进行如下修改:

Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{c8b522cb-5cf3-11ce-ade5-00aa0044773d}]
@="MSDASQL"
"OLEDB_SERVICES"=dword:fffffffe
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Wow6432Node\CLSID\{c8b522cb-5cf3-11ce-ade5-00aa0044773d}]
@="MSDASQL"
"OLEDB_SERVICES"=dword:fffffffe

如果您将上述注册表更改放入具有 .reg 文件扩展名的文件中,您将能够在 Windows 资源管理器中双击它来进行更改。

一旦注册表具有这些设置,IIS不会在连接关闭后锁定 SQLite 数据库文件 60 秒。

希望这将帮助遇到此问题的其他人。

【讨论】:

  • 哇,这些是非常具体的注册表项。很高兴听到您终于找到了解决方案?
  • 嗨,伙计,希望你一切都好。是的,Nick S 在一个有关所有事物的 MySql 论坛上遇到了解决方案。它已经在生产中工作了 6 个月。只是一直忘记回到这里发布解决方案。
【解决方案2】:

使用CH Werner SQLite ODBC Driver,您无法关闭连接池。驱动程序中有处理SQL_ATTR_CONNECTION_POOLING 属性的代码,但该属性从未使用过。这意味着它将默认使用连接池。

停止 IIS 保持对数据库的锁定将涉及修改 DLL 以包含 ConnectionPooling=True/FalseCPTimeout=n 以便我们可以发送适当的值到SQLSetEnvAttr 函数。

【讨论】:

  • @Simon 你应该为这部伟大的调查作品投票!
  • @Lankymart,好点,我刚刚投了赞成票。如您所知,mrstebo 实际上离我有两张桌子。他正在从事同一个项目:)
  • @SimonLomax 他们仍然找到了答案,在答案中可能值得注意,但对我没有任何改变。如果其他人遇到这个问题,它仍然会有所帮助。
猜你喜欢
  • 2016-12-13
  • 2019-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-09
相关资源
最近更新 更多