java - H2 使用线程时内存数据库不一致

标签 java swing thread-safety h2

我已经在这个问题上思考了几个小时,并且完全不知道发生了什么。

基本上,我在 ExecutorService 线程池中运行 Swing Worker 任务,并传递内存中的 H2 数据库来测试一些数据库交互。发生的情况是,当需要先插入快照时,我有时会因为将 SnapshotFV 插入数据库而出现引用完整性错误。

现在,如果我在执行线程之前中断,我可以检查数据库并查看数据库中确实存在快照行,但是如果我在产生问题的行的 doInBackground 方法中中断,则该行不存在即使数据源对象具有与以前相同的对象 ID,数据库中的值也会更长。 H2 数据库似乎在链中的某个时刻重置了。很难说,但似乎不一定每次调试时都会发生,但每次运行时肯定会发生。

如果我将线程池设置为 1,没有问题。

在调试过程中,我检查了所有对象 ID,以确保没有发生任何奇怪的事情,比如将某些内容设置为 null 或其他内容。数据源和快照ID相同

    ExecutorService taskExecutor = Executors.newFixedThreadPool(8);

    for (File f : files) {
         FVGatherer task = new FVGatherer(f, dataSource, snapshot);
         taskExecutor.execute(task);
    }

    taskExecutor.shutdown();
    try {
        taskExecutor.awaitTermination(60, TimeUnit.MINUTES);
    } catch (InterruptedException e) {
        ...
    }


    ...


    private static class FVGatherer extends SwingWorker<Void, Void> {
        private final File f;
        private final XDataSource dataSource;
        private final Snapshot snapshot;

        ...
        constructor
        ...

        @Override
        protected Void doInBackground() throws Exception {
            FV fv = getFV(f, dataSource);
            FI fi = getFI(f, dataSource);

            if (fv != null && fi != null) {
                SnapshotFV sfv = dataSource.createSnapshotFV(snapshot, fv, fi);
                snapshotFVs.add(sfv);
            }

            progressIncrementer.run();
            return null;
        }

错误:

13:25:20.021 [pool-4-thread-1] ERROR JdbcUtilities - catching org.h2.jdbc.JdbcSQLException: Referential integrity constraint violation: "FK_SNAPSHOTFV: PUBLIC.SNAPSHOTFV FOREIGN KEY(SNAPSHOT_ID) REFERENCES PUBLIC.SNAPSHOT(ID) (1)"; SQL statement: insert into SNAPSHOTFV (SNAPSHOT_ID, FV_ID, FI_ID) values (?, ?, ?) [23506-175]

有什么想法吗?

编辑

我刚刚注意到的另一个细节。 getFV 和 getFI 还将对象插入数据库,如果我将线程池设置为 > 1,那么它们似乎也不会出现在 doInBackground 方法中的数据库中。再次将线程池设置为 1 并在同一位置中断,FV、FI 和快照将出现在数据库中。这些方法是否会导致某些未报告的异常或问题导致无效并因此重置内存数据库?如果需要,我可以发布这些方法的代码。

编辑2

上线失败:

SnapshotFV sfv = dataSource.createSnapshotFV(snapshot, fv, fi);

堆栈跟踪:

at org.h2.message.DbException.getJdbcSQLException(DbException.java:332) ~[h2-1.3.175.jar:1.3.175]
at org.h2.message.DbException.get(DbException.java:172) ~[h2-1.3.175.jar:1.3.175]
at org.h2.message.DbException.get(DbException.java:149) ~[h2-1.3.175.jar:1.3.175]
at org.h2.constraint.ConstraintReferential.checkRowOwnTable(ConstraintReferential.java:368) ~[h2-1.3.175.jar:1.3.175]
at org.h2.constraint.ConstraintReferential.checkRow(ConstraintReferential.java:310) ~[h2-1.3.175.jar:1.3.175]
at org.h2.table.Table.fireConstraints(Table.java:894) ~[h2-1.3.175.jar:1.3.175]
at org.h2.table.Table.fireAfterRow(Table.java:911) ~[h2-1.3.175.jar:1.3.175]
at org.h2.command.dml.Insert.insertRows(Insert.java:162) ~[h2-1.3.175.jar:1.3.175]
at org.h2.command.dml.Insert.update(Insert.java:115) ~[h2-1.3.175.jar:1.3.175]
at org.h2.command.CommandContainer.update(CommandContainer.java:79) ~[h2-1.3.175.jar:1.3.175]
at org.h2.command.Command.executeUpdate(Command.java:253) ~[h2-1.3.175.jar:1.3.175]
at org.h2.jdbc.JdbcPreparedStatement.executeUpdateInternal(JdbcPreparedStatement.java:154) ~[h2-1.3.175.jar:1.3.175]
at org.h2.jdbc.JdbcPreparedStatement.executeUpdate(JdbcPreparedStatement.java:140) ~[h2-1.3.175.jar:1.3.175]
at org.apache.commons.dbcp2.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:98) ~[commons-dbcp2-2.1.jar:2.1]
at org.apache.commons.dbcp2.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:98) ~[commons-dbcp2-2.1.jar:2.1]
at data.sources.JdbcUtilities.insertItem(JdbcUtilities.java:92) [bin/:?]
at data.sources.SnapshotFVSource.create(SnapshotFVSource.java:61) [bin/:?]
at data.PooledDataSource.createSnapshotFV(PooledDataSource.java:347) [bin/:?]
at util.SnapshotVersionUtil$FVGatherer.doInBackground(SnapshotVersionUtil.java:262) [bin/:?]
at util.SnapshotVersionUtil$FVGatherer.doInBackground(SnapshotVersionUtil.java:1) [bin/:?]
at javax.swing.SwingWorker$1.call(Unknown Source) [?:1.8.0_60]
at java.util.concurrent.FutureTask.run(Unknown Source) [?:1.8.0_60]
at javax.swing.SwingWorker.run(Unknown Source) [?:1.8.0_60]
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [?:1.8.0_60]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [?:1.8.0_60]
at java.lang.Thread.run(Unknown Source) [?:1.8.0_60]

编辑3

这个问题似乎只在我使用内存数据库时存在。物理磁盘数据库似乎可以工作。嗯...

最佳答案

对此我仍然没有满意的答案,但我只能得出结论:H2 的内存数据库不是线程安全的,而磁盘数据库是线程安全的。

关于java - H2 使用线程时内存数据库不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33305785/

相关文章:

java - 如何从 zipgroupfileset 中排除?

c# - 共享资源锁

c# - 复制前锁定整个字典或部分字典 (SyncRoot)

.NET - Queue.Enqueue 方法线程安全吗?

Java 条件配置 (web.xml) - 开发/生产

java - 使用java的Sqoop失败

java - 属性值的组合

swing - NetBeans GUI 生成器找不到 SwingX 类

java - JTable-调整行大小时调整行标题大小

java - 如何在主 JFrame 后面打开 JFrame