【问题标题】:Timeout error trying to lock table in h2尝试在 h2 中锁定表的超时错误
【发布时间】:2011-05-08 22:24:09
【问题描述】:

在某种情况下出现以下错误

当不同的线程通过批量上传操作填充大量用户时,我试图在不同的网页上查看所有用户的列表。列表查询会引发以下超时错误。有没有办法设置这个超时,这样我就可以避免这个超时错误。

环境:h2(最新),Hibernate 3.3.x

Caused by: org.h2.jdbc.JdbcSQLException: Timeout trying to lock table "USER"; SQL statement:

[50200-144]

    at org.h2.message.DbException.getJdbcSQLException(DbException.java:327)
    at org.h2.message.DbException.get(DbException.java:167)
    at org.h2.message.DbException.get(DbException.java:144)
    at org.h2.table.RegularTable.doLock(RegularTable.java:482)
    at org.h2.table.RegularTable.lock(RegularTable.java:416)
    at org.h2.table.TableFilter.lock(TableFilter.java:139)
    at org.h2.command.dml.Select.queryWithoutCache(Select.java:571)
    at org.h2.command.dml.Query.query(Query.java:257)
    at org.h2.command.dml.Query.query(Query.java:227)
    at org.h2.command.CommandContainer.query(CommandContainer.java:78)
    at org.h2.command.Command.executeQuery(Command.java:132)
    at org.h2.server.TcpServerThread.process(TcpServerThread.java:278)
    at org.h2.server.TcpServerThread.run(TcpServerThread.java:137)
    at java.lang.Thread.run(Thread.java:619)
    at org.h2.engine.SessionRemote.done(SessionRemote.java:543)
    at org.h2.command.CommandRemote.executeQuery(CommandRemote.java:152)
    at org.h2.jdbc.JdbcPreparedStatement.executeQuery(JdbcPreparedStatement.java:96)
    at org.jboss.resource.adapter.jdbc.WrappedPreparedStatement.executeQuery(WrappedPreparedStatement.java:342)
    at org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:208)
    at org.hibernate.loader.Loader.getResultSet(Loader.java:1808)
    at org.hibernate.loader.Loader.doQuery(Loader.java:697)
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:259)
    at org.hibernate.loader.Loader.doList(Loader.java:2228)
    ... 125 more

【问题讨论】:

    标签: h2


    【解决方案1】:

    是的,you can change the lock timeout。默认值相对较低:1 秒(1000 毫秒)。

    很多情况下问题是另一个连接锁了表,使用多版本并发也能解决问题(在数据库 URL 后追加;MVCC=true)。

    编辑:MVCC=true 参数不再受支持,因为h2 1.4.200 对于默认引擎的 MVStore 引擎来说总是如此。

    【讨论】:

    • 我确实在驱动程序 URL 上设置了超时,但我仍然收到相同的错误,因为上述操作可能需要大约 30 秒才能完成。我只是不希望使用此页面的其他用户在此期间看到崩溃。这是否意味着我必须将超时设置为超过 30 秒才能避免这个问题?如果超时设置为很大,我将如何发现特定于性能的问题
    • 使用参数“MVCC=true”是解决方案,更改超时并不能解决此问题。
    • @BryanHunt yes MVCC=true 也可以解决问题,我已经更新了我的答案。然而,问题是锁定超时,并且在许多情况下增加锁定超时也是一种解决方案。如果它不是您的用例的解决方案,那没关系,但问题根本不包括用例,所以这真的取决于。
    • @ThomasMueller 我在 H2 DB 上遇到了同样的问题,我在 connectionurl 中尝试了 MVCC=true 但没有帮助
    • @Sen 否,因为对相同行的并发修改被拒绝(只有一个事务会成功)
    【解决方案2】:

    我遇到了同样的问题,使用参数“MVCC=true”,它解决了。您可以在此处的 H2 文档中找到有关此参数的更多说明:http://www.h2database.com/html/advanced.html#mvcc

    【讨论】:

    • 这个是正确答案,改锁超时不是解决办法。
    • @BryanHunt 这真的取决于。您只能说它不是您用例的解决方案。
    • @ThomasMueller 如果我们使用“MVCC=true”有什么缺点吗?
    • @RoshanWijesena 是的,MVCC 模式在 H2 版本 1.3.x(使用 PageStore)中没有得到很好的测试。然而,它是 1.4.x 版本的默认模式(使用 MVStore)。
    • 我使用的是 H2 DB 1.4.x,默认情况下 MVCC=true。但我仍然收到错误
    【解决方案3】:

    对于那些在集成测试中遇到此问题的人(即服务器正在访问 h2 数据库,并且集成测试在调用服务器之前访问数据库以准备测试),在测试之前执行的脚本中添加一个“提交”在调用服务器之前确保数据在数据库中(没有 MVCC=true - 如果默认情况下未启用,我觉得有点“奇怪”)。

    【讨论】:

      【解决方案4】:

      我想建议,如果您遇到此错误,那么也许您不应该在批量数据库操作中使用事务。考虑改为对每个单独的更新进行事务处理:将整个批量导入视为事务处理是否有意义?可能不是。如果是这样,那么是的,MVCC=true 或更大的锁定超时是一个合理的解决方案。

      但是,我认为在大多数情况下,您看到此错误是因为您正在尝试执行一个非常长的事务 - 换句话说,您不知道您正在执行一个非常长的事务。对我自己来说当然就是这种情况,我只是更加注意我是如何编写记录的(不使用事务或使用较小的事务)并且锁定超时问题得到了解决。

      【讨论】:

        【解决方案5】:

        我在 PlayFramework 上遇到了这个问题

        JPAQueryException 发生:执行查询时出错 models.Page where name = ?: 尝试锁定表“PAGE”时超时

        它以某种无限循环结束,因为我有一个

        @之前

        没有除非导致函数重复调用自身

        @Before(除非="getUser")

        【讨论】:

          【解决方案6】:

          使用 DBUnit、H2 和 Hibernate - 相同的错误,MVCC=true 有帮助,但我仍然会在删除数据后的任何测试中遇到错误。解决这些情况的方法是将实际删除代码包装在事务中:

          Transaction tx = session.beginTransaction();
          ...delete stuff
          tx.commit(); 
          

          【讨论】:

            【解决方案7】:

            我的连接字符串中有 MVCC=true,但上面仍然出现错误。我添加了;DEFAULT_LOCK_TIMEOUT=10000;LOCK_MODE=0,问题解决了

            【讨论】:

            • 听起来很糟糕,因为 H2 数据库 URL 中的“LOCK_MODE=0”表示“使用未提交的读取”。
            【解决方案8】:

            来自 2020 年的用户,请参阅 reference

            基本上,参考说:

            设置当前会话的锁定超时(以毫秒为单位)。此设置的默认值为 1000(一秒)。

            该命令不提交事务,回滚也不影响它。此设置可以附加到数据库 URL:jdbc:h2:./test;LOCK_TIMEOUT=10000

            【讨论】:

              猜你喜欢
              • 2016-12-03
              • 1970-01-01
              • 2012-11-14
              • 1970-01-01
              • 2021-01-12
              • 1970-01-01
              • 2015-07-30
              • 2015-12-10
              相关资源
              最近更新 更多