我一直在努力解决这个问题几天,我找不到一个我很满意的解决方案。我可以通过各种程度的间接来解决这个问题,但这似乎是我应该做的事情,虽然我找到了一些可能有我问题的其他人,但他们似乎没有一个确切的问题。问题或没有提供答案。
虽然我之前使用Hibernate成功完成了这项工作,但我还是无法使用JPA,这正是我现在关注的重点。
初步信息:
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似乎不会更改结果。
创建对象的过程如下:
FileContainer
对象并填充它,包括使用我们刚刚检索的对象调用`setMimetype(MIMEType)`dao.save(fileContainer)
,在FileContainer
对象中设置基本字段,然后调用em.persist(Object)
。将其从DAO中拉出并使用先前注入的EntityManager
不会改变结果。此时EntityManager.flush()
发生时(无论发生在何处 - 在事务结束时或之前),INSERT都会发生并且代码会死锁。
当我检查pg_stat_activity
并将其与pg_locks
进行比较时,我看到插入语句被“事务中空闲”连接阻塞,并且它处于等待状态。删除MIMEType的插入(并将列设置为允许空值)允许代码正常进行,并且检查MIMEType的值表明它已被正确检索。
任何想法或想法都表示赞赏。
编辑:
这是层次结构,希望它澄清了操作的顺序和发生的事情:
EntityManager
个对象在所有DAO对象中都是相同的,并且发生了故障。EntityManager
调用或获取injector.getInstance(EntityManager.class)
对象始终获取Provider
个对象。flush()
代码似乎没有任何应该是线程之间共享的线程本地,并且所有内容都是使用注入器进行初始化的,这对我来说是令人困惑的。
答案 0 :(得分:3)
我在这里所说的唯一可能是问题的就是:
系统在失败的情况下适度挑剔:我需要生成一个单独的线程并从那里执行访问。
Guice-Persist工作单元和事务使用ThreadLocal
限定为一个线程。如果你在一个单独的线程上做某事,我肯定能看到类似的事情发生(尽管我不确定究竟是怎么回事)。你能详细解释一下这个单独的线程何时以及如何被使用?从@Transactional
方法内部?它是否使用在原始线程上注入的EntityManager
?
编辑:嗯......我没看到你在做什么有什么问题。似乎工作和事务都在一个线程上完成。不知道那里发生了什么。
答案 1 :(得分:2)
我发现了问题。
在代码的其他地方,我有一个不相关但正在进行的事务,该事务正在@Before
方法中启动。出于某种原因,EntityManager
阻止该交易完成。当所有内容都在同一个线程中并且用于某些只读操作时,这不是问题,但是当它被拆分成一个单独的线程并尝试写入时,它开始等待另一个事务处理,这在时间上没有完成交易和触及许多相同的表。