关闭H2的正确方法是啥?

Posted

技术标签:

【中文标题】关闭H2的正确方法是啥?【英文标题】:What is the proper way to close H2?关闭H2的正确方法是什么? 【发布时间】:2012-04-15 20:58:25 【问题描述】:

这与post有关。 我认为H2 有问题,这意味着它没有正确关闭。 我怀疑这是因为我在关闭 tomcat 时看到 myDB.lock.db 并且进程没有停止。 我使用Tomcat的连接池,数据库的url是:url="jdbc:h2:file:/opt/myOrg/tomcat/webapps/MyApplication/db/myDatabase;SCHEMA=myschema"

来自文档close H2:

通常,当最后一次连接到数据库时,数据库会关闭 关闭.... 默认情况下,数据库在最后一次连接时关闭 已经关闭。但是,如果它从不关闭,则数据库在何时关闭 虚拟机正常退出,使用关机钩子

我不明白我是否做错了什么。 我应该通过命令强制数据库关闭吗?这就是shutdown hook的意思吗? 我在这里做错了什么?

注意: 我在 Google 中找不到如何正确关闭 H2 的示例(除了它在上次连接关闭时自动关闭的声明)。我应该自己打电话给SHUTDOWN吗?这是正确的方法吗? 我已经看到投票结束了这个问题,但我正在调查的示例没有理由或链接

更新: 在 Joonas Pulakka 回答一些额外信息后:

javacore 我得到使用kill -3 我看到了线程:

"H2 Log Writer MYAPPLICATION" J9VMThread:0x08DC6F00, j9thread_t:0x08C9B790,java/lang/Thread:0xE7206CC8,状态:CW,prio=5 3XMTHREADINFO1(本机线程 ID:0xA32,本机 优先级:0x5,本机策略:未知)3XMTHREADINFO2 (本机堆栈地址范围从:0xE5E26000,到:0xE5E67000, 大小:0x41000) 3XMTHREADINFO3 Java 调用栈: java/lang/Object.wait 中的 4XESTACKTRACE(本机方法) 4XESTACKTRACE 在 java/lang/Object.wait(Object.java:196(编译代码)) 4XESTACKTRACE 在 org/h2/store/WriterThread.run(WriterThread.java:102) 4XESTACKTRACE 在 java/lang/Thread.run(Thread.java:736)

3XMTHREADINFO "pool-8-thread-1" J9VMThread:0x087C0200, j9thread_t:0x0840566C, java/lang/Thread:0xE79BFC80, state:P, prio=5 3XMTHREADINFO1(本机线程 ID:0xE1A,本机 优先级:0x5,本机策略:未知)3XMTHREADINFO2 (本机堆栈地址范围从:0xE5F69000,到:0xE5FAA000, 大小:0x41000) 3XMTHREADINFO3 Java 调用栈: sun/misc/Unsafe.park 的 4XESTACKTRACE(本机方法) 4XESTACKTRACE 在 java/util/concurrent/locks/LockSupport.park(LockSupport.java:184(已编译 代码)) 4XESTACKTRACE 在 java/util/concurrent/locks/AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1998(编译 代码)) 4XESTACKTRACE 在 java/util/concurrent/LinkedBlockingQueue.take(LinkedBlockingQueue.java:413(编译 代码)) 4XESTACKTRACE 在 java/util/concurrent/ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:958(编译 代码)) 4XESTACKTRACE 在 java/util/concurrent/ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918) 4XESTACKTRACE 在 java/lang/Thread.run(Thread.java:736)

3XMTHREADINFO "H2 文件锁看门狗 opt/myOrg/tomcat/webapps/MyApplication/db/myDatabase.lock.db" J9VMThread:0x08DC6900, j9thread_t:0x08C9BA24, ja va/lang/Thread:0xE71E9018,状态:CW,prio=9 3XMTHREADINFO1 (原生线程 ID:0xA30,原生优先级:0x9,原生策略:UNKNOWN) 3XMTHREADINFO2(本机堆栈地址范围从:0xE5DBA000, 到:0xE5DFB000,大小:0x41000)3XMTHREADINFO3 Java 调用堆栈:4XESTACKTRACE 在 java/lang/Thread.sleep(Native Method) 4XESTACKTRACE 在 java/lang/Thread.sleep(Thread.java:851(编译代码)) 4XESTACKTRACE 在 org/h2/store/FileLock.run(FileLock.java:490) 4XESTACKTRACE 在 java/lang/Thread.run(Thread.java:736)

3XMTHREADINFO "FileWatchdog" J9VMThread:0x087C0800, j9thread_t:0x08C9B4FC,java/lang/Thread:0xE715D878,状态:CW,prio=5 3XMTHREADINFO1 (native thread ID:0xA2C, native 优先级:0x5,本机策略:未知)3XMTHREADINFO2 (本机堆栈地址范围从:0xE5E67000,到:0xE5EA8000, 大小:0x41000) 3XMTHREADINFO3 Java 调用栈: 4XESTACKTRACE 在 java/lang/Thread.sleep(本机方法) 4XESTACKTRACE 在 java/lang/Thread.sleep(Thread.java:851(编译代码)) 4XESTACKTRACE 在 org/apache/log4j/helpers/FileWatchdog.run(FileWatchdog.java:104)

【问题讨论】:

