【问题标题】:org.h2.jdbc.JdbcSQLException: General error: "java.lang.StackOverflowError" [50000-176]org.h2.jdbc.JdbcSQLException:一般错误:“java.lang.StackOverflowError”[50000-176]
【发布时间】:2016-03-08 15:13:41
【问题描述】:

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

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

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

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

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

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

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

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

当我们再次触发测试类时,我们遇到了“stackoverflowerror”。详细的stacktrace如下所示

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 Invocation 之间添加了一个随机线程休眠(10-25 秒)。执行成功三次(全部 50 个 EJB 调用) 当我们第 4 次触发时,它因上述错误而失败。

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

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

如果您需要任何其他信息,请告诉我。提前感谢您的帮助。

技术栈:

1) Java 1.6

2) h2-1.3.176

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

-Variable Connection Pool Manager 

-init pool size 250

【问题讨论】:

    标签: java jdbc h2


    【解决方案1】:

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

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

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

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

    问题现已解决。

    【讨论】:

      【解决方案2】:

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

      1. 包含非终止递归调用的错误
      2. 为 jvm 分配的堆栈大小不够大

      查看您的堆栈跟踪,它看起来不是递归的,所以我猜您的空间不足。您是否为您的 JVM 设置了 -Xss 标志?您可能需要增加此值。

      【讨论】:

        猜你喜欢
        • 2015-11-12
        • 2015-02-06
        • 1970-01-01
        • 1970-01-01
        • 2014-03-10
        • 1970-01-01
        • 2022-06-22
        • 2020-04-23
        • 2013-05-24
        相关资源
        最近更新 更多