关闭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.lock
的 H2
。所以我强烈怀疑这是 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 关闭时,哪些线程会继续执行某些操作?
我已经对此进行了更新。我还看到一些线程不是我的,但我认为我应该关注我的。我注意到的部分是H2
和Log4j
。其他我不确定的主题【参考方案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的正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章