H2在内存数据库中使用线程

时间:2015-10-23 15:12:26

标签: java swing thread-safety h2

我几个小时以来一直坐在这个问题上,对于发生的事情我感到非常难过。

基本上我在ExecutorService线程池中运行Swing Worker任务并传递内存H2数据库来测试一些数据库交互。发生的情况是,当需要首先插入快照时,由于将SnapshotFV插入数据库,我得到参考完整性错误有时

现在,如果我在执行线程之前就中断了,我可以检查数据库,看看数据库中是否存在Snapshot行,但是如果我在生成问题的行上的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;
        }

erorr:

  

13:25:20.021 [pool-4-thread-1] ERROR JdbcUtilities - 捕获   org.h2.jdbc.JdbcSQLException:参照完整性约束违规:   “FK_SNAPSHOTFV:PUBLIC.SNAPSHOTFV FOREIGN KEY(SNAPSHOT_ID)   参考PUBLIC.SNAPSHOT(ID)(1)“; SQL语句:   插入SNAPSHOTFV(SNAPSHOT_ID,FV_ID,FI_ID)值(?,?,?)[23506-175]

有什么想法吗?

修改

我刚注意到的另一个细节。 getFV和getFI也将对象插入到数据库中,如果我有线程池集&gt; 1然后他们似乎也没有出现在doInBackground方法的数据库中。同样,将线程池设置为1并在同一位置中断,并且FV,FI和快照显示在数据库中。可能是这些方法导致某些异常或问题未被报告无效并因此重置内存数据库?如果需要,我可以发布这些方法的代码。

EDIT2

在线失败:

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

这个问题似乎只在我使用内存数据库时才存在。物理光盘数据库似乎有效。嗯...

1 个答案:

答案 0 :(得分:1)

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