Transações em EJB

9 respostas
kleins

Fala galera.

Seguinte.

Estou implementando uma classe que pega uma tarefa e executa, durante esta execução, ela atualiza a tabela no banco e eu leio essas informações para mostrar na tela o progresso.

A questão é que não estou conseguindo mostrar na tela pois aparentemente tudo esta sendo executado em uma mesma transação, inclusive o laço (while)…

Enquanto o while não termina, o banco não é atualizado… e eu preciso que a cada loop do while, a base seja atualizada.

O cabeçalho do EJB…

@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
public class TaskFacade extends AbstractFacade<Task> implements TaskFacadeLocal {

Vocês podem notar que a transação eu abro em outro metodo.

public Task execute(Task task) {

        int check = 0;
        int amount = task.getTaamount();
        int time2check = 10;
        int steps = amount / time2check;

        int i = 0;
        while( i < task.getTaamount() ){

            if(executeTransaction(task) == true){
                i++;
                updateTaskDone(i, task);
            }else{
                i = task.getTaamount();
            }
        }
        task.setTadatefinish( new Date());
        task.setTastatus(Short.valueOf("3"));
        em.merge(task);
        return task;
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public boolean executeTransaction(Task task) {
        try {
            String serial;
            if(task.getTaseed() == null){
                serial = SerializationFactory.getSerialization("DEFAULT").getSerializedString(task.getTasize());
            }else{
                serial = SerializationFactory.getSerialization("DEFAULT").getSerializedString(task.getTasize(), task.getTaseed());
            }
            int tcode = codeFacade.countCodeBySerial(task.getCompany().getIdcompany(), serial);
            if(tcode == 0){
                Code c = new Code();
                c.setCompany(task.getCompany());
                c.setTask(task);
                c.setCodate( new Date());
                c.setCostatus( Short.valueOf("1"));
                c.setCoserial(serial);
                codeFacade.create(c);
            }else{
                System.out.println("Serial já existe!!!");
            }
            return true;
        } catch (Exception e) {
            System.out.println("Erro no EJB do task - transaction");
            e.printStackTrace();
            context.setRollbackOnly();
            System.out.println(e.getMessage()+" "+e.getLocalizedMessage());
            return false;
        }
    }

Alguma dica?

Obrigado por qualquer ajuda.

Abs

9 Respostas

CintiaDR

kleins,

Eu NÃO uso EJB, mas uso Spring que tem esse conceito de controle de transação por anotações e talz.

Na época que eu tive este problema, eu fiz uma nova classe só para possuir o método (no seu caso) ‘executeTransaction(Task task)’ com ‘requires_new’, vou chamar aqui de ‘TaskFacadeAux’.

Mas o segredo era que eu NÃO podia injetar diretamente assim:

@Resource ("taskFacadeAux")
private TaskFacadeAux blabla;

Eu precisava acessar de outra forma, que no caso do Spring tinha de ser pelo factory assim:

TaskFacadeAux  blabla = (TaskFacadeAux) beanFactory.getBean("taskFacadeAux");
blabla.executeTransaction(whatevah);
kleins

Olá CintiaDR,

Muito obrigado pela dica!
Fiz a alteração mas o comportamento foi o mesmo... :shock:

Um abs

@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
public class TaskAuxFacade implements TaskAuxFacadeLocal {

    @Resource
    private EJBContext context;

    @EJB
    private CodeFacadeLocal codeFacade;

    @EJB
    private CompanyEJBLocal companyEJB;

    @EJB
    private UnitFacadeLocal unitFacade;

    // Add business logic below. (Right-click in editor and choose
    // "Insert Code > Add Business Method")

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public boolean executeTransaction(Task task) {

        try {
            String serial;
            if(task.getTaseed() == null){
                serial = SerializationFactory.getSerialization("DEFAULT").getSerializedString(task.getTasize());
            }else{
                serial = SerializationFactory.getSerialization("DEFAULT").getSerializedString(task.getTasize(), task.getTaseed());
            }
            int tcode = codeFacade.countCodeBySerial(task.getCompany().getIdcompany(), serial);
            if(tcode == 0){
                Code c = new Code();
                c.setCompany(task.getCompany());
                c.setTask(task);
                c.setCodate( new Date());
                c.setCostatus( Short.valueOf("1"));
                c.setCoserial(serial);
                codeFacade.create(c);
                Unit u = new Unit();
                u.setUncreateddate(new Date());
                u.setCompany(task.getCompany());
                u.setCode(c);
                u.setLine(task.getLine());
                u.setUnstatus(Short.valueOf("1"));
                u.setUnstore(Short.valueOf("1"));
                //em.persist(u);
                unitFacade.create(u);
            }else{
                System.out.println("Serial já existe!!!");
            }
            return true;
        } catch (Exception e) {
            System.out.println("Erro no EJB do task - transaction");
            e.printStackTrace();
            context.setRollbackOnly();
            System.out.println(e.getMessage()+" "+e.getLocalizedMessage());
            return false;
        }
    }

}
@Stateless
//@TransactionManagement(TransactionManagementType.CONTAINER)
public class TaskFacade extends AbstractFacade<Task> implements TaskFacadeLocal {

    @EJB
    private TaskAuxFacadeLocal taskAuxFacade;

    @Resource
    private EJBContext context;

    @EJB
    private CodeFacadeLocal codeFacade;

    @EJB
    private CompanyEJBLocal companyEJB;

    @EJB
    private UnitFacadeLocal unitFacade;

    protected EntityManager getEntityManager() {
        return em;
    }

    public TaskFacade() {
        super(Task.class);
    }

    public List<Task> findTaskByCompany(int idcompany) {
        try{
            Company company = companyEJB.findCompanyById(idcompany);
            //Query q = em.createQuery("SELECT t FROM Task t WHERE t.company = :company AND t.tadatefinish is null order by t.tadatecreate desc");
            Query q = em.createQuery("SELECT t FROM Task t WHERE t.company = :company order by t.tadatecreate desc");
            q.setParameter("company", company);
            return q.getResultList();
        }catch(Exception erro){
            return null;
        }
    }

    public List<Task> findLineBySearch(int idcompany, String search) {
        try{
            Company company = companyEJB.findCompanyById(idcompany);
            Query q = em.createQuery("SELECT t FROM Task t WHERE t.company = :company AND t.tadatefinish is null AND t.tacode like '%"+search+"%' or t.taseed like '%"+search+"%' or t.line.liname like '%"+search+"%' order by t.tadatecreate desc");
            q.setParameter("company", company);
            return q.getResultList();
        }catch(Exception erro){
            return null;
        }
    }

    public boolean updateTaskDone(int countDone, Task task) {
        try {
            task.setTadone(countDone);
            em.merge(task);
            return true;
        } catch (Exception e) {
            return false;
        }
        
    }
    
    public Task execute(Task task) {

        int check = 0;
        int amount = task.getTaamount();
        int time2check = 10;
        int steps = amount / time2check;

        int i = 0;
        while( i < task.getTaamount() ){

            //taskAuxFacade.executeTransaction(task);

            if(taskAuxFacade.executeTransaction(task) == true){
                i++;
                updateTaskDone(i, task);
            }else{
                i = task.getTaamount();
            }
        }
        task.setTadatefinish( new Date());
        task.setTastatus(Short.valueOf("3"));
        em.merge(task);
        return task;
    }
    
    
    //@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public boolean executeTransaction(Task task) {
        
        try {
            String serial;
            if(task.getTaseed() == null){
                serial = SerializationFactory.getSerialization("DEFAULT").getSerializedString(task.getTasize());
            }else{
                serial = SerializationFactory.getSerialization("DEFAULT").getSerializedString(task.getTasize(), task.getTaseed());
            }
            int tcode = codeFacade.countCodeBySerial(task.getCompany().getIdcompany(), serial);
            if(tcode == 0){
                Code c = new Code();
                c.setCompany(task.getCompany());
                c.setTask(task);
                c.setCodate( new Date());
                c.setCostatus( Short.valueOf("1"));
                c.setCoserial(serial);
                codeFacade.create(c);
                Unit u = new Unit();
                u.setUncreateddate(new Date());
                u.setCompany(task.getCompany());
                u.setCode(c);
                u.setLine(task.getLine());
                u.setUnstatus(Short.valueOf("1"));
                u.setUnstore(Short.valueOf("1"));
                //em.persist(u);
                unitFacade.create(u);
                
            }else{
                System.out.println("Serial já existe!!!");
            }
            return true;
        } catch (Exception e) {
            System.out.println("Erro no EJB do task - transaction");
            e.printStackTrace();
            //context.setRollbackOnly();
            System.out.println(e.getMessage()+" "+e.getLocalizedMessage());
            return false;
        }
    }



}
CintiaDR

Então, se eu fizesse assim:

@Stateless
//@TransactionManagement(TransactionManagementType.CONTAINER)
public class TaskFacade extends AbstractFacade&lt;Task&gt; implements TaskFacadeLocal {

