从RESTEasy服务正确使用EntityManager是什么? (SEAM,JBoss)

时间:2011-10-20 08:49:40

标签: jboss persistence seam resteasy entitymanager

我的项目是一个用seam-gen生成的WAR项目。它包含一个像这样的RESTEasy Web服务类(简化,只有相关部分):

@Scope(ScopeType.APPLICATION)
public abstract class RestService {

    @In
    protected EntityManager entityManager;

    @GET
    @POST
    @Produces("application/json")
    public Object proxy() {
        // invokes various subclass methods
        // based on request parameters
        // and returns the result
    }
    // further method and logic
}

@Path("/my")
@Name("myRestService")
public class MyRestService extends RestService {

    public Object login(/*...*/) {
        User user = getUser(email);

        // ...

        Token token = user.getToken();
        if (token != null) {
            entityManager.remove(token);
        }
        token = new Token();
        entityManager.persist(token);
        user.setToken(token);
        user.setLastlogin(new Date());
        entityManager.persist(user);

        // ...
    }

    private User getUser(String email) {
        try {
            return (User) entityManager
                    .createQuery("FROM User WHERE UPPER(email) = UPPER(:email)")
                    .setParameter("email", email)
                    .getSingleResult();
        } catch (NoResultException e) {
            return null;
        }
    }
}

如果我通过Web浏览器调用login方法,它会找到正确的用户(基于get参数),为它实例化一个Token(我可以在Hibernate的STDOUT上看到数据库的下一个序列),但是persist()方法不会将令牌保存到数据库中,也不会将User对象的修改(令牌ID,上次登录日期)保存。

我已经用Google搜索了两天,这是我能想到的:

  • 我的项目使用SEAM托管事务(components.xml):

    <persistence:managed-persistence-context name="entityManager" auto-create="true"
                       persistence-unit-jndi-name="java:/MyEntityManagerFactory"/>
    
  • 我的项目使用JTA进行事务处理(persistence.xml):

    <persistence-unit name="MyProject" transaction-type="JTA">
        <provider>org.hibernate.ejb.HibernatePersistence</provider> ...
    
  • EntityManager.persist()不提交对数据库的更改,只是将更改排队到当前事务(?)

  • SEAM托管交易默认情况下与对话相关联

我尝试使用.flush(),抛出异常,说没有正在进行的事务。

我尝试使用.joinTransaction()和.getTransaction()。begin(),抛出另一个异常,说JTA EntityManager无法访问事务。

还试图在类上使用不同的范围类型,或者在我的login()方法上使用@Transactional注释,没有运气。

还尝试使用@PersistenceContext注释注入EntityManager,这导致了一个异常,即@PersistenceContext只能与会话bean一起使用。

还试图将我的班级标记为@Stateless,这导致我无法联系到我的服务(404)。

如何使用EntityManager将我的实体保留在RESTEasy服务中?

系统规格:

  • JBoss 5.1.0 GA
  • SEAM 2.2.1 Final
  • Postgres 8.3

请注意,我对JavaEE / JBoss / SEAM完全没有经验。

任何评论都会有用!感谢。

2 个答案:

答案 0 :(得分:1)

您正在分离托管字段:

entityManager.remove(token);

创建一个新的:

token = new Token();

但是在这里:

entityManager.persist(token);

Token与User有关系(我不知道那个关系是什么 - oneToMany,oneToOne,你是从用户级联,获取等),但只是在令牌上调用persist不会重新建立这种关系。 看看这里 http://www.objectdb.com/java/jpa/persistence/crud

答案 1 :(得分:0)

事务性注释在登录方法中很重要。这将确保事务拦截器在必要时创建事务。 (如果还没有交易)。找出是否应用拦截器的最简单方法是调试登录方法并检查堆栈。我不确定如何调用该课程,但我会在工作时立即更新这篇文章。 如果此拦截器不存在则意味着您没有使用seam事务。 components.xml的摘录未显示您这样做。

马丁

更新: 所以这是堆栈跟踪。如果你的堆栈中没有这个,那么请看一下TransactionInterceptor,你没有事务管理。

Daemon Thread [http-18081-1] (Suspended (breakpoint at line 170 in QueryHome))  
    QueryHome.getCandidatesCount() line: 170    
    NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]  
    NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39  
    DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25  
    Method.invoke(Object, Object...) line: 597  
    Reflections.invoke(Method, Object, Object...) line: 22  
    RootInvocationContext.proceed() line: 32    
    SeamInvocationContext.proceed() line: 56    
    RollbackInterceptor.aroundInvoke(InvocationContext) line: 28    
    SeamInvocationContext.proceed() line: 68    
    BijectionInterceptor.aroundInvoke(InvocationContext) line: 77   
    SeamInvocationContext.proceed() line: 68    
    ConversationInterceptor.aroundInvoke(InvocationContext) line: 65    
    SeamInvocationContext.proceed() line: 68    
    TransactionInterceptor$1.work() line: 97    
    TransactionInterceptor$1(Work<T>).workInTransaction() line: 61  
    TransactionInterceptor.aroundInvoke(InvocationContext) line: 91 
    SeamInvocationContext.proceed() line: 68    
    MethodContextInterceptor.aroundInvoke(InvocationContext) line: 44   
    SeamInvocationContext.proceed() line: 68    
    JavaBeanInterceptor(RootInterceptor).invoke(InvocationContext, EventType) line: 107 
    JavaBeanInterceptor.interceptInvocation(Method, Object[]) line: 185 
    JavaBeanInterceptor.invoke(Object, Method, Method, Object[]) line: 103