WFLYJPA0060: для выполнения этой операции требуется транзакция (используйте транзакцию или расширенный контекст сохраняемости).

Я потерял много времени, пытаясь решить эту проблему, но я на том же месте. Подозреваю, что перепутал что-то из CDI с EJB.

Проблема сохраняется, и удалить только не работает.

Caused by: javax.persistence.TransactionRequiredException: WFLYJPA0060: Transaction is required to perform this operation (either use a transaction or extended persistence context)
    at org.jboss.as.jpa.container.AbstractEntityManager.transactionIsRequired(AbstractEntityManager.java:866)
    at org.jboss.as.jpa.container.AbstractEntityManager.persist(AbstractEntityManager.java:579)
    at com.oki.scope.console.model.dao.GenericDAO.save(GenericDAO.java:29)
    at com.oki.scope.console.model.dao.GenericConsoleDAO.save(GenericConsoleDAO.java:12)
    at com.oki.scope.console.service.ServidorServiceImp.salvar(ServidorServiceImp.java:27)
    at com.oki.scope.console.service.ServidorServiceImp$Proxy$_$$_WeldClientProxy.salvar(Unknown Source)
    at com.oki.scope.console.managedBean.consulta.ServidorMB.salvar(ServidorMB.java:65)
    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:497)
    at com.sun.el.parser.AstValue.invoke(AstValue.java:292)
    at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:304)
    at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:40)
    at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50)
    at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:40)
    at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50)
    at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105)
    at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:87)
    ... 40 more

Мой ДАО

public class GenericDAO<T, K> {

    protected EntityManager em;
    private Class<T> entityClass;

    public GenericDAO(Class<T> entityClass,  EntityManager em) {
        this.entityClass = entityClass;
        this.em = em;
    }

    @Transactional
    protected void save(T entity) {
        em.persist(entity);
    }

Общий ДАО:

import javax.persistence.EntityManager;

public abstract class GenericConsoleDAO<T, K> extends GenericDAO<T, K> {

     public GenericConsoleDAO(Class<T> entityClass, EntityManager em) {
        super(entityClass, em);
    }

    public void save(T t){
        super.save(t);
    }

}

Фабрика ДАО:

package com.oki.scope.console.model.dao;

import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import javax.ejb.Singleton;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Singleton
@TransactionManagement(TransactionManagementType.CONTAINER)
public class DAOConsoleFactory {
    private final static String UNIT_NAME = "scope-console";

    private static Map<String, Object> mapa = Collections.synchronizedMap(new HashMap<String, Object>());

    @PersistenceContext(unitName = UNIT_NAME )  
    private EntityManager entityManager;

    @Produces public ServidorDAO            criaServidorDAO(){          return getDAO(ServidorDAO.class); }
    @Produces public ConexaobdDAO           criaConexaoDAO(){           return getDAO(ConexaobdDAO.class);      }
    @Produces public ContratoDAO            criaContratoDAO(){          return getDAO(ContratoDAO.class);   }
    @Produces public EmpresaDAO             criaEmpresaDAO(){           return getDAO(EmpresaDAO.class); }
    @Produces public LojaDAO                criaLojaDAO(){              return getDAO(LojaDAO.class);   }
    //@Produces public RedeAutorizadoraDAO  criaRedeAutorizadoraDAO(){  return getDAO(RedeAutorizadoraDAO.class); }
    @Produces public RedeDAO                criaRedeDAO(){              return getDAO(RedeDAO.class);   }
    @Produces public RoteadorDAO            criaRoteadorDAO(){          return getDAO(RoteadorDAO.class);   }
    @Produces public TerminalDAO            criaTerminalDAO(){          return getDAO(TerminalDAO.class);   }
    @Produces public TipoHeaderDAO          criaTipoHeaderDAO(){        return getDAO(TipoHeaderDAO.class);     }

    @SuppressWarnings("unchecked")
    public <E> E getDAO(Class<E> classe){
        String key = classe.getSimpleName();
        if (!mapa.containsKey(key))
        {
            try {
                mapa.put(key, classe.getDeclaredConstructor(EntityManager.class).newInstance(entityManager));
            } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
                    | InvocationTargetException | NoSuchMethodException | SecurityException e) {
                System.out.println("Classe "+ key +" não possui um construtor que tenha EntityManager como parametro.");
            }
        }
        return (E)mapa.get(key);

    }
}

Мои занятия:

@Named
@ApplicationScoped
public class ServidorServiceImp implements ServidorService {

    @Inject private ServidorDAO dao;


    @Override
    public List<Servidor> getLista() {
        return dao.getLista();
    }

    @Override
    public void salvar(Servidor servidor) {
        if (servidor.getId()==0){
            dao.save(servidor);
        }
        else
        {
            dao.update(servidor);
        }
    }

    @Override
    public void remover(Servidor servidor) {
        dao.delete(servidor);

    }

}

person Rogério Marchiori    schedule 18.04.2016    source источник


Ответы (2)


Пытаясь повысить производительность, вы обошли то, что контейнер должен делать за вас, а именно создание экземпляра компонента внутри транзакции.

Я бы посоветовал удалить @Singleton и @TransactionManagement(TransactionManagementType.CONTAINER) из DAOConsoleFactory и разрешить обработку транзакции EJB компонентом EJB, который использует DAO.

ОБНОВЛЕНИЕ: Кроме того, @ApplicationScoped не является аннотацией EJB. Класс ServidorServiceImp должен быть компонентом EJB, поэтому его следует аннотировать с помощью @Stateless или, возможно, @Statefull и удалить @ApplicationScoped. Он читается как bean-компонент EJB без сохранения состояния, поэтому нет необходимости делать его ограниченным приложением.

Опять же, мне кажется, что вы слишком много внимания уделяете попыткам оптимизировать производительность, не имея хорошего понимания того, как EJB должны работать в контейнере. Я бы порекомендовал заставить все работать и следовать лучшим архитектурным практикам, особенно в концепции «Фасад сеанса». Некоторые из этих сообщений могут помочь: Что является точкой фасада в Java EE? или Зачем использовать шаблон Facade для сеансового компонента EJB.

person K.Nicholas    schedule 18.04.2016
comment
Я удалил обе записи. Это доказывает, что @TransactionManagement не использовался. Проблема осталась прежней. - person Rogério Marchiori; 18.04.2016

Решено: До этого 2 дня страданий. Проблема была в моем классе. Где находится @Named @ApplicationScoped, я изменил на @Statefull.

person Rogério Marchiori    schedule 18.04.2016
comment
Привет, приятель, это может звучать грубо, но твои реализации очень плохи. Просто взгляните на эту книгу (realworldpatterns.com), и вы поймете все неправильно используемые шаблоны и стандартный код, который у вас есть, я рекомендую вам главы, связанные с шаблонами DAO и SessionBean и Facade. - person Rene Enriquez; 18.04.2016