H2-数据库,进程死锁导致访问异常的问题
H2 数据库,进程死锁导致访问异常的问题
问题现象:
H2数据库启动后,Web Server运行正常,能通过9090端口访问,但无法访问数据库。
问题复现:
通过启动脚本重启H2数据库,复现的概率非常高(测试人员反应运行中的H2数据库也会出现连接异常的问题,该场景暂时未复现)。
问题分析:
初步断定是进程死锁导致。根据程序的堆栈信息,也支持这一判断。
对造成死锁的原因进行分析:
1 H2服务器有多种启动方式,我们使用的是Console模式,且全部使用默认参数;这种场景下,H2会按顺序逐次启动WebServer,TcpServer,PgServer。
WebServer能支持用户通过浏览器访问数据库,TcpServer支持Java程序中通过api访问数据库,PgServer支持通过PgAdmin客户端访问数据库。
2 WebServer启动后,会有一个自我检测的环节,也就是创建一个Socket去连接WebServer,来检测WebServer是否已启动;因此,WebServer的第一个
WebThread线程,就是用来处理这个自检请求的,由于自检请求没有携带正常的启动信息,因此会引发异常,进而去执行DbException.traceThowable()函数。
3 与此同时,Main函数会继续启动TcpServer,过程中会加载org.h2.Driver类;如果此时WebThead线程也恰好正在执行Driver的初始化,就会导致
死锁;如果此时WebThread线程已经执行结束并正常退出,那么Main函数就可以正常的启动TcpServer。
这也就可以解释为什么启动失败是偶发事件。
解决方案:
Console模式的启动顺序是:WebServer->OpenBrowser->TcpServer->PgServer;我们的使用场景中,其实不需要启动浏览器和PgServer;另外,WebServer在TcpServer
之前启动,会偶发启动失败的问题,应该是H2的一个bug。
H2同时提供了另一种启动模式——Server模式,该模式中各服务器的启动顺序是:TcpServer->PgServer->WebServer->OpenBrowser;
因此可以通过Server模式来启动,来避免启动失败的问题。
java -cp $H2HOME/h2-1.4.192.jar org.h2.tools.Server -web -webPort 9090 -webAllowOthers -tcp -tcpPort 9092 –tcpAllowOthers