Golang: Database: Behavior of Closing sql.DB

 25th October 2022 at 1:29pm

Go 的 sql.DB 对象有一个 Close 方法,可以用来关闭此对象。文档中提到:

Close closes the database and prevents new queries from starting. Close then waits for all queries that have started processing on the server to finish.

Close 会等待所有已经发送到 server 的连接结束。但是没有指明它是等到连接执行完才返回,还是马上返回。

实际使用 GORM 搭配 github.com/go-sql-driver/mysql 进行测试。测试方法是:

  1. 连接上 DB。
  2. 新建一个协程,其中开启一个事务并用 SELECT FOR UPDATE 加一个行锁。Sleep 5 秒后再 COMMIT 该事务。
  3. 确保上一步的协程执行后(比如 time.Sleep 一小会),新建另外一个协程,尝试 UPDATE 该行。这个 UPDATE 过程会被卡住,因为要等行锁释放。
  4. 确保上一步的协程执行后,调用 *sql.DBClose 方法关闭该 DB。观察到该 Close 方法没有阻塞,马上返回了。
  5. 第 2 步的协程运行 5s 后,正常结束;结束后第 3 步的协程也成功更新该行。
  6. 此时再使用该 *sql.DB 对象执行任意 SQL 语句时,会报 "database is closed"。

总结一下,调用 sql.DB.Close() 后:

  • Close 会马上返回
  • 已经发出的请求仍会被正常执行
  • 无法发布新的请求