Как правильно использовать EntityManager из службы RESTEasy? (SEAM, JBoss)

Мой проект - это проект WAR, созданный с помощью seam-gen. Он содержит такой класс веб-службы RESTEasy (упрощенно, только соответствующие части):

@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;
        }
    }
}

Если я вызываю метод входа в систему через веб-браузер, он находит правильного пользователя (на основе параметров get), создает для него токен (я вижу в STDOUT Hibernate, запрашивающего базу данных для следующей последовательности), но сохраняется () не сохраняет токен в базе данных, ни модификации объекта User (идентификатор токена, дата последнего входа в систему).

Я гуглил это уже два дня, вот что я мог выяснить:

  • мой проект использует управляемые транзакции 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 не может получить доступ к транзакциям.

Также пытался использовать разные типы области в классе или использовать аннотацию @Transactional в моем методе login (), не повезло.

Также попытался внедрить EntityManager с аннотацией @PersistenceContext, это привело к исключению, в котором говорилось, что @PersistenceContext можно использовать только с сессионными компонентами.

Также попытался пометить мой класс как @Stateless, в результате я не смог связаться со своим сервисом (404).

Как мне сохранить свои объекты в службе RESTEasy с помощью EntityManager?

Системные характеристики:

  • JBoss 5.1.0 GA
  • ШОВ 2.2.1 Финал
  • Postgres 8.3

Обратите внимание, что я совершенно новичок и не знаком с JavaEE / JBoss / SEAM.

Любой комментарий был бы полезен! Спасибо.


person Istvan    schedule 20.10.2011    source источник


Ответы (2)


Аннотации транзакций важны для метода входа в систему. Это гарантирует, что перехватчик транзакции создает транзакцию, если необходимо. (если транзакции еще нет). Самый простой способ узнать, применяется ли перехватчик, - это отладить метод входа в систему и проверить стек. Я не уверен, как называется класс, но я обновлю этот пост, как только буду на работе, чтобы проверить его. Если этого перехватчика нет, значит, вы не используете стыковочные транзакции. Экстракт вашего 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  
person Martin Frey    schedule 26.10.2011
comment
Я только что понял, что вы пишете, что используете Seam 2. С другой стороны, вы используете @Produces, который является CDI? Я не уверен, совместимы ли эти две технологии? Наверное, кто-нибудь может намекнуть? - person Martin Frey; 26.10.2011
comment
@Transactional был решением, но мне нужно было поместить его в метод прокси, а не в login (). Спасибо! - person Istvan; 26.11.2011

Вы отключаете управляемое поле:

entityManager.remove(token);

Создание нового:

token = new Token();

Но здесь:

entityManager.persist(token);

Токен имеет связь с пользователем (я не знаю, что это за отношения - oneToMany, oneToOne, вы каскадируете от пользователя?, Извлекаете и т. Д.), Но простой вызов сохранения на токене не восстанавливает эту связь. Взгляните сюда http://www.objectdb.com/java/jpa/persistence/crud

person gebuh    schedule 25.10.2011