设计通用CRUD会话Bean [英] Design Generic CRUD Session Bean

查看:148
本文介绍了设计通用CRUD会话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();


问题:


$ 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 语句,它工作正常。任何想法为什么?

解决方案


  1. EJB容器实际上会创建一个基于代理的接口实现包装您的bean并添加事务和安全检查等。然后将该代理注入到注释字段中,这就是为什么它需要接口类型。我认为在EJB 3.1中,可以省略接口并且只有一个bean类,容器将创建一个子类来实现它的魔力。
  2. javax.ejb .Remote 是一个EJB 3.0注释,而 java.rmi.Remote 是一个从EJB存在之前的普通接口。没有 javax.rmi.Remote 。如果你没有使用 Remote 注释,那么默认情况下,EJB将被认为只有一个本地接口。

  3. 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?

解决方案

  1. 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.
  2. javax.ejb.Remote is an EJB 3.0 annotation, while java.rmi.Remote is a plain interface from before EJBs existed. There is no javax.rmi.Remote. And you are right, if you do not use the Remote annotation, then by default the EJB will be considered to have only a local interface.
  3. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