    @EJB
    private TaskAuxFacadeLocal taskAuxFacade;


    //BLABLABLABLA
}

também não funcionava aqui. Eu tinha que fazer algo como:

@Stateless
//@TransactionManagement(TransactionManagementType.CONTAINER)
public class TaskFacade extends AbstractFacade&lt;Task&gt; implements TaskFacadeLocal {

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) 
public Task execute(Task task) { 
     (...)
     while( i &lt; task.getTaamount() ){  
  
            TaskAuxFacade taskAuxFacade = (TaskAuxFacade) beanFactory.getBean("taskAuxFacade");  // ISTO É SPRING rs
  
            if(taskAuxFacade.executeTransaction(task) == true){  
                i++;  
                updateTaskDone(i, task);  
            }else{  
                i = task.getTaamount();  
            }  
        }  
      (...)
}


}
johnny_quest

Você está utilizando um Bean sem informações de estado e sem usar JTA.

Logo o escopo da transação só termina quando termina o método chamado do Bean.

Para resolver o seu problema você deve utilizar JTA, definindo o começo da transação e o final dela,
usando o javax.transaction.UserTransaction definindo o begin( ) e o commit( ). Com isso você terá o controle da Transação.

A

Cara, não sei se ajuda, mas vale como alternativa.

Dentro do While você pode força o commit executando um flush.

