表“SYS”中的并发更新:h2 数据库在插入多条记录时失败
Posted
技术标签:
【中文标题】表“SYS”中的并发更新:h2 数据库在插入多条记录时失败【英文标题】:Concurrent update in table "SYS": h2 database fails while inserting multiple records 【发布时间】:2018-04-02 14:07:02 【问题描述】:我在使用 h2 数据库 1.4.197 时遇到以下错误。基本上,我会尝试在处理记录后立即更新记录。
我不使用插入,而是使用合并语句,因为我不想重复记录。以下是我的查询:
merge into tableName key(col1,col2) values(?,?,?);
我正在使用最大连接池设置为 100 的连接池,并且通过调试,我发现错误是按随机顺序抛出的。话虽如此,插入第 1000 条记录时首先引发错误。在第二次执行时,它发生了第 554 条记录。
这是我的连接字符串:
jdbc:h2:file:" + DB_NAME + ";MV_STORE=true;MVCC=true;AUTO_SERVER=TRUE
下面是堆栈跟踪。
org.h2.jdbc.JdbcSQLException: General error: "java.lang.RuntimeException: Unexpected code path" [50000-197]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:357)
at org.h2.message.DbException.get(DbException.java:168)
at org.h2.message.DbException.convert(DbException.java:307)
at org.h2.message.DbException.toSQLException(DbException.java:280)
at org.h2.message.TraceObject.logAndConvert(TraceObject.java:357)
at org.h2.jdbc.JdbcPreparedStatement.execute(JdbcPreparedStatement.java:268)
at com.verscend.dxcg.reports.db.h2.QueryHelper.insertOrUpdateTable(QueryHelper.java:20)
at com.verscend.dxcg.audit.AuditLogGenerator.process(AuditLogGenerator.java:22)
at org.apache.camel.component.bean.BeanProcessor.process(BeanProcessor.java:103)
at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:541)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:198)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:120)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:83)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:198)
at org.apache.camel.component.direct.DirectProducer.process(DirectProducer.java:62)
at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:145)
at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:541)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:198)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:120)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:83)
at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:541)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:198)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:198)
at org.apache.camel.component.seda.SedaConsumer.sendToConsumers(SedaConsumer.java:298)
at org.apache.camel.component.seda.SedaConsumer.doRun(SedaConsumer.java:207)
at org.apache.camel.component.seda.SedaConsumer.run(SedaConsumer.java:154)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.RuntimeException: Unexpected code path
at org.h2.message.DbException.throwInternalError(DbException.java:254)
at org.h2.message.DbException.throwInternalError(DbException.java:267)
at org.h2.engine.Session.unlockAll(Session.java:985)
at org.h2.engine.Session.endTransaction(Session.java:760)
at org.h2.engine.Session.commit(Session.java:708)
at org.h2.command.Command.stop(Command.java:157)
at org.h2.command.CommandContainer.stop(CommandContainer.java:122)
at org.h2.command.Command.executeUpdate(Command.java:296)
at org.h2.jdbc.JdbcPreparedStatement.execute(JdbcPreparedStatement.java:249)
... 23 more
org.h2.jdbc.JdbcSQLException: Concurrent update in table "SYS": another transaction has updated or deleted the same row [90131-197]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:357)
at org.h2.message.DbException.get(DbException.java:179)
at org.h2.message.DbException.get(DbException.java:155)
at org.h2.table.RegularTable.removeRow(RegularTable.java:375)
at org.h2.engine.Database.removeMeta(Database.java:985)
at org.h2.engine.Database.updateMeta(Database.java:1698)
at org.h2.command.ddl.Analyze.analyzeTable(Analyze.java:136)
at org.h2.engine.Session.commit(Session.java:701)
at org.h2.command.Command.stop(Command.java:157)
at org.h2.command.CommandContainer.stop(CommandContainer.java:122)
at org.h2.command.Command.executeUpdate(Command.java:296)
at org.h2.jdbc.JdbcPreparedStatement.execute(JdbcPreparedStatement.java:249)
at com.verscend.dxcg.reports.db.h2.QueryHelper.insertOrUpdateTable(QueryHelper.java:20)
at com.verscend.dxcg.audit.AuditLogGenerator.process(AuditLogGenerator.java:22)
at org.apache.camel.component.bean.BeanProcessor.process(BeanProcessor.java:103)
at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:541)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:198)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:120)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:83)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:198)
at org.apache.camel.component.direct.DirectProducer.process(DirectProducer.java:62)
at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:145)
at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:541)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:198)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:120)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:83)
at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:541)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:198)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:198)
at org.apache.camel.component.seda.SedaConsumer.sendToConsumers(SedaConsumer.java:298)
at org.apache.camel.component.seda.SedaConsumer.doRun(SedaConsumer.java:207)
at org.apache.camel.component.seda.SedaConsumer.run(SedaConsumer.java:154)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:748)
` 我在这里想念什么?
【问题讨论】:
我遇到了类似的问题。你找到解决办法了吗? 我在使用相同版本 (1.4.197) 时遇到了同样的问题,我使用的是单个数据库连接,我使用单个重复使用的 PreparedStatement 插入大量记录。插入使用标准的插入 SQL 语句。 【参考方案1】:我找到了解决此问题的临时解决方法:
如果在插入记录时抛出异常(大约每 5-10.000 条记录发生一次,看似随机),线程等待 10 毫秒,然后重试插入记录。如果重试也失败,则向上传播异常,并且不插入记录。
到目前为止,等待和重试似乎给了数据库足够的时间来解锁有问题的记录。
【讨论】:
以上是关于表“SYS”中的并发更新:h2 数据库在插入多条记录时失败的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot 2.x 实践记:H2 Database
Spring Boot 2.x 实践记:H2 Database
将MYSQL某一数据库中的多条记录批量插入到另一MYSQL数据库时,记录不存在则插入,存在则更新