java - JdbcSQLNonTransientConnectionException:数据库可能已在使用中:“等待数据库关闭时间超过 1 分钟”
问题描述
我们使用 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 在关闭最后一个连接后会关闭数据库。
- 数据库何时关闭?
- 如何控制数据库关闭?
提前谢谢
解决方案
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 Server 进程并在您的 Web 应用程序中使用远程连接。
另一种选择是将 H2 移动到 Tomcat 本身的类路径中,并将连接池配置为 中的资源server.xml
,在这种情况下,它不应受到应用程序生命周期的影响。
在这两种情况下,您都不应该使用该SHUTDOWN
命令。
更新
对于远程服务器的客户端-服务器连接,这种异常意味着服务器决定关闭数据库,因为没有活动连接。此操作中途不能中断和还原。在此过程中尝试打开与同一数据库的新连接时,它最多等待 1 分钟以完成此过程以再次重新打开数据库。此超时不可配置。
有两种可能的解决方案。
DB_CLOSE_DELAY
设置可以在几秒钟内使用一些较大的值。当所有连接都关闭时,数据库将保持在线指定的秒数。-1
也可用于设置无限超时。您可以尝试加快关机过程,但您必须自己弄清楚什么需要这么多时间。文件压缩过程默认限制为200毫秒,可能需要更长的时间,但我认为不应该那么长。也许您有很多临时对象或未提交的数据。也许你有一个非常高的数据库文件碎片。如果没有进一步调查,很难说出了什么问题。
推荐阅读
- excel - 基于下拉列表数字选择隐藏/显示行
- c# - 如何使用 Active Directory 中的信息填充文本字段?
- visual-studio - pyspark 中不存在 hadoop 路径的输入路径
- jasper-reports - 如何在 Jasper 报告生成的 RTF 中将两个文本字段合并为一个框?
- reactjs - Webpack 3 - 未找到模块:错误:无法解析“”
- android - 如何防止 CoordinatorLayout 中的自定义 View 拦截其他 View 的行为
- html - Wordpress - 子菜单显示错误
- python - 有没有办法可以为列表中的同一支球队加分?
- android - 使用 cordova-plugin-ionic-webview 版本冲突?
- hasura - 仅当变量不为空时,如何应用 Hasura `where` 过滤器?