em.flush();

Tenta ai …

[]'s

kleins

hehehe…

Nem fazendo lookup esta funcionando…
Agora a tarnsação esta apenas na classe auxiliar que é um EJB… e nada…

:idea: ?

:smiley:

public Task execute(Task task) {

        int check = 0;
        int amount = task.getTaamount();
        int time2check = 10;
        int steps = amount / time2check;

        int i = 0;
        while( i < task.getTaamount() ){

            TaskAuxFacadeLocal taskAuxFacade = lookupTaskAuxFacadeLocal();

            //taskAuxFacade.executeTransaction(task);

            if(taskAuxFacade.executeTransaction(task) == true){
                i++;
                updateTaskDone(i, task);
            }else{
                i = task.getTaamount();
            }
        }
        task.setTadatefinish( new Date());
        task.setTastatus(Short.valueOf("3"));
        em.merge(task);
        return task;
    }

private TaskAuxFacadeLocal lookupTaskAuxFacadeLocal() {
        try {
            Context c = new InitialContext();
            return (TaskAuxFacadeLocal) c.lookup("java:global/eatt/eatt-ejb/TaskAuxFacade!br.com.t2software.database.TaskAuxFacadeLocal");
        } catch (NamingException ne) {
            Logger.getLogger(getClass().getName()).log(Level.SEVERE, "exception caught", ne);
            throw new RuntimeException(ne);
        }
    }
kleins

Valeu Alex,

Nem assim… :shock:

alex.brito:
Cara, não sei se ajuda, mas vale como alternativa.

Dentro do While você pode força o commit executando um flush.

em.flush();

Tenta ai …

[]'s

CintiaDR

Realmente, o ‘flush’ NÃO atualiza o banco. Ele força exceções e etc, algumas vezes pode ser bem útil.

Puxa, que pena que não funcionou, disso extrapolamos que spring não é igual EJB rs.

