【问题标题】:Is it okay to always leave a database connection open?始终保持数据库连接打开可以吗?
【发布时间】:2019-10-13 11:30:17
【问题描述】:

我在业余时间从事单用户桌面数据库应用程序之类的工作,但我总是不确定自己所做的设计选择。现在,就目前而言,每当用户想要与数据库(这是一个本地 SQLite 数据库,所以通常只有一个用户一次看到它)进行交互时,应用程序会创建一个新连接,做它需要做的任何事情,然后关闭连接。因此,在应用程序的一次执行过程中,会创建和处理大量连接。

这通常是“最好”的方式吗,还是应用程序应该在启动时打开连接并仅在应用程序退出时关闭它?每种方法的优缺点是什么?

【问题讨论】:

  • 在 Stackoverflow.com 上搜索。这个问题在那里被反复问过。
  • @JeffO 每个被问到的问题似乎都有不同的答案,通常是略有(或完全)不同意的答案。

标签: database


【解决方案1】:

我会说在这种情况下没问题,因为只有一个用户并且数据库托管在同一台机器上(更有可能在同一内存空间中,因为我认为 SQLite 只是作为 DLL 加载应用程序)作为应用程序。不需要不断地打开和关闭连接。

一个可能的例外可能是您需要让应用程序的多个线程同时访问数据库。然后你可以强制他们等待并共享一个连接对象,或者你可以尝试为不同的线程创建新的连接。我从来没有在 SQLite 中真正尝试过这个。这是关闭主连接和打开/关闭多个连接可能更适合桌面应用程序的一种情况。

对于 Web 应用程序或客户端/服务器桌面应用程序,我建议不要让连接保持打开状态。

【讨论】:

  • 您可能是第一个真正完整阅读问题的回答者。
  • @Andrew:你确定这不仅仅是同意你先前观点的第一个答案吗?利用连接池将允许您的应用程序重新使用一个保持打开状态的单个连接,但无需围绕该决定构建您的应用程序。您仍然可以编写仅在需要时获取和释放连接资源的代码。
  • @qes:SQLite 不支持连接池,所以不相关。
  • @Andrew Arnold 这确实是特定于 SQLite 的本地化案例;请牢记这一点。一方面,您声明您正在使用 SQLite,但似乎想知道采取一般立场的路线;那么另一方面,您似乎想知道 SQLite 中的最佳实现。不同的动物。
  • @Andrew Arnold 够公平的。正如您所指出的,SQLite 没有开箱即用的连接池支持;此外,缓存数据与连接相关,因此关闭/打开连接实际上会影响性能。
【解决方案2】:

通常在使用后关闭连接;将其释放回可用连接池中。如果在单个客户端上发生大量事务,则利用单个连接而不是创建多个连接来立即关闭它们是有意义的。

这有点偶然,但典型的最佳做法是在使用后将其关闭,以便它再次在池中可用。

【讨论】:

  • +1 用于提及连接池。通常,连接池保持连接打开,应用程序从池中检索/返回连接。连接可以保持打开数月或数年。连接池也可用于限制数据库访问并提高吞吐量。打开 1000 个连接会阻塞数据库和应用程序,但如果只有 5 个连接可用,每个事务将很快完成,并且应用程序将有不错的吞吐量。池大小取决于应用程序并需要调整
  • 连接池并不真正相关,因为 OP 谈论的是一次性本地 SQLite 数据库。
  • @gnuchu OP 正在询问最佳实践。仅仅因为 OP 没有明确指出,在回答这些类型的问题时隐瞒适用于现在和未来情况的信息,这对 OP 是不公平的。如果不赞成向 OP 提供其他信息;就这样吧...当其他人扩展我的问题并触及我以前可能不知道的事情时,我个人很感激。
  • @gnuchu:绝对相关。使用连接池可以获得保持连接打开的性能,同时允许构建代码以获取和释放所需资源的最少数量。
  • @qes 我想这是一个观点。 OP 在询问一个独立的 SQLite 数据库。 IMO 如果我们回答世界上所有关于连接到数据库的信息,它就会变成噪音。
【解决方案3】:

假设您有 1000 个用户同时访问您的应用程序。这意味着 1000 个打开的连接。最终你可能会用完连接。所以让每个用户打开一个连接,使用它,然后关闭它,这样连接就可以免费供其他人使用。

进一步说明

想象他有多个模块同时需要相同的连接?图像同时运行需要连接的控件。他要做什么?有一个全局连接对象吗?使用单例模式?如果我错了,请告诉我

【讨论】:

  • 不,它是个人桌面应用程序。只有一个用户访问过数据库。我应该说得更清楚。
  • 那么我会说它只是不好的设计。将来可能会出现问题
  • 它实际上是一个很好的桌面应用程序设计。事实上,这是此类应用程序的常态,并且已经持续了数十年。它有效,可靠,并且比一直重新打开连接执行得更好。
  • @jwenting:实际上两者之间的性能差异很小(几乎为零)。因此,最好采用更常见且更容易转化为大型多用户应用程序的做法。
  • @jwenting @Andrew Arnold:想象他有多个模块同时需要相同的连接?图像同时运行需要连接的控件。他要做什么?有一个全局连接对象吗?使用单例模式?如果我错了,请告诉我
【解决方案4】:

连接池应该让这成为一个争论点。池应保持连接并打开以供您重用。这应该允许您遵循以最短的合理数量使用资源但不牺牲性能的一般最佳实践。

【讨论】:

    【解决方案5】:

    在处理数据库连接时,我的策略是取决于您需要做什么。例如,如果您正在加载大量相关的关键数据,我的建议是将您的所有操作封装在一个事务中,并且在事务提交后应该关闭一个连接。

    现在,如果您需要执行大量查询来检索数据,则为每个查询打开和关闭连接可能会非常昂贵,因此,保持连接打开是值得的。

    【讨论】:

      【解决方案6】:

      我刚开始问自己同样的问题。和你一样,它只是一个应用程序,我不担心连接不足。

      然而,我确实遇到了一个让数据库保持打开状态的潜在问题:事务。如果您执行 BEGIN TRANSACTION 并且出现错误或发生其他事情,而您的代码未命中 COMMITROLLBACK,那么您将保持该事务处于打开状态。

      因此,最好仅将其关闭以确保在数据库完成工作后恢复所有内容。

      我真的不知道打开和关闭数据库的开销有多大。我很想听听其他人对此的看法。

      【讨论】:

        【解决方案7】:

        打开新连接很昂贵。 因此,使用连接的最佳方式是在完成事务后将其标记为空闲。然后连接将返回到空闲连接池。

        当应用程序请求连接时,代码必须检查空闲 {free} 连接池并返回一个。如果池中没有空闲连接,则应使用新连接。当向服务或实体提供连接时,必须将连接标记为“活动”;这样连接就不会提供给任何后续请求。

        连接未关闭时,必须正确处理连接的提交、回滚等。

        检查您的语言或框架。大多数框架已经维护了一个空闲连接的容器;因此,您无需担心。 一些语言还提供了开箱即用的此功能。例如 Golang 核心包类型 sql.DB 维护了一个空闲连接池,能够被并发使用,所以你不需要担心关闭连接。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-09-10
          • 1970-01-01
          • 1970-01-01
          • 2013-09-28
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多