Java 在类层次结构中使用注入的EntityManager
以下代码起作用:Java 在类层次结构中使用注入的EntityManager,java,jpa,jakarta-ee,ejb-3.0,jta,Java,Jpa,Jakarta Ee,Ejb 3.0,Jta,以下代码起作用: @Stateless @LocalBean public class MyClass { @PersistenceContext(name = "MyPU") EntityManager em; public void myBusinessMethod(MyEntity e) { em.persist(e); } } 但是下面的层次结构在Glassfish 3.0(以及带有Ecl
@Stateless
@LocalBean
public class MyClass
{
@PersistenceContext(name = "MyPU")
EntityManager em;
public void myBusinessMethod(MyEntity e)
{
em.persist(e);
}
}
但是下面的层次结构在Glassfish 3.0(以及带有EclipseLink的标准JPA注释)的persist
行中给出了TransactionRequiredException
@Stateless
@LocalBean
public class MyClass extends MyBaseClass
{
public void myBusinessMethod(MyEntity e)
{
super.update(e);
}
}
public abstract class MyBaseClass
{
@PersistenceContext(name = "MyPU")
EntityManager em;
public void update(Object e)
{
em.persist(e);
}
}
对于我的EJB,我在一个抽象类中收集公共代码,以获得更干净的代码。(update
还保存了谁执行了操作以及我的所有实体何时实现了一个接口。)
这个问题不是致命的,我可以简单地将update
和姐妹方法复制到子类中,但我希望将它们放在一个地方
我没有尝试,但这可能是因为我的基类是抽象的,但我想为这样一个(IMHO common)用例学习一个合适的方法 好的,您不能注入到一个超类中,所以您必须注入到实际EJB的一个字段或方法中。你可以这样做:
public class MyBaseEJB {
public abstract EntityManager getEM();
public void update(Object e) {
getEM().persist(e);
}
}
@Stateless
public class MyEJB extends MyBaseEJB {
@PersistenceContext
EntityManager em;
public EntityManager getEM() { return em;}
}
更新:我错了,根据JavaEE5平台规范的第5.2.3节,允许在超类字段和方法中进行注入
我更进一步,使用类似的代码GlassFishV3和EclipseLink在我这边做了一个小测试,我无法重现您的问题。因此,我怀疑您的persistence.xml
存在某种问题。你能提供吗?您使用的是交易类型=“JTA”
?以防万一,我用的是:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence persistence_2_0.xsd" version="2.0">
<persistence-unit name="MyPU" transaction-type="JTA">
<!-- EclipseLink -->
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/q2484443</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
<property name="eclipselink.ddl-generation.output-mode" value="database"/>
</properties>
</persistence-unit>
</persistence>
org.eclipse.persistence.jpa.PersistenceProvider
jdbc/q2484443
假的
顺便说一句,我认为对于简单的数据访问操作,跳过DAO模式是非常好的。看看。你的方法没有错(如果可行的话)
但是,更常见的是使用(注入)Dao并在其上调用方法,或者如果Dao是一个仅包装EntityManager
的冗余层,则可以直接调用EntityManager
上的方法。当然,通过受保护的getter向子类公开EntityManager
getEntityManager().persist(e);
问题不是使用超类的注入实体管理器,而是调用另一个EJB的方法:例如
@Stateless
@LocalBean
public class MyBean extends MySuperBean
{
@EJB
com.example.project.MyOtherBean otherBean;
public boolean myService(String userName, MyEntity entity)
{
if(otherBean.checkAuthority(userName))
{
super.insert(entity);
}
}
}
当OtherBean
不是bean,checkAuthority
是使用(非JTA)EntityManagerFactory
的静态方法时,我使用了这个模式。然后我改变了OtherBean
来扩展MySuperBean
。我认为,在这种情况下,当OtherBean
结束checkAuthority
时,JTA结束事务,MySuperBean
的insert
无法找到要持久化的事务。可以理解,无状态EJB不允许其他EJB继续事务
作为Pascal,我最初认为注入不适用于继承,但当我在子类中直接调用em.persist()
时,这个问题仍然存在。在此之后,我终于能够检查其他可能的原因
谢谢大家的意见 超类的insert、update和delete做了一些额外的工作,而不仅仅是调用它们,因此我不想在子类中重复我自己。我知道可以通过监听器实现这一点,但我让我的所有实体实现了一个接口,并让它们具有特定的字段。然后,基类可以在insert/update/delete和persist entities中填充这些额外字段。问题不在于持久性,而在于我对EJB事务语义缺乏理解。非常感谢。@Emre正如我所写,您的代码运行良好(至少是您显示的部分)。换句话说,超级类中的注入就是有效的。不要在托管上下文中使用
EntityManagerFactory
,而是使用EntityManager
注入。