设计通用CRUD会话Bean [英] Design Generic CRUD Session Bean
问题描述
这个问题曾经在这里提过一次 EJB 3 Session Bean Design for简单的CRUD ,我只想更深入地询问关于此设计的问题。我已经试着在原帖中提问,但是,我没有看到任何回复,所以我决定创建新帖子。因此Pascal实现通用CRUD会话bean的解决方案如下:
$ public $ GenericCrudService {
public< T> T创建(T t);
public< T> T find(Class< T> type,Object id);
public< T> void delete(T t);
public< T> T更新(T t);
public List findWithNamedQuery(String queryName);
public List findWithNamedQuery(String queryName,int resultLimit);
public List findWithNamedQuery(String namedQueryName,
Map< String,Object> parameters);
public List findWithNamedQuery(String namedQueryName,
Map< String,Object>参数,
int resultLimit);
public< T>列表与LT; T> findWithNativeQuery(String sql,Class< T>类型);
AND
<$ p
$ @ b $ b @Remote(GenericCrudService.class)
@TransactionAttribute(TransactionAttributeType.MANDATORY)
public class GenericCrudServiceBean实现GenericCrudService {
@PersistenceContext
私人EntityManager em;
@Override
public< T> T创建(T t){
em.persist(t);
return t;
}
@Override
public< T> T find(Class< T> type,Object id){
return em.find(type,id);
}
@Override
public< T> void delete(T t){
t = em.merge(t);
em.remove(t);
}
@Override
public< T> T update(T t){
return em.merge(t);
}
@Override
public List findWithNamedQuery(String queryName){
return em.createNamedQuery(queryName).getResultList();
$ b @Override
public List findWithNamedQuery(String queryName,int resultLimit){
return em.createNamedQuery(queryName).setMaxResults(resultLimit)
.getResultList();
$ b @Override
public List findWithNamedQuery(String namedQueryName,
Map< String,Object> parameters){
return findWithNamedQuery(namedQueryName,parameters, 0);
$ b @Override
public List findWithNamedQuery(String namedQueryName,
Map< String,Object>参数,
int resultLimit){
Query query = this.em.createNamedQuery(namedQueryName);
if(resultLimit> 0){
query.setMaxResults(resultLimit); (Map.Entry< String,Object> entry:parameters.entrySet()){
query.setParameter(entry.getKey(),entry.getValue());
。
}
返回query.getResultList();
}
@Override
@SuppressWarnings(unchecked)
public< T>列表与LT; T> findWithNativeQuery(String sql,Class< T> type){
return em.createNativeQuery(sql,type).getResultList();
问题: 1)当我试图在托管bean中引用这个EJB bean时,我必须这样做:
$ b
@EJB
private GenericCrudService myEJB;
而不是
@EJB
private GenericCrudServiceBean myEJB;
自从 GenericCrudService
只是一个接口, GenericCrudServiceBean
是无状态Bean
当我做 GenericCrudServiceBean
,
原因:javax.naming.NamingException:'java:comp /env/com.bridgeye.web.Profile/myEJB'in SerialContext [myEnv = {java.naming.factory.initial = com.sun.enterprise.naming.impl.SerialInitContextFactory,java.naming.factory.state = com.sun .corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl,java.naming.factory.url.pkgs = com.sun.enterprise.naming} [根异常是javax.naming.NamingException:异常解析Ejb for'Remote ejb-ref name = com.bridgeye.web.Profile / myEJB,Remote 3.x interface = com.bridgeye.ejb.GenericCRUDServiceBean,ejb-link = null,lookup =,mappedName =,jndi-name = com.bridgeye.ejb.GenericCRUDServiceBean, refType = Session'。用于查找的实际(可能是内部的)远程JNDI名称是'com.bridgeye.ejb.GenericCRUDServiceBean#com.bridgeye.ejb.GenericCRUDServiceBean'[根异常是javax.naming.NamingException:查找失败'com.bridgeye.ejb.GenericCRUDServiceBean #com.bridgeye.ejb.GenericCRUDServiceBean'in SerialContext [myEnv = {java.naming.factory.initial = com.sun.enterprise.naming.impl.SerialInitContextFactory,java.naming.factory.state = com.sun.corba.ee .impl.presentation.rmi.JNDIStateFactoryImpl,java.naming.factory.url.pkgs = com.sun.enterprise.naming} [根异常是javax.naming.NameNotFoundException:com.bridgeye.ejb.GenericCRUDServiceBean#com.bridgeye.ejb .GenericCRUDServiceBean not found]]]
at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:518)
at com.sun.enterprise.naming.impl.SerialContext.lookup (SerialContext.java:455)在javax.naming.InitialContext.lookup中的
(InitialContext.java:392)在javax.naming.InitialContext.lookup中的
(InitialContext.java :392)
at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl._inject(InjectionManagerImpl.java:597)
2)javax.rmi.Remote和javax.ejb.Remote有什么不同?如果我拿出注释Remote,我的EJB变成本地的,还是必须用注解指定Local
<3>在我的托管bean中,我执行一个简单的
myEJB.find(User.class,id)
,但如果我有 @TransactionAttribute(TransactionAttributeType.MANDATORY)
,那么我会遇到异常,如果我拿出 TransactionAttribute
语句,它工作正常。任何想法为什么?
- EJB容器实际上会创建一个基于代理的接口实现包装您的bean并添加事务和安全检查等。然后将该代理注入到注释字段中,这就是为什么它需要接口类型。我认为在EJB 3.1中,可以省略接口并且只有一个bean类,容器将创建一个子类来实现它的魔力。
javax.ejb .Remote
是一个EJB 3.0注释,而java.rmi.Remote
是一个从EJB存在之前的普通接口。没有javax.rmi.Remote
。如果你没有使用Remote 注释,那么默认情况下,EJB将被认为只有一个本地接口。
从TransactionAttributeType.MANDATORY
的API文档:
如果客户端调用企业
bean的方法,而客户端是与事务上下文相关的
,则
容器将在客户端的
事务上下文中调用企业
的bean方法。
如果没有现有的交易,
将抛出异常。
您可能想要使用
TransactionAttributeType.REQUIRED
,如果没有参数,它会自动启动一个事务,如果您使用没有参数的注释,它也是默认值。
This question has been asked once here EJB 3 Session Bean Design for Simple CRUD, and I just want to ask more in depth questions about this design. I already tried to ask the questions at the original post, however, I did not see any respond, so I decide to create new post. So Pascal solution of implement generic CRUD session bean is as follow
public interface GenericCrudService {
public <T> T create(T t);
public <T> T find(Class<T> type, Object id);
public <T> void delete(T t);
public <T> T update(T t);
public List findWithNamedQuery(String queryName);
public List findWithNamedQuery(String queryName, int resultLimit);
public List findWithNamedQuery(String namedQueryName,
Map<String, Object> parameters);
public List findWithNamedQuery(String namedQueryName,
Map<String, Object> parameters,
int resultLimit);
public <T> List<T> findWithNativeQuery(String sql, Class<T> type);
}
AND
@Stateless
@Remote(GenericCrudService.class)
@TransactionAttribute(TransactionAttributeType.MANDATORY)
public class GenericCrudServiceBean implements GenericCrudService {
@PersistenceContext
private EntityManager em;
@Override
public <T> T create(T t) {
em.persist(t);
return t;
}
@Override
public <T> T find(Class<T> type, Object id) {
return em.find(type, id);
}
@Override
public <T> void delete(T t) {
t = em.merge(t);
em.remove(t);
}
@Override
public <T> T update(T t) {
return em.merge(t);
}
@Override
public List findWithNamedQuery(String queryName) {
return em.createNamedQuery(queryName).getResultList();
}
@Override
public List findWithNamedQuery(String queryName, int resultLimit) {
return em.createNamedQuery(queryName).setMaxResults(resultLimit)
.getResultList();
}
@Override
public List findWithNamedQuery(String namedQueryName,
Map<String, Object> parameters) {
return findWithNamedQuery(namedQueryName, parameters, 0);
}
@Override
public List findWithNamedQuery(String namedQueryName,
Map<String, Object> parameters,
int resultLimit) {
Query query = this.em.createNamedQuery(namedQueryName);
if(resultLimit > 0) {
query.setMaxResults(resultLimit);
}
for (Map.Entry<String, Object> entry : parameters.entrySet()) {
query.setParameter(entry.getKey(), entry.getValue());
}
return query.getResultList();
}
@Override
@SuppressWarnings("unchecked")
public <T> List<T> findWithNativeQuery(String sql, Class<T> type) {
return em.createNativeQuery(sql, type).getResultList();
}
}
Questions:
1) When I try to reference this EJB bean in my managed bean, I have to do
@EJB
private GenericCrudService myEJB;
instead of
@EJB
private GenericCrudServiceBean myEJB;
This make little sense to me since GenericCrudService
is just an interface, GenericCrudServiceBean
is the Stateless Bean
I get this exception when I do GenericCrudServiceBean
,
Caused by: javax.naming.NamingException: Lookup failed for 'java:comp/env/com.bridgeye.web.Profile/myEJB' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming} [Root exception is javax.naming.NamingException: Exception resolving Ejb for 'Remote ejb-ref name=com.bridgeye.web.Profile/myEJB,Remote 3.x interface =com.bridgeye.ejb.GenericCRUDServiceBean,ejb-link=null,lookup=,mappedName=,jndi-name=com.bridgeye.ejb.GenericCRUDServiceBean,refType=Session' . Actual (possibly internal) Remote JNDI name used for lookup is 'com.bridgeye.ejb.GenericCRUDServiceBean#com.bridgeye.ejb.GenericCRUDServiceBean' [Root exception is javax.naming.NamingException: Lookup failed for 'com.bridgeye.ejb.GenericCRUDServiceBean#com.bridgeye.ejb.GenericCRUDServiceBean' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming} [Root exception is javax.naming.NameNotFoundException: com.bridgeye.ejb.GenericCRUDServiceBean#com.bridgeye.ejb.GenericCRUDServiceBean not found]]]
at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:518)
at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:455)
at javax.naming.InitialContext.lookup(InitialContext.java:392)
at javax.naming.InitialContext.lookup(InitialContext.java:392)
at com.sun.enterprise.container.common.impl.util.InjectionManagerImpl._inject(InjectionManagerImpl.java:597)
2) what is the different between javax.rmi.Remote and javax.ejb.Remote? If I took out annotation Remote, does my EJB become local or I have to specify with annotation Local
3) In my managed bean, I do a simple myEJB.find(User.class, id)
, but if I have @TransactionAttribute(TransactionAttributeType.MANDATORY)
, then I run into exception, it work fine if I took out TransactionAttribute
statement. Any idea why?
- The EJB container will actually create a proxy-based implementation of the interface that wraps your bean and adds things like transactions and security checks. This proxy is then injected into the annotated field, which is why it needs to have the interface type. I think in EJB 3.1, you can omit the interface and have only a bean class, and the container will create a subclass to implement its magic.
javax.ejb.Remote
is an EJB 3.0 annotation, whilejava.rmi.Remote
is a plain interface from before EJBs existed. There is nojavax.rmi.Remote
. And you are right, if you do not use theRemote
annotation, then by default the EJB will be considered to have only a local interface.From the API doc of
TransactionAttributeType.MANDATORY
:If a client invokes the enterprise bean's method while the client is associated with a transaction context, the container invokes the enterprise bean's method in the client's transaction context.
If there is no existing transaction, an exception is thrown.
You probably want to use
TransactionAttributeType.REQUIRED
, which automatically starts a transaction if none is present and is also the default if you use the annotation without a parameter.
这篇关于设计通用CRUD会话Bean的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!