36

对于一个小型项目,我需要使用一个要求非常轻的简单数据库:很少的表,总共不超过几千条记录,2 或 3 个用户。我在.NET 环境中工作。

由于数据库服务器(即使是那些 Express 版本)在这种情况下似乎是一个巨大的矫枉过正,一个非常简单的 MDB 数据库可以满足大多数要求。但是,我担心并发性。我的想法是将 .mdb 文件放在网络共享上,让用户从基于 .NET 的客户端访问该文件。数据库主要针对只读操作,但用户有时也需要更新/删除记录。如果当时无法做到这一点(由于数据库被锁定或其他原因),我可以在客户端上保存更新并在以后处理它们。

问题本身涉及以下几点:

  • MDB 中如何处理并发读取?
  • MDB 中如何处理并发更新/删除?
  • 是否有锁的概念以及如何在 .NET 应用程序中利用它?
  • 将 MDB 文件放在网络共享上是好主意还是坏主意?

当我在 .NET 中工作时,我也很想知道如何检测任何并发问题并采取适当的措施。即,我应该捕获哪个异常以及您建议采取什么行动?

编辑:这可能是我对问题的错误描述,但大多数答案似乎都建议使用完整的数据库服务器。我确实了解安装服务器的区别和好处,并且实际上已经在 MSSQL 和 Oracle 上实施了相当数量的项目。但是,在这个问题中,我只关心 Access 及其并发问题,所以请不要建议使用数据库服务器。

谢谢你的帮助。

4

11 回答 11

50

这是一个古老的问题,但没有人真正回答过它。以下是问题:

  1. MDB 中如何处理并发读取?
  2. MDB 中如何处理并发更新/删除?
  3. 是否有锁的概念以及如何在 .NET 应用程序中利用它?
  4. 将 MDB 文件放在网络共享上是好主意还是坏主意?

前两个问题基本上可以用一个解释来回答。这里有一个关键警告:我在这里给出的答案是针对 Jet MDB(及其变体)的,并不完全适用于从 A2007 开始引入的新文件格式,即 ACCDB 格式。我还没有完全探讨从 ACE 中移除 Jet ULS 的影响,下面的一些评论可能会假设 Jet ULS 在引擎盖下。但是,对于很多事情,您可以将“LACCDB 文件”替换为“LDB 文件”,结果将是相同的。

1-2) 并发读取/更新/删除

Jet 数据库引擎通常被称为“文件服务器”数据库,因为没有服务器端恶魔管理服务器上的数据文件的 I/O。这意味着所有使用 Jet MDB 的客户端都在直接读取文件。

如果没有内置某种机制来处理对文件的并发访问,那当然是灾难的根源。

Jet 使用记录锁定文件,如果您的 MDB 是“MyFile.MDB”,则记录锁定文件将位于同一文件夹中并称为“MyFile.LDB”。LDB 文件记录了哪些 Jet ULS 用户打开了 MDB 文件、该用户从哪个工作站连接,以及协商并发问题所需的所有信息。

现在,对于那些开始研究客户端/服务器数据库引擎的人来说,这可能看起来很原始和危险,但是在开发 Jet 数据库引擎时,它的目的是用作小型工作组的桌面数据库引擎,并且它与 xBase 和 Paradox 等其他桌面数据库引擎竞争,它们都使用类似的锁定文件来管理来自多个客户端的数据文件的并发使用。

在 Jet 数据库文件中,锁定应用于数据页(在 Jet 4 中增加到 4K,而在 Jet 3.x 和之前的版本中,它们是 2K),或者如果数据表最初创建为使用记录级锁定。在 Jet 4 的早期,许多人发现记录级锁定非常缓慢,尤其是在使用悲观锁定时,因此许多 Access 开发人员除了页面级锁定之外从未使用过任何东西(@David Fenton 举手!)。

事实上,当使用乐观锁时,您可以避免悲观锁带来的大部分并发问题。

一些警告:

  1. 从 DAO 中,记录级锁定不可用,并且您只能获得页面级锁定。

  2. 从 DAO 中,有许多用于控制乐观/悲观锁定的选项,特别是 OpenRecordset 方法的 LockEdits 参数,但它也与 OpenRecordset 选项参数中指定的某些设置交互(例如,选项 dbReadOnly 不能与锁定编辑)。除了锁定之外,还有一致/不一致更新的选项,所有这些都可以与事务交互(例如,未提交事务中的更改不会对其他用户可见,因此不会与他们发生冲突,但它可以在所涉及的表上放置只读锁)。