Play! not shutting down H2 correctly的可能重复 @MohamedMansour:我已阅读该线程但没有帮助。1)我关闭了 tomcat 而不是应用程序。所以应该没有打开连接 2)答案似乎是一个工作区,我试图了解shutdown 通过来自钩子的 SQL 命令的力量是否实际上是推荐的方法。我无法分辨文档 H2 使用org.h2.engine.DatabaseCloser 的实例为您调用addShutdownHook() 我不明白“我关闭了 tomcat 并且进程没有停止”。这是否意味着 Tomcat 没有正确关闭?在这种情况下,您应该找出 Tomcat 不关闭的原因。 @a_horse_with_no_name:From catalina.out 没有错误。并且在运行过程中使用kill -3 我从ps -ef 看到我看到H2 一些如何处于活动状态。我也看到了db.lockH2。所以我强烈怀疑这是 H2 问题而不是 Tomcat 【参考方案1】:

不,关闭挂钩只是一个在 JVM 终止时运行的线程,无论是从 main() 返回、调用 System.exit(int) 还是抛出异常。只有 JVM 崩溃才能避免它。请参阅 Runtime.addShutdownHook(Thread)。

【讨论】:

我知道什么是关闭挂钩。我不知道这是否是关闭 H2 的正确方法 @Jim:如果你知道什么是shutdown hook,为什么还要问“这就是shutdown hook的意思吗? @a_horse_with_no_name:我的意思是在关闭H2的上下文中。我找不到一个例子来说明我应该自己添加一个钩子 我从这个文档中得到的是关闭钩子是由框架提供的,你不必添加它。【参考方案2】:

文档说虚拟机正常退出时H2 db连接关闭。这就是它的作用。默认情况下,关闭挂钩已经存在,您无需执行任何操作。关闭钩子是关闭只需要在退出时关闭的资源的一种完全有效的方法。

如果你在关机后还有.lock.db文件,那么虚拟机没有正常退出。您写道进程不会停止。您必须找到原因,因为这可能也是阻止 H2 关闭挂钩执行的原因。

对于大型数据库,关闭可能需要一些时间。使用调试器(例如 VisualVM)查看在您调用 (Tomcat) 关闭后哪些线程仍处于活动状态。

还有更多可能:设置文件权限,以便 H2 可以创建锁定文件,但不能删除它们。如果操作系统阻止 H2 删除其锁定文件,则 H2 无能为力。

【讨论】:

谢谢。我试图调查为什么进程没有停止 (***.com/questions/9971876/…),我最终来到了这里。在文件夹中还有rw- 用户权限和r--该组的权限。我需要x 权限才能删除吗? x 只需要执行,不需要删除。但是请检查该目录是否没有设置sticky bit。 不,目录中没有t。并且tomcat正在使用作为文件所有者的用户运行。现在我被卡住了! @Jim:不,你没有被卡住。您刚刚排除了这是权限问题的可能性(即使是权限问题,它也只会解释 .lock.db 文件,而不是为什么进程不会停止。(如果 H2 无法删除文件,那么它不能,但它绝对不会因此而永远阻塞。))。当您调用 Tomcat 关闭时,哪些线程会继续执行某些操作? 我已经对此进行了更新。我还看到一些线程不是我的,但我认为我应该关注我的。我注意到的部分是H2Log4j。其他我不确定的主题【参考方案3】:

不确定这是否与您的情况有关,但您是否尝试过添加 DBStarter 侦听器?

http://www.h2database.com/html/tutorial.html,请参阅“使用 Servlet 侦听器启动和停止数据库”部分。

该链接建议将以下内容添加到 web.xml:

<listener>
    <listener-class>org.h2.server.web.DbStarter</listener-class>
</listener>

请在此处查看讨论(诚然,从 2008 年开始,因此可能已经过时) - 显然该修复适用于嵌入式和非嵌入式实例:http://groups.google.com/group/h2-database/browse_thread/thread/eb609d58c96f4317

或者,您如何使用连接?您确定您正在正确清理连接吗?

我之前遇到过问题,在我的情况下,我使用的是与 JPA EntityManager 的连接,但我忘记在使用后关闭 EntityManager 实例,这导致了一些问题:

@PersistenceUnit(unitName="myEm")
private EntityManagerFactory emf;

public void doStuff() 
    EntityManager em = emf.createEntityManager();
    ...
    em.close(); // forgot this line

【讨论】:

【参考方案4】:

可以执行SHUTDOWN语句,然后关闭连接。

SHUTDOWN 命令将使 H2 立即释放与连接相关的所有资源。例如,这将允许您在重新部署 Web 应用程序时摆脱嵌入式 H2 数据库。

【讨论】:

【参考方案5】:

通过查看DbStarter.contextDestroyed() 的代码(感谢Allan5 的answer),下面是可以工作的代码:

connection.createStatement().execute("SHUTDOWN");

所以Aaron Digulla 的answer 是正确的(即使不是完全“复制/粘贴”)。

此外,如果您已经使用server = Server.createTcpServer("-tcpAllowOthers") 启动了 H2 TCP 服务器,您可以简单地使用server.stop() 停止它。

【讨论】:

以上是关于关闭H2的正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

关闭和清理 Socket 连接的正确方法是啥?

命名类的正确方法是啥? [关闭]

呈现和关闭模式小部件流的正确方法是啥?

在java的exec上关闭流的正确方法是啥?

使用 .NET 数据集的正确方法是啥? [关闭]

使用 PHP 自动安排作业的正确方法是啥 [关闭]