org.h2.jdbc.JdbcSQLException:一般错误:“java.lang.StackOverflowError”[50000-176]

时间:2016-03-08 15:13:42

标签: java jdbc h2

在多线程环境中使用H2数据库时出现Stackoverflow错误

我们的应用程序具有服务层查询H2数据库并检索结果集。

服务层使用开源集群中间件“Sequoia”连接到h2数据库(提供负载均衡和 透明故障转移)并且还管理数据库连接。

https://sourceforge.net/projects/sequoiadb/

我们的服务层有50个服务方法,我们将服务方法公开为EJB。在调用EJB时 我们得到服务的响应(包括H2 READ),平均响应时间为0.2秒。

DAO层,使用Hibernate Criteria查询数据库,我们还使用JPA2.0实体管理器来管理数据源。

对于负载测试,我们创建了一个测试类(使用main方法),它调用所有50个EJB方法。

创建了50个线程,所有线程都调用了测试类。第一次运行时执行正常,所有50个线程都完成了 调用50个EJB方法。

当我们再次触发测试类时,我们遇到了“stackoverflower”。详细的堆栈跟踪如下所示

org.h2.jdbc.JdbcSQLException: General error: "java.lang.StackOverflowError" [50000-176]
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:344)
    at org.h2.message.DbException.get(DbException.java:167)
    at org.h2.message.DbException.convert(DbException.java:290)
    at org.h2.server.TcpServerThread.sendError(TcpServerThread.java:222)
    at org.h2.server.TcpServerThread.run(TcpServerThread.java:155)
    at java.lang.Thread.run(Thread.java:784)
Caused by: java.lang.StackOverflowError
    at java.lang.Character.digit(Character.java:4505)
    at java.lang.Integer.parseInt(Integer.java:458)
    at java.lang.Integer.parseInt(Integer.java:510)
    at java.text.MessageFormat.makeFormat(MessageFormat.java:1348)
    at java.text.MessageFormat.applyPattern(MessageFormat.java:469)
    at java.text.MessageFormat.<init>(MessageFormat.java:361)
    at java.text.MessageFormat.format(MessageFormat.java:822)
    at org.h2.message.DbException.translate(DbException.java:92)
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:343)
    at org.h2.message.DbException.get(DbException.java:167)
    at org.h2.message.DbException.convert(DbException.java:290)
    at org.h2.command.Command.executeUpdate(Command.java:262)
    at org.h2.jdbc.JdbcPreparedStatement.execute(JdbcPreparedStatement.java:199)
    at org.h2.server.TcpServer.addConnection(TcpServer.java:140)
    at org.h2.server.TcpServerThread.run(TcpServerThread.java:152)
    ... 1 more

    at org.h2.engine.SessionRemote.done(SessionRemote.java:606)
    at org.h2.engine.SessionRemote.initTransfer(SessionRemote.java:129)
    at org.h2.engine.SessionRemote.connectServer(SessionRemote.java:430)
    at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:311)
    at org.h2.jdbc.JdbcConnection.<init>(JdbcConnection.java:107)
    at org.h2.jdbc.JdbcConnection.<init>(JdbcConnection.java:91)
    at org.h2.Driver.connect(Driver.java:74)
    at org.continuent.sequoia.controller.connection.DriverManager.getConnectionForDriver(DriverManager.java:266)

然后,我们甚至在E​​JB调用之间添加了随机线程休眠(10-25秒)。执行成功三次(全部50个EJB调用) 当我们第四次触发时,它失败并出现上述错误。

即使线程数为25,我们也会看到上述失败。

失败是随机的,似乎没有模式。如果我们错过任何配置,请告诉我们。

如果您需要任何其他信息,请与我们联系。在此先感谢您的帮助。

技术堆栈:

1)Java 1.6

2)h2-1.3.176

3)管理数据库连接打开和关闭的红杉中间件。

-Variable Connection Pool Manager 

-init pool size 250

2 个答案:

答案 0 :(得分:1)

感谢Lance Java提出的建议。由于以下原因,增加堆栈大小在我们的场景中没有帮助(即额外的堆栈仅帮助少数几次执行)。

  • 在我们的应用程序中,我们使用的是实体管理器(JPA),并且未设置事务属性。因此每次查询数据库,创建一个执行执行的线程。在JVisualVm中,我们观察到DB Threads,Live Threads等于Total Threads Started。

最终我们的应用程序创建了超过30K的线程,因此导致了Stackoverflow错误。

在设置事务属性后,线程在数据库执行后被杀死,然后所有事务仅由25-30个线程管理。

问题现已解决。

答案 1 :(得分:0)

堆栈溢出错误的两个主要原因

  1. 包含非终止递归调用的错误
  2. jvm分配的堆栈大小不够大
  3. 查看堆栈跟踪,它看起来不会递归,所以我猜测你的空间不足。您是否为JVM设置了-Xss标志?您可能需要增加此值。