从 ADO/OLEDB 中,这些 Jet 并发控制结构将映射到 ADO/OLEDB 中的相关函数和参数。由于我仅从 Access 使用 Jet,因此我仅通过 DAO 与其交互,因此我无法建议您如何使用 ADO/OLEDB 控制这些,但关键是 Jet 数据库引擎在访问它时提供对记录锁定的控制以编程方式(而不是通过 Access UI)——它只是更复杂。

3) 锁和.NET

除了您可能会使用 OLEDB 作为数据接口之外,我在这里无法提供任何建议,但关键是 db 引擎本身就存在锁定功能/控件,因此可能有一种方法可以通过OLEDB。不过,它可能并不漂亮,因为在我看来 OLEDB 是围绕客户端/服务器架构设计的,而 Jet 的基于文件的锁定可能无法以优雅的方式映射到它。

4) 网络共享上的 MDB

Jet 对任何网络连接中最轻微的故障都非常敏感。因此,低带宽网络会增加通过慢速连接打开的 Jet 数据库的脆弱性。

这是因为数据库文件的主要块必须通过线路拉到本地计算机的 RAM 进行处理。现在,许多人错误地声称整个 MDB 文件是通过网络传输的,或者整个表都是通过网络传输的。这不是真的。相反,Jet 首先请求索引(并且请求不超过完成查询所必需的),然后根据该结果确定需要哪些数据页面,然后仅提取这些页面。这是令人惊讶的高效和快速。

此外,Jet 进行了一些非常智能的缓存,这可能意味着第一个数据请求可能需要一段时间,但由于缓存,后续对相同数据的请求几乎是即时发生的。

现在,如果你没有很好地索引你的表,你最终可能会拉出整个表并进行全表扫描。同样,如果您基于不属于 Jet 的 SQL 方言的客户端函数的标准,您最终可能会拉取一个完整的表(排序,例如,Replace(MyField, "A", "Z") 可能会导致全表扫描)。但是这种事情对于客户端/服务器架构也将是低效的,因此正确索引事物并小心使用 UDF 或非 Jet 兼容函数只是常识模式设计。一般来说,对于客户端/服务器有效的相同操作将在 Jet 中有效(主要区别在于,对于 Jet,您最好使用持久连接,以避免重新创建 LDB 文件的开销,这很重要)。

要避免的另一件事是尝试通过 WiFi 连接使用 Jet 数据。我们都知道 WiFi 有多不可靠,它只是在尝试通过 WiFi 连接处理 Jet 数据时遇到麻烦。

底线:

如果您使用 MDB 作为数据存储来提供来自 Web 服务器的数据,则应将数据尽可能靠近 Web 服务器的 RAM。这意味着在可能的情况下,在连接到物理 Web 服务器的磁盘卷上。如果这是不可能的,您需要快速、可靠的 LAN 连接。如今,数据中心中的 GB LAN 非常普遍,我很乐意通过这种连接处理 Jet 数据。

对于共享使用,例如,运行 VB.NET 桌面应用程序的多个客户端工作站共享单个 Jet MDB 作为数据存储,将数据文件放在可靠的文件服务器上是非常安全的。在可能的情况下,最好将 Jet MDB 文件放在不具备多种用途的机器上(例如,运行 Exchange、SQL Server 并充当文件服务器和打印服务器的域控制器可能不是最佳位置) . 像 Exchange 这样的应用程序会严重干扰文件服务器的功能,我通常建议不要将 MDB 文件放在作为 Exchange 服务器的多任务服务器上,除非它的容量非常小。

