两个实体管理器的 HSQL 死锁

Posted

技术标签:

【中文标题】两个实体管理器的 HSQL 死锁【英文标题】:Deadlock on HSQL with two entity managers 【发布时间】:2017-01-13 14:44:41 【问题描述】:

我有两个实体管理器(必须保持原样)。我正在使用内存数据库进行单元测试。当我运行测试时,我发现了以下问题。

在这个简单的例子中:

  emFirst.createNativeQuery("select * from schema1.table").getResultList();

  emSecond.createNativeQuery("create table schema2.table (id int)").executeUpdate();

将 HSQL 从 2.3.2 升级到 2.3.4 后陷入死锁

为了让它再次工作,我必须将每个语句包装在事务中。

你知道我怎样才能在不使用下面的情况下让它工作吗?

    getTransaction().begin();
    emFirst.createNativeQuery("select * from schema1.table").getResultList();
    getTransaction().commit();

    getTransaction().begin();         
    emSecond.createNativeQuery("create table schema2.table (id int)").executeUpdate();
    getTransaction().commit();

我使用的是 Hibernate 4.3.6

这里是死锁的堆转储:

> "main" #1 prio=5 os_prio=0 tid=0x00007f7be0015000 nid=0x3b29 waiting
> on condition [0x00007f7be8584000]    java.lang.Thread.State: WAITING
> (parking)     at sun.misc.Unsafe.park(Native Method)
>   - parking to wait for  <0x000000073635b3d0> (a org.hsqldb.lib.CountUpDownLatch$Sync)    at
> java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)     at
> java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
>   at
> java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:997)
>   at
> java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1304)
>   at org.hsqldb.lib.CountUpDownLatch.await(Unknown Source)    at
> org.hsqldb.Session.executeCompiledStatement(Unknown Source)   at
> org.hsqldb.Session.execute(Unknown Source)
>   - locked <0x000000073635b298> (a org.hsqldb.Session)    at org.hsqldb.jdbc.JDBCPreparedStatement.fetchResult(Unknown Source)    at
> org.hsqldb.jdbc.JDBCPreparedStatement.executeUpdate(Unknown Source)
>   - locked <0x00000007363a92f8> (a org.hsqldb.jdbc.JDBCPreparedStatement)     at
> com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:147)
>   at
> org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:208)
>   at
> org.hibernate.engine.query.spi.NativeSQLQueryPlan.performExecuteUpdate(NativeSQLQueryPlan.java:211)
>   at
> org.hibernate.internal.SessionImpl.executeNativeUpdate(SessionImpl.java:1310)
>   at
> org.hibernate.internal.SQLQueryImpl.executeUpdate(SQLQueryImpl.java:389)

【问题讨论】:

可能是这个? ***.com/questions/14001558/… 【参考方案1】:

使用 HSQLDB 服务器而不是进程内数据库。

【讨论】:

数据库用于单元测试。因此它应该是内存数据库。我将编辑原帖 您可以使用内存数据库启动服务器。服务器可以从您的应用程序启动。在这种情况下,CREATE 语句将等待 emFirst 提交。 我明白你的意思。但是为什么要等呢?自 HSQL 2.3.2 以来,那里发生了什么变化?为什么现在需要在休眠会话级别提交只读 SELECT? 改变的是 HSQLDB 2.3.4 现在等待所有事务(包括 SELECT)在执行 CREATE TABLE 或任何其他 DDL 语句之前提交。这可能会在下一个版本中改进。

以上是关于两个实体管理器的 HSQL 死锁的主要内容,如果未能解决你的问题,请参考以下文章

入门 jpa--实体管理器的基本应用

使用不同实体管理器的不同捆绑包中的实体中的问题

Java Servlet 过滤器和其他对象和实体管理器的范围

连接 HSQL 数据库管理器时无法从 Java 代码连接到 HSQL 数据库

Symfony 2 从实体管理器获取实体的原始数据

两个实体管理器实例在第一个更新时第二个选择旧值