并发数据库查询线程化是否安全?

4

我正在尝试改进我为工作编写的程序。最初,由于时间紧迫,他们并不关心性能等问题。所以,我做了一个可怕的决定,查询整个数据库(一个SQLite数据库),然后将结果存储在列表中以供我的函数使用。然而,我现在考虑让我的每个函数都线程化,并让函数只查询它需要的数据库部分。总共有约25个函数。我的问题是,这样做安全吗?同时,是否可能有那么多并发连接?我只会从数据库中提取信息,不会插入或更新。


请参见:https://dev59.com/fkXRa4cB1Zd3GeqPv_j9 主要问题在于SQLite方面可能会令人烦恼。 - Conrad Frix
3个回答

0
我听到的描述是,每个并发线程都要打开自己的数据库连接,因为每个连接一次只能处理一个查询或修改。这些线程及其连接组可以轻松地执行并发读取操作。如果您遇到了许多并发写入导致过度阻塞或无法获取锁的问题,那么您已经超出了SQLite所能处理的范围(应该考虑使用像PostgreSQL这样的基于服务器的数据库)。
请注意,您也可以让主线程为工作线程打开连接,如果更方便的话,但建议(出于您的理智考虑,如果没有其他原因!)仅从一个线程实际使用每个连接。

[*对于SQLite的正常构建。当然可以在构建时关闭一些东西。]


最近我也在尝试使用RavenDB,它可以作为服务器或者进程内运行。值得一试。 - Mike Christensen

0

SQLite没有写并发性,但它支持任意多个同时读取的连接。只需确保每个线程都有自己的连接即可。


0

同时处理25个连接并不是一个明智的选择。这是一个巨大的数字。

我通常为这个问题创建一个多层设计。我通过一种名为ObjectFactory类的内部缓存将所有请求发送到数据库。ObjectFactory将请求转发给ConnectionPoolHandler,并将结果存储在其缓存中。这个连接池处理程序使用X个同时连接,但将它们分派到几个线程中。

然而,在应用这个设计之前,必须做出一些说明。您首先必须问自己以下两个问题:

  • 您的应用程序是唯一可以访问此数据库的应用程序吗?
  • 您的应用程序是唯一可以修改此数据库中数据的应用程序吗?

如果第一个问题的答案是否定的,则可能会遇到锁定问题。如果第二个问题的答案是否定的,则将极其难以应用缓存。您甚至可能更喜欢不实现任何缓存。

缓存在请求基于唯一引用的对象时特别有趣,例如主键。在这种情况下,您可以将最常使用的对象存储在Map中。用于缓存的流行集合是“LRUMap”(“最近最少使用”映射)。该集合的好处是它自动将最常使用的对象排在顶部。同时,它具有最大大小,并自动从地图中删除很少使用的项目。

缓存的第二个优点是每个对象仅存在一次。例如:

  1. 从数据库获取员工。
  2. ObjectFactory将结果集转换为实际对象实例
  3. ObjectFactory立即将其存储在缓存中。
  4. 稍后,使用SQL“... where name like“ John%”语句获取一堆员工。
  5. 在将结果集转换为对象之前,ObjectFactory首先检查这些记录的ID是否已经存储在缓存中。
  6. 找到匹配!啊哈,这个对象不需要重新创建。

在内存中仅有某个对象一次具有几个优点。

最后,在Java中有一种类似于“弱引用”的东西。这些引用实际上可以被垃圾回收器清理掉。我不确定在C#中是否存在以及它的名称是什么。通过实现这个,你甚至不需要关心缓存对象的最大数量,你的垃圾回收器会处理它。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接