其他注意事项:

  1. 切勿尝试在复制的文件系统上分发 MDB,除非所有用户都使用相同的副本。也就是说,如果您有两台服务器在它们之间复制文件,甚至不要考虑从两台服务器编辑 MDB 文件。这几乎会立即损坏文件。

  2. 我建议不要将任何 MDB 存储在通过本机 Microsoft SMB 网络提供服务的本机 Windows 文件系统以外的任何地方。这意味着没有 Novell、没有 Linux、没有 SAMBA。造成这种情况的关键原因是 Jet 显然在 Windows 文件系统中的某些低级锁定功能中存在低级挂钩,这些挂钩并未 100% 复制到其他文件系统上。现在,我对此非常保守,许多称职的 Access 开发人员报告了正确配置的 Novell 文件服务器的出色结果(通常需要进行一些记录锁定调整,尽管这些天可能不太相关 - 我不'甚至不知道 Novell 是否还存在!),以及运行 SAMBA 的基于 Linux 的文件服务器的出色性能。我对此持谨慎态度,并建议任何客户端反对它(这包括各种 SAN 设备,

  3. 出于同样的原因,我永远不会在任何虚拟化文件系统上运行它们。但是,我有一个客户,她多年来一直在 Mac Air 上的 Parallels 下运行她的单用户 Access 应用程序,现在没有出现任何问题。但它是单用户的,所以锁定问题相对较小。

我不知道这是否回答了你的问题。这一切都基于我作为 Access 开发人员 13 年来经常使用 Jet 以及对唯一出版的关于 Jet 的书籍《Jet Database Engine Programmers Guide》(仅适用于 Jet 3.5)的研究。我没有提供任何真实的引用,但如果有人需要我所说的任何细节,我会尽可能地进行研究。

于 2009-12-22T02:16:54.860 回答
13

多年来,我在 Access 中构建了十几个小型企业应用程序。大多数人一次最多有 10-20 个用户。数据库分为“应用程序”和“数据”数据库。性能不错,没有并发问题。自 Access 2000 SP2 以来,基本上不存在损坏。

有很多人说“永远不要使用 Access”——如果做得对(即由专业开发人员完成),Access 是一个相当不错的开发包,我已经过上了很好的生活。我的客户对我建造的东西非常满意。

于 2009-03-30T00:32:52.577 回答
11

我编写了两个使用 Access 数据库的商业产品,从网络共享运行,通常最多可容纳 10 个用户。如果你不滥用它,那真的没有问题;但正如您所看到的,许多开发人员从未到达那里——而且由于其低端性质,有很多基于它的蹩脚黑客。对于一个产品,由于其他人详细描述的所有问题,我不得不重新设计应用程序;但是在我清理它之后,我在数百次安装中从未遇到过数据库完整性问题。

它的一大优势是单一文件数据库,易于备份、恢复和复制到您的笔记本电脑进行剖析。几乎所有的替代方案,包括 sqlite(尽管有些人不承认),都需要 DBA 时不时地给予某种形式的关注。

在大多数情况下,Access 默认为某些 DDL(例如架构更改)提供记录锁和文件锁。

但是微软基本上已经淘汰了它,你的一些同事会因为你使用它而嗤之以鼻。

(此时我通常会躲避并大喊“进来!!!”。)

于 2009-03-29T21:58:44.883 回答
4

Access 是真正的桌面单用户解决方案。实际上,它的用户上限为“一”。

它也是一个本地引擎。也就是说,当您运行查询时,数据会通过网络拉到本地 JET 引擎进行处理。.ldb 文件放置在网络共享上以控制锁。

如果您使用服务器端引擎(MSSQL、MySQL、Sybase、'Orable 等),那么您将查询提交给处理它并将结果返回给您的引擎。锁是内部持有的。

这对性能、稳定性和数据完整性具有巨大影响。

如果您的用户决定按下重置按钮,则 Access 数据库很有可能被损坏,您必须删除 .ldb。

有了合适的数据库引擎(MSSQL、Sybase、'Orable:我不喜欢 MySQL 的备份),你也有合适的备份能力。除非您有一些出色的软件来备份正在使用的文件,否则您可能无法在 Access DB 中备份您的数据。

我特别提到了锁,因为数据库引擎可以比任何基于文件的系统更高效、更优雅地处理并发和事务。

我可以看到使用 Access 项目作为数据库引擎的前端,而不是投资于具有 Access 后端的完整客户端应用程序。

于 2009-03-29T17:21:33.787 回答
3

我一直在使用 Access,或者更准确地说,Jet 作为一个非常小的私人网站的后端,该网站永远不会增长,因为它受到这个小国家的专业规模的限制。三年来,我没有遇到任何问题。用户不到 100 人,每天大约有 30 到 40 人使用它。这些表有几千条记录。

于 2009-03-29T20:41:59.437 回答
2

我对 Access 没有太多经验,但此链接可能对您有用:

http://office.microsoft.com/en-us/access/HP052408601033.aspx

“您可以将整个 Access 数据库放在网络服务器上或共享文件夹中。这是最容易实现的方法。每个人都共享数据并使用相同的表单、报表、查询、宏和模块。如果您希望每个人都以相同的方式使用 Access 数据库,或者如果您不能支持用户创建自己的对象。”

“在共享模式下打开 Access 数据库文件 (.mdb) 时,Microsoft Access 还会在与数据库文件相同的文件夹中创建一个具有相同文件名(例如 Northwind.ldb)的锁定信息文件 (.ldb) . 这个锁定信息文件存储了数据库的每个共享用户的计算机名(如mypc)和安全名(如Admin)。Microsoft Access 使用此信息来控制并发。大多数情况下,Microsoft Access 会自动删除锁定信息最后一个用户关闭数据库文件时的文件。”

于 2009-03-29T16:52:02.890 回答
2

Access 应该是多用户的 - 我认为 Microsoft 建议最多 4 或 5 个用户使用它,但实际上我建议您永远不要在有多个用户的情况下使用 Access 数据库,尽管如果您真的不这样做考虑到某些附带条件,没有两个或三个可以接受的选择。

我有过使用 Access 数据库后端的四五个系统的经验——所有这些系统都是从其他“开发人员”那里获得的——并且在所有情况下,我都将它们作为优先事项转移到 SQL Server 之后,需要任何即时更新和修复签订合同时——通常是在我能说服老板付账的时候。时间跨度通常是几个月,所以我看到它在几个不同的应用程序下并发运行了一段合理的时间。

实际上,如果系统没有很多并发插入/更新并且没有大量使用,它通常会很好地工作。根据我的经验,主要的实际问题是..

  1. 它容易腐败——它就是这样。通常这不是什么大问题,因为打开文件并运行压缩和修复会解决问题,但良好的备份机制是绝对必要的。

  2. 它很慢。每次我将系统升级到 SQL Server 时,我都会收到很多用户对系统加速的赞誉。

  3. 由于 Access 将记录标记为已更新或已删除的方式,数据库文件膨胀。这进一步减慢了系统的速度,因为文件必须通过网络加载。因此,一些通常每天压缩数据的机制是必不可少的。

以上所有这些对于单用户系统来说都不是问题,因为引发这些问题的潜在问题不那么突出。

总而言之,我必须强调,我绝不会为任何多用户系统推荐 Access。但是,如果真的有太多,只要它是一个轻量级的应用程序并且您确实制定了备份和维护程序,您可能会侥幸逃脱。

于 2009-03-29T21:57:29.910 回答
1

当使用网络共享时,我会使用启用网络的数据库(mysql/firebird/mssql)而不是访问。

对于您使用 Access 描述的情况不会有问题。

我在更具挑战性的情况下使用了 Access,这主要是在处理网站时,当 Access 未被滥用时,它确实不是数据库引擎那么糟糕。(不是在谈论表格和诸如表格和记录之类的东西)

当您一次从多个用户进行插入/更新/删除时,它会变得有点毛茸茸。这是您开始考虑真正的数据库引擎的地方。

此外,当您想要一个线程安全的低开销数据库时,您可以查看 vistadb(访问速度较慢,并不总是免费,100% .NET)

我认为访问使用具有某种排队机制的表级锁应该可以正常工作。如果您担心它,您可以随时对其进行模拟压力测试。

于 2009-03-29T16:47:32.993 回答
1

我认为您可以在 .net 应用程序连接字符串中定义它。我搜索了 JET,访问和记录锁定

这是一个可能有帮助的链接。

有关 Access 和 JET 如何获取数据的真实详细信息,请参阅已接受的答案。

于 2009-03-29T17:19:22.307 回答
1

已经多次声明要使用真正的多用户、免费数据库平台。但其中一个原因尚未说明。原因是,有多少现有的、杂乱的、麻烦的、大型的 Access 数据库是从“几条记录,最多一两个用户”开始的?我敢说所有这些。

除非整个公司只有两三个员工,否则很有可能如果你开发了一个有用的软件,它最终会被超过原来的两三个用户使用,拥有超过原来的几千条记录, 并且将在多年来扩展到包括许多表格、更多表格和更多数据。房子建好后就不能再打地基了。今天打下坚实的基础,你就可以随心所欲地扩建房子。软件也一样。

于 2009-03-29T19:17:27.127 回答
-1

请不要将 Access 用于多用户方案。

我刚刚经历了两周的痛苦,因为我的前任在一个项目中选择了 Access 作为后端。

具体原因:

  • 没有 Linq-to-Access 这样的东西
  • Access 有许多怪癖,例如依赖于将参数添加到命令的顺序,这将花费您很长时间来调试
  • 访问无法扩展
  • 与使用 SQL Server 相比,数据库更新是一件苦差事
于 2009-03-29T18:36:14.307 回答