-1
I have a complex problem, but it can be exemplified by the following metaphor::
@Stateless
public interface ChildEJB01 {
salvarGato(Gato g);
}
@Stateless
public interface ChildEJB01 {
salvarCachorro(Cachorro c);
}
@Stateless
public interface ChildEJB01 {
salvarPeriquito(Periquito p);
}
These three Ejbs are used in isolation at various points of my application and work well in isolation. But there’s a certain moment I need to use them together, see:
@Statefull
public class MasterEJB {
@EJB
private ChildEJB01 a;
@EJB
private ChildEJB02 b;
@EJB
private ChildEJB01 c;
public void salvarTudo(){
a.salvarGato();
b.salvarCachorro();
c.salvarPeriquito();
}
}
Now I need to save all at once and I need everything to be saved in the database only if all are saved correctly [transaction].
Only that I have realized that even if one of them gives error what was done previously is saved anyway... How do I create a transaction for this method? (I’m using JTA (managed by Containner)).
My setup: Jboss AS7
editing for a new example using Ricardo’s tips
@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
public class ChildEJB01 implements C01 {
@PersistenceContext
private EntityManager manager;
@WebMethod
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void persist(String a){
Model m = new Model();
m.setDesc(getClass().getCanonicalName());
manager.persist(m);
}
}
@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
public class ChildEJB02 implements C02 {
@PersistenceContext
private EntityManager manager;
@WebMethod
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void persist(String a){
Model m = new Model();
m.setDesc(getClass().getCanonicalName());
manager.persist(m);
}
}
@WebService
@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
public class MasterEJB {
@EJB
private C01 c01;
@EJB
private C02 c02;
@Resource
private SessionContext contexto;
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void persist() {
for (int i = 0; i < 3; i++) {
c01.persist("");
c02.persist("");
if (i == 2) // forcando uma exceção apos 4 inserts
throw new RuntimeException();
}
}
}
SELECT IN THE BANK BEFORE RUNNING THE CODE:
mysql> SELECT * FROM test; Empty set (0.00 sec) mysql>
CONSOLE OUTPUT DURING CODE EXECUTION:
10:26:00,905 INFO [stdout] (http-0.0.0.0-8080-1) Hibernate: Insert into test (description) values (?)
10:26:01,006 INFO [stdout] (http-0.0.0.0-8080-1) Hibernate: Insert into test (description) values (?)
10:26:01,057 INFO [stdout] (http-0.0.0.0-8080-1) Hibernate: Insert into test (description) values (?)
10:26:01,101 INFO [stdout] (http-0.0.0-8080-1) Hibernate: Insert into test (description) values (?)
10:26:01,135 INFO [stdout] (http-0.0.0-8080-1) Hibernate: Insert into test (description) values (?)
10:26:01,168 INFO [stdout] (http-0.0.0.0-8080-1) Hibernate: Insert into test (description) values (?)
10:26:01,209 ERROR [org.jboss.ejb3.Invocation] (http-0.0.0.0-8080-1) JBAS014134: EJB Invocation failed on Component Masterejb for method public void implementations.MasterEJB.persist(): javax.ejb.Ejbexception: java.lang.Runtimeexception
SELECT AT THE BANK:
mysql> SELECT * FROM test;
+----+---------------------------+
| id | Description |
+----+---------------------------+
| 1 | implementations.Childejb01 |
| 2 | implementations.Childejb02 |
| 3 | implementations.Childejb01 |
| 4 | implementations.Childejb02 |
| 5 | implementations.Childejb01 |
| 6 | implementations.Childejb02 |
+----+---------------------------+
6 Rows in set (0.00 sec)
===
In short.. the rollback still does not work :(
== +1 Edit:
now using a UNICO EJB (without using other injected EJB’s);
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void persist() {
for (int i = 0; i < 5; i++) {
Model m = new Model();
m.setDesc("KEKEKEKEKKE: " + i);
manager.persist(m);
}
contexto.setRollbackOnly();
}
rollback was not done. ta VERY STRANGE :o
RESOLVED:
I had to activate the transactions for my DATASOURCE from JBOSS.. it was just mark the box: [x] USE JTA
The methods
salvarGato()
,salvarCahorro()
andsalvarPeriquito()
, are already in transactional context? If so, what is the context of each one (REQUIRED, REQUIRES_NEW...)?– humungs
what would be in transactional context? the methods are all marked with REQUIRED
– user155542
Transactional context (or transaction propagation) is the way the container should handle transactions. For example, if you mark a method as transactional and specify that the spread of that transaction is
REQUIRED
for example, indicates that if this method is called another method without being transactional it will create a new transaction. If the method you call is already in transactional context, then the method called will use the transaction opened in the previous method.– humungs
Yes yes.. was what I expected from this code.. But when the exception is released.. no rollback :( | look at this test code: http://pastebin.com/ySMMSUwV
– user155542
See my answer and see if it matches your code. If hit and there is still the exception and there is no rollback, have to edit your question and post the exception released?
– humungs
ready.. edited question with a new example.. but with the same error unfortunately.
– user155542
It is not the best solution, but try to do this: place the following call before launching Runtimeexception():
sessionContext.setRollbackOnly();
And take the test. I’m researching what might be.– humungs
One more tip: write down the classes of your EJB’s with:
@ApplicationException(rollback=true)
and try again.– humungs
Another thing I’m using my persistence unit like this: http://pastebin.com/hwn0vNrg | I’m doing the tests you asked for
– user155542
I added another Edit.. and this is even stranger.. at a glance.. It’s as if the transactions didn’t work..
– user155542
Some things to check: it looks like Dialect is Innodb, but confirm that the engine is really Innodb. If it is Myisam, the transactions will not really work. Second, try doing it with a Servlet, not a Webservice, to reduce the number of variables. If nothing goes right, try injecting a @Usertransaction and manually demarcate the transaction. If it doesn’t work that way, then I would recommend taking a look at the quickstarts available in jboss.org/jdf. Maybe one or the other Quickstart will give you some light on what is happening (or rather not happening).
– jpkrohling
answers found the/ | put in the main post the resolution. :)
– user155542
Nice that you managed to solve your problem! Congratulations! I edited my answer to encompass your solution as well. Abs.
– humungs