JdbcSQLNonTransientConnectionException:数据库可能已在使用中:“等待数据库关闭时间超过 1 分钟”
Posted
技术标签:
【中文标题】JdbcSQLNonTransientConnectionException:数据库可能已在使用中:“等待数据库关闭时间超过 1 分钟”【英文标题】:JdbcSQLNonTransientConnectionException: Database may be already in use: "Waited for database closing longer than 1 minute" 【发布时间】:2020-11-20 10:36:39 【问题描述】:我们使用 H2 作为数据库服务器进程启动并监听标准 TCP/IP 端口 9092。
我们的应用程序使用连接池部署在 Tomcat 中。我们在空闲时间进行清除,最终导致关闭与 H2 的所有连接。当应用程序再次尝试打开与 H2 的连接时,我们有时会观察到错误:
SCHEDULERSERVICE schedule: Exception: Database may be already in use: "Waited for database closing longer than 1 minute". Possible solutions: close all other connection(s); use the server mode [90020-199]
org.h2.jdbc.JdbcSQLNonTransientConnectionException: Database may be already in use: "Waited for database closing longer than 1 minute". Possible solutions: close all other connection(s); use the server mode [90020-199]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:617)
at org.h2.message.DbException.getJdbcSQLException(DbException.java:427)
at org.h2.message.DbException.get(DbException.java:205)
at org.h2.message.DbException.get(DbException.java:181)
at org.h2.engine.Engine.openSession(Engine.java:209)
at org.h2.engine.Engine.createSessionAndValidate(Engine.java:178)
at org.h2.engine.Engine.createSession(Engine.java:161)
at org.h2.server.TcpServerThread.run(TcpServerThread.java:160)
at java.lang.Thread.run(Thread.java:748)
at org.h2.message.DbException.getJdbcSQLException(DbException.java:617)
at org.h2.engine.SessionRemote.done(SessionRemote.java:607)
at org.h2.engine.SessionRemote.initTransfer(SessionRemote.java:143)
at org.h2.engine.SessionRemote.connectServer(SessionRemote.java:431)
at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:317)
at org.h2.jdbc.JdbcConnection.<init>(JdbcConnection.java:169)
at org.h2.jdbc.JdbcConnection.<init>(JdbcConnection.java:148)
at org.h2.Driver.connect(Driver.java:69)
at java.sql.DriverManager.getConnection(DriverManager.java:664)
当 Tomcat 连接池关闭所有空闲连接(未使用),然后关闭一个仍在使用的连接时,就会出现问题。
下一次尝试打开新连接失败,等待一段时间后重试成功。
在什么情况下会出现这种异常? 异常是什么意思? 是否有任何建议可以避免该问题?在我看来,H2 在关闭最后一个连接后会关闭数据库。
数据库何时关闭? 如何控制数据库关闭?提前谢谢 托尔斯滕
【问题讨论】:
【参考方案1】:Web 应用程序中的嵌入式数据库需要仔细处理其生命周期。
您可以添加javax.servlet.ServletContextListener
实现(标有@WebListener
注释或包含在web.xml
中)并将显式数据库关闭添加到其contextDestroyed()
方法。
您可以在此处使用connection.createStatement().execute("SHUTDOWN")
强制关闭数据库。如果您的应用程序需要在卸载期间向数据库写入内容,则应在该命令之前执行。
如果没有显式配置某些其他行为(例如,使用 JDBC URL 中的参数),H2 会在所有连接关闭时关闭数据库。例如,DB_CLOSE_DELAY
设置了额外的延迟,可能您的应用程序使用了该设置,因此 H2 不会立即关闭数据库,或者应用程序不会立即关闭所有连接。
无论如何,当您尝试更新 fly 的 web 应用程序时,Tomcat 会在旧版本卸载之前尝试初始化新版本。如果 H2 在 Web 应用本身的 classpath 中,新版本已经上线但旧版本尚未卸载,新版本将在短时间内无法连接到数据库。
如果您不喜欢它,您可以运行独立的 H2 服务器进程并在您的 Web 应用程序中使用远程连接。
另一种选择是将 H2 移动到 Tomcat 本身的类路径中,并将连接池配置为 server.xml
中的资源,在这种情况下,它不应受到应用程序生命周期的影响。
在这两种情况下,您都不应该使用SHUTDOWN
命令。
更新
对于远程服务器的客户端-服务器连接,这种异常意味着服务器决定关闭数据库,因为没有活动连接。此操作中途不能中断和还原。在此过程中尝试打开与同一数据库的新连接时,它最多等待 1 分钟以完成此过程以再次重新打开数据库。此超时不可配置。
有两种可能的解决方案。
DB_CLOSE_DELAY
设置可以使用以秒为单位的较大值。当所有连接都关闭时,数据库将保持在线指定的秒数。 -1
也可用于设置无限超时。
您可以尝试加快关机过程,但您必须自己弄清楚是什么花费了这么多时间。文件压缩过程默认限制为200毫秒,可能需要更长的时间,但我认为它不应该那么长。也许你有很多临时对象或未提交的数据。也许你有一个非常高的数据库文件碎片。如果不进一步调查,很难说出了什么问题。
【讨论】:
感谢您的回答。在我看来,您正在谈论 Tomcat 服务器内的嵌入式数据库。这不是我们的场景。从我的第一句话中可以看出,我们的 H2 服务器作为自己的进程运行。还是我回答错了? 哦,不知怎的,我在堆栈跟踪中间错过了SessionRemote
。我更新了我的答案(但我也保留了旧文本,它可能对某人有用)。以上是关于JdbcSQLNonTransientConnectionException:数据库可能已在使用中:“等待数据库关闭时间超过 1 分钟”的主要内容,如果未能解决你的问题,请参考以下文章