hibernate - 使用持久引用保留对象时,使用JPA遇到数据库死锁

标签 hibernate postgresql jpa deadlock guice

我已经在这个问题上挣扎了几天,我找不到一个我满意的解决方案。我可能可以通过不同程度的间接处理来解决这个问题,但这似乎是我应该能够做的事情,虽然我已经找到了其他一些可能有我问题的人,但他们似乎都没有确切的问题或没有提供答案。
虽然我以前使用Hibernate成功地做到了这一点,但我还不能让它与JPA一起工作,这正是我现在要做的。
初步信息:
使用持久扩展、hibernate(带注释)和c3p0(最多5个连接)的Guice 3.0应用程序。我们正在从提供程序中注入EntityManager,我可以确认EntityManager对象在整个过程中与transaction对象保持相同。
作为web应用程序的一部分,当前的问题只在使用JUnit和dbUnit的自动化集成测试中出现。访问是针对单例对象(.in(Scopes.singleton))的,但该单例对象仅依赖于注入程序和@Transactional来实现线程安全。
在数据库中,有一个映射到带注释的文件容器的文件表和一个映射到对象mimetype的mimetype表。在应用程序中,当我们创建一个新文件时,我们首先将MIMEType对象作为NamedQuery检索并持久化它。
数据库是PostgreSQL 8.4,使用PostgreSQL-8.4-702.jdbc3.jar。
系统对失败的情况有一定的挑剔:我需要生成一个单独的线程并从那里执行访问。
FileContainer对象中的mimetype字段的映射为:

@ManyToOne(fetch=FetchType.EAGER, cascade={})  
@JoinColumn(name="mimetype_id", referencedColumnName="id", nullable=false, updatable=true)

MIMEType对象的注释如下:
@Entity
@Table(name="mimetypes")  
@org.hibernate.annotations.Immutable  
@Cacheable(true)  
@NamedQuery(name="mt.ext", query="from MIMEType where extension = :ext",  
    hints= {@QueryHint(name="org.hibernate.fetchSize", value="1"),  
            @QueryHint(name="org.hibernate.readOnly", value="true")})

以上所有注释都是javax.persistence版本。
addFile方法用@com.google.inject.persist.Transactional注释。将其更改为在类中使用注入的EntityManager似乎不会更改结果。
创建对象的过程如下:
从注入器中获取EntityManager和FileDAO。它们都来自一个提供者。
通过调用em.createNamedQuery(“mt.ext”,MIMEType.class).setParameter(“ext”,extension).getSingleResult(),从数据库中获取要使用的MIMEType对象;
创建FileContainer对象并填充它,包括使用我们刚刚检索到的对象调用'setMimetype(MIMEType)'
Calldao.save(fileContainer),它在FileContainer对象中设置一个基本字段,然后调用em.persist(Object)。从DAO中取出并使用先前注射的EntityManager不会改变结果。
此时只要EntityManager.flush()发生(无论发生在哪里——在事务结束时或之前),插入就会发生,代码就会死锁。
当我检查pg_stat_activity并将其与pg_locks进行比较时,我看到insert语句被“idle in transaction”连接阻塞,并且处于等待状态。删除MIMEType的插入(并将列设置为允许空)可以使代码正常进行,检查MIMEType的值表示已正确检索到它。
任何想法或想法都是值得赞赏的。
编辑:
这是层次结构,希望它能澄清操作顺序和发生的情况:
测试线束(初始化Injector并使用runner将其注入特定的测试类)
测试用例
线程已启动
从线程中输入singleton对象上的transactional block(使用相同的注入器初始化),确认所有DAO对象中的EntityManager对象都是相同的,并且故障发生在哪里。
EntityManager对象始终是通过调用或获取injector.getInstance(EntityManager.class)对象获得的。
在同一个线程中完成上述过程。
冻结Provider
代码中似乎没有任何应该是线程本地的东西在线程之间共享,并且所有的东西都是用注入器初始化的,这让我很困惑。

最佳答案

从你在这里所说的话中,我唯一能了解到的似乎是问题所在:
系统对失败的情况有一定的挑剔:我需要生成一个单独的线程并从那里执行访问。
Guice持久化工作单元和事务的作用域是使用ThreadLocal的线程。如果你在一个单独的线程上做一些事情,我绝对可以看到类似的事情发生(尽管我不确定具体是如何发生的)。你能更详细地解释一下这个单独的线程是什么时候以及如何使用的吗?从@Transactional方法内部?是不是用了一种注射在原始螺纹上的EntityManager
编辑:嗯。。。我看不出你做的有什么问题。似乎工作和事务都是在一个线程上完成的。不知道发生了什么。

关于hibernate - 使用持久引用保留对象时,使用JPA遇到数据库死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5439014/

相关文章:

java - hibernate 选择。返回对象而不选择所有内容

java - JPQL/HSQL更新有限制吗?

postgresql - 允许冲突的 Postgres 主键

arrays - 如何取消嵌套数组以提供一系列参数?

c# - Dapper 产生不同的结果

java - 使用 JPA 和 Spring 加载选定的 Hibernate 实体

java - 带接口(interface)的 Spring 目录结构(最佳实践)

java - 多个SessionFactory/TransactionManager : no session found for current thread

java - JPA中如何连接多个数据库?

验证错误: Value is not valid