问题记录:论为什么要显式关闭数据库连接
问题过程
- 运行代码,代码内容包括执行一条insert sql和一段耗时操作。
- 运行起来之后看到db没有插入这条数据,才想起来这个工具类的insert方法是不自动commit的
- 于是kill掉代码运行的进程,在insert语句后面加上commit,重新运行
- insert超时,报错信息:
connectDB timeout: (1205, u'Lock wait timeout exceeded; try restarting transaction') when update
- 这个insert的表有unique key,两次运行插入的数据是相同的,所以报错信息说明锁还被第一次运行产生的数据库连接进程持有着
- 通过
show processlist;可以看到进程确实还在,然后通过kill id;kill掉这个进程,就可以insert这条数据了。
- 所以就查了一下为啥kill了代码进程,数据库服务端的连接进程还在呢。
- 是因为虽然代码进程已经被kill掉,但是TCP连接并没有立即关闭,MySQL服务器还没有意识到客户端已经断开连接。
- TCP连接有一个特性,就是在客户端断开连接后,服务器端并不会立即知道,除非服务器试图向客户端发送数据。这是因为TCP连接是全双工的,即使客户端断开了连接,服务器仍然可以向客户端发送数据,直到遇到错误才知道客户端已经断开。
- MySQL服务器有一个系统变量
wait_timeout,用于设置非交互式连接的超时时间。如果在这个时间内没有任何活动,MySQL服务器会自动关闭连接,默认是8小时。
- 所以应该在应用程序中显式地关闭数据库连接,确保连接在进程结束时被正确关闭。