在多线程环境中使用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)
然后,我们甚至在EJB调用之间添加了随机线程休眠(10-25秒)。执行成功三次(全部50个EJB调用) 当我们第四次触发时,它失败并出现上述错误。
即使线程数为25,我们也会看到上述失败。
失败是随机的,似乎没有模式。如果我们错过任何配置,请告诉我们。
如果您需要任何其他信息,请与我们联系。在此先感谢您的帮助。
技术堆栈:
1)Java 1.6
2)h2-1.3.176
3)管理数据库连接打开和关闭的红杉中间件。
-Variable Connection Pool Manager
-init pool size 250
答案 0 :(得分:1)
感谢Lance Java提出的建议。由于以下原因,增加堆栈大小在我们的场景中没有帮助(即额外的堆栈仅帮助少数几次执行)。
最终我们的应用程序创建了超过30K的线程,因此导致了Stackoverflow错误。
在设置事务属性后,线程在数据库执行后被杀死,然后所有事务仅由25-30个线程管理。
问题现已解决。
答案 1 :(得分:0)
堆栈溢出错误的两个主要原因
查看堆栈跟踪,它看起来不会递归,所以我猜测你的空间不足。您是否为JVM设置了-Xss
标志?您可能需要增加此值。