【问题标题】:Do we need to close DB connection before closing application in Go?在 Go 中关闭应用程序之前,我们是否需要关闭数据库连接?
【发布时间】:2016-03-13 06:35:25
【问题描述】:

在 Go 中,使用 SQL 数据库时,是否需要在关闭应用程序之前关闭 DB (db.Close)?数据库会自动检测到连接已经断开吗?

【问题讨论】:

  • 需要记住的重要一点是 Close() 不能保证触发,尤其是当您调用 defer db.Close() 时。 SIGTERM 信号将立即终止程序(除非你抓住它)并且不会调用 Close()。根据我的经验,当没有调用 Close() 时,lib/pq(最流行的 Postgres)驱动程序似乎没有挂起连接。

标签: sql database go


【解决方案1】:

DB 会尽力检测,但如果运气不好,它可能无法检测到。最好尽快释放获得的东西。

send() 系统调用将等待 TCP 连接发送数据,但客户端不会收到任何内容。

  1. 在没有正确释放资源的情况下发生电源故障、网络问题或裸退出。 TCP keepalive 机制将启动并尝试检测连接已死。

  2. 客户端已暂停,未接收任何数据,在这种情况下send() 将阻塞。

因此,它可能会阻止

  1. 集群正常关闭。
  2. 如果它持有排他锁作为事务的一部分,例如 postgresql 中的auto vacuum,则推进事件视界。

可以缩短服务器保活配置以更早地检测到它。 (例如,postgresql 中的~2h 12m 默认会根据工作量很长)。

最大打开连接数可能有硬性限制,在检测到之前,一些连接将是僵死的(在那里,不可用但会降低限制)。

【讨论】:

    【解决方案2】:

    数据库将注意到连接已断开并采取适当的措施:例如,在该连接上活动的所有未提交事务将被回滚,并且用户会话将被终止。

    但请注意,从数据库引擎的角度来看,这是一个“恢复”场景:它不能只是在客户端断开连接时抛出;而是必须采取明确的行动来获得一致的状态。

    另一方面,当程序以“正常方式”(即不是因为恐慌或log.Fatal())出现故障时关闭属性确实不是那么难。而且由于sql.DB 实例通常是程序范围的全局变量,它甚至更简单:只需尝试像马特建议的那样在main() 中关闭它。

    【讨论】:

      【解决方案3】:

      如果您在任何函数中初始化连接,通常最好将调用推迟到立即关闭,即

      conn := sql.Connect() // for example
      defer conn.Close()
      

      一旦封闭函数退出,它将关闭连接。

      这在main 函数中使用时很方便,因为一旦程序退出,就会调用Close()

      【讨论】:

        猜你喜欢
        • 2020-11-22
        • 1970-01-01
        • 2016-03-18
        • 2011-04-02
        • 2014-06-28
        • 2013-03-04
        • 2015-08-08
        • 1970-01-01
        • 2021-05-19
        相关资源
        最近更新 更多