我正在使用Java EE 7.我想知道将JPA EntityManager
注入应用程序范围的 CDI bean 的正确方法是什么.您不能只使用@PersistanceContext
注释注入它,因为EntityManager
实例不是线程安全的.假设我们希望EntityManager
在每个HTTP请求处理的开始时创建我们,并在处理HTTP请求后关闭它们.我想到了两个选择:
1.创建一个请求范围的CDI bean,它具有对a的引用EntityManager
,然后将bean注入到应用程序范围的CDI bean中.
import javax.enterprise.context.RequestScoped;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@RequestScoped
public class RequestScopedBean {
@PersistenceContext
private EntityManager entityManager;
public EntityManager getEntityManager() {
return entityManager;
}
}
Run Code Online (Sandbox Code Playgroud)
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
@ApplicationScoped
public class ApplicationScopedBean {
@Inject
private RequestScopedBean requestScopedBean;
public void persistEntity(Object entity) {
requestScopedBean.getEntityManager().persist(entity);
}
}
Run Code Online (Sandbox Code Playgroud)
在此示例中,EntityManager
将在创建时RequestScopedBean
创建,并在RequestScopedBean
销毁时关闭.现在我可以将注入移动到一些抽象类中以将其从中删除ApplicationScopedBean
.
2.创建一个生成实例的生产者,EntityManager
然后将EntityManager
实例注入到应用程序范围的CDI bean中.
import …
Run Code Online (Sandbox Code Playgroud) 拥有以下相当简单的代码和正确配置的基于JTA的持久化上下文:
abstract class AbstractRepository<E> {
@PersistenceContext
protected EntityManager em;
@Transactional
public synchronized void persist(E entity) {
em.persist(entity);
em.flush();
}
}
@ApplicationScoped
class MyEntityRepository extends AbstractRepository<MyEntity> {
}
Run Code Online (Sandbox Code Playgroud)
我在调用时遇到以下异常MyEntityRepository.persist()
:
2015-06-23T12:34:55.233+0200|Severe: javax.persistence.TransactionRequiredException
at com.sun.enterprise.container.common.impl.EntityManagerWrapper.doTxRequiredCheck(EntityManagerWrapper.java:161)
at com.sun.enterprise.container.common.impl.EntityManagerWrapper.doTransactionScopedTxCheck(EntityManagerWrapper.java:151)
at com.sun.enterprise.container.common.impl.EntityManagerWrapper.persist(EntityManagerWrapper.java:281)
at my.project.AbstractRepository.persist(AbstractRepository.java:28)
at my.project.QuestionnaireRepository.persist(QuestionnaireRepository.java:1)
at my.project.QuestionnaireRepository$Proxy$_$$_WeldClientProxy.persist(Unknown Source)
at my.project.QuestionnaireForm.save(QuestionnaireForm.java:29)
at my.project.QuestionnaireForm.lambda$0(QuestionnaireForm.java:1)
at my.project.QuestionnaireForm$$Lambda$56/1079229220.buttonClick(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:508)
at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:198)
at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:161)
at com.vaadin.server.AbstractClientConnector.fireEvent(AbstractClientConnector.java:977)
at com.vaadin.ui.Button.fireClick(Button.java:393)
at com.vaadin.ui.Button$1.click(Button.java:61)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) …
Run Code Online (Sandbox Code Playgroud) 我想将一个object(ReportBean
)持久化到数据库,但是我收到了错误消息:
javax.persistence.TransactionRequiredException: Transaction is required to perform this operation (either use a transaction or extended persistence context)
Run Code Online (Sandbox Code Playgroud)
这是一些代码:
实体
@Entity
@Table(name="t_report")
@Access(AccessType.FIELD)
public class ReportBean implements Serializable {
// fields (@Column, etc.)
// setters/getters methods
// toString , hashCode, equals methods
}
Run Code Online (Sandbox Code Playgroud)
允许EntityManager注入的自定义注释(带@Inject
)
import javax.inject.Qualifier;
import static java.lang.annotation.ElementType.*;
import java.lang.annotation.Target;
@Qualifier
@Target({TYPE, METHOD, FIELD, PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyEm {
}
Run Code Online (Sandbox Code Playgroud)
EntityManager提供程序
import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
public class EntityManagerProvider { …
Run Code Online (Sandbox Code Playgroud) 我有一个使用容器管理事务的@Stateless
EJB.有没有办法获得"状态" javax.transaction.UserTransaction
?也就是说,调用UserTransaction.getStatus()
bean方法?
我知道UserTransaction
在容器管理的bean中禁止访问,但我想知道,有没有其他方法可以访问getStatus()
方法?
可以使用@PersistenceContext
(或@PersistenceUnit
)将实体管理器(或其工厂)注入jsf托管bean 吗?
我尝试了但没有,我获得了NullPointerException.
问题:在Java EE和EJB的上下文中,任何人都可以显示具有两种不同方法的特定DAO类(或多个).和一个服务类在一个事务边界中调用这两个方法并回滚?
我有一个EJB,但我想将它用作服务层,就像在Spring @Transactional方法中一样.
1)这是个好主意吗?
2)如何在一个方法中的一个"事务"中进行多个dao方法调用?我想我必须在transaction.begin()和.上制定一些策略.COMIT()?任何人都可以展示代码示例吗?
一些主要优点是:
a-所有小的不可变DAO事务将在单个数据库连接中的"一次性"中提交(in single transactional boundries
)
b-如果说我在服务器上有4个dao调用,而第三个调用失败,那么由于它的一个事务边界,我可以这样做roll backs
.
c-我immutable DAO methods
会re-usable
在很多其他地方.
Java EE示例:
import com.....entities.Users;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
@Stateless
public class UsersBean {
// Add business logic below. (Right-click in editor and choose
// "Insert Code > Add Business Method")
public Users sayHello() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("CommunityPU");
EntityManager em = emf.createEntityManager();
Users user = em.find(Users.class, 1);
em.close();
emf.close();
return user;
}
} …
Run Code Online (Sandbox Code Playgroud)