【问题标题】:Is it safe to thread concurrent database queries?线程并发数据库查询是否安全?
【发布时间】:2012-12-06 22:51:21
【问题描述】:

我正在努力改进我为工作而编写的这个程序。最初我很着急,他们不关心性能或其他任何事情。因此,我做出了一个可怕的决定:查询整个数据库(一个 SQLite 数据库),然后将结果存储在列表中以供我的函数使用。但是,我现在正在考虑让我的每个函数都线程化,并且让函数只查询它需要的数据库部分。有大约 25 个函数。我的问题是,这样做安全吗?另外,是否有可能有那么多并发连接?我只会从数据库中提取信息,从不插入或更新。

【问题讨论】:

标签: c# sqlite concurrency thread-safety


【解决方案1】:

我向我描述的方式[*]是让每个并发线程打开自己的数据库连接,因为每个连接一次只能处理一个查询或修改.然后,具有连接的线程组可以轻松地执行并发读取。如果您遇到许多并发写入导致过度阻塞或无法获取锁的重大问题,那么您将超过 SQLite 为您所做的事情(并且应该考虑像 PostgreSQL 这样的基于服务器的数据库) .

请注意,如果这样更方便,您也可以让主线程打开工作线程的连接,但建议(为了您的理智,如果没有别的!)只实际使用每个连接来自一个线程。


[* 用于 SQLite 的正常构建。当然,可以在构建时关闭。]

【讨论】:

  • 我最近也一直在搞乱RavenDB,您也可以将其作为服务器或进程内运行。可能值得一试。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    25 个同时连接不是一个聪明的主意。这是一个巨大的数字。

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

    但是,在应用此设计之前必须做一些说明。您首先必须问自己以​​下 2 个问题:

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

    如果第一个问题是否定的,那么您可能会遇到锁定问题。如果您的第二个问题的回答是否定的,那么应用缓存将非常困难。您甚至可能不希望全部实现任何缓存。

    如果您经常根据唯一引用(例如主键)请求对象,缓存尤其有趣。在这种情况下,您可以将最常用的对象存储在 Map 中。一个流行的缓存集合是“LRUMap”(“最近最少使用”地图)。这个集合的好处是它会自动将最常用的对象排列到顶部。同时,它具有最大尺寸,并自动从地图中移除很少使用的项目。

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

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

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

    最后但并非最不重要的一点是,Java 中存在“弱引用”之类的东西。这些是实际上可以被垃圾收集器清理的引用。我不确定它是否存在于 C# 中以及它是如何被调用的。通过实现这一点,您甚至不必关心缓存对象的最大数量,您的垃圾收集器会处理它。

    【讨论】:

      猜你喜欢
      • 2023-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-12
      • 1970-01-01
      • 2012-08-21
      相关资源
      最近更新 更多