Fazer o controle da transação na mão (open, commit, etc) pode ser uma possibilidade, mas é algo que eu realmente não tinha interesse em fazer.

kleins

Fala Jhony,

Mesmo controlando a transação pelo container?

<persistence-unit name="eatt-ejbPU" transaction-type="JTA">

Tentei como vc falou, mas pelo jeito eu teria que trocar o tipo de transação para resource_local, certo? Pra mim não é viavel.

Deu esta exception.
Caused by: javax.persistence.TransactionRequiredException

Valeuu

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */


 */
@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class TaskFacade extends AbstractFacade<Task> implements TaskFacadeLocal {

    //@EJB
    //private TaskAuxFacadeLocal taskAuxFacade;

    @Resource
    private EJBContext context;

    @Resource
    private UserTransaction ut;

    @EJB
    private CodeFacadeLocal codeFacade;

    @EJB
    private CompanyEJBLocal companyEJB;

    @EJB
    private UnitFacadeLocal unitFacade;

    protected EntityManager getEntityManager() {
        return em;
    }

    public TaskFacade() {
        super(Task.class);
    }

    
    public Task execute(Task task) {

        int check = 0;
        int amount = task.getTaamount();
        int time2check = 10;
        int steps = amount / time2check;

        int i = 0;
        while( i < task.getTaamount() ){

            

            //taskAuxFacade.executeTransaction(task);

            if(executeTransaction(task) == true){
                i++;
                updateTaskDone(i, task);
            }else{
                i = task.getTaamount();
            }
        }
        task.setTadatefinish( new Date());
        task.setTastatus(Short.valueOf("3"));
        em.merge(task);
        return task;
    }
    
    
    //@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public boolean executeTransaction(Task task) {
        
        try {
            ut.begin();
            String serial;
            if(task.getTaseed() == null){
                serial = SerializationFactory.getSerialization("DEFAULT").getSerializedString(task.getTasize());
            }else{
                serial = SerializationFactory.getSerialization("DEFAULT").getSerializedString(task.getTasize(), task.getTaseed());
            }
            int tcode = codeFacade.countCodeBySerial(task.getCompany().getIdcompany(), serial);
            if(tcode == 0){
                Code c = new Code();
                c.setCompany(task.getCompany());
                c.setTask(task);
                c.setCodate( new Date());
                c.setCostatus( Short.valueOf("1"));
                c.setCoserial(serial);
                codeFacade.create(c);
                Unit u = new Unit();
                u.setUncreateddate(new Date());
                u.setCompany(task.getCompany());
                u.setCode(c);
                u.setLine(task.getLine());
                u.setUnstatus(Short.valueOf("1"));
                u.setUnstore(Short.valueOf("1"));
                //em.persist(u);
                unitFacade.create(u);
                ut.commit();
                em.flush();
            }else{
                System.out.println("Serial já existe!!!");
            }
            return true;
        } catch (Exception e) {
            try {
                System.out.println("Erro no EJB do task - transaction");
                e.printStackTrace();
                //context.setRollbackOnly();
                ut.rollback();
                System.out.println(e.getMessage() + " " + e.getLocalizedMessage());

            } catch (IllegalStateException ex) {
                Logger.getLogger(TaskFacade.class.getName()).log(Level.SEVERE, null, ex);
            } catch (SecurityException ex) {
                Logger.getLogger(TaskFacade.class.getName()).log(Level.SEVERE, null, ex);
            } catch (SystemException ex) {
                Logger.getLogger(TaskFacade.class.getName()).log(Level.SEVERE, null, ex);
            }
            return false;
        }
    }



}

Abs

johnny quest:
Você está utilizando um Bean sem informações de estado e sem usar JTA.

Logo o escopo da transação só termina quando termina o método chamado do Bean.

Para resolver o seu problema você deve utilizar JTA, definindo o começo da transação e o final dela,
usando o javax.transaction.UserTransaction definindo o begin( ) e o commit( ). Com isso você terá o controle da Transação.

Criado 10 de agosto de 2011
Ultima resposta 11 de ago. de 2011
Respostas 9
Participantes 4