Bank.java
@Stateless
@Local
public class Bank implements IBank {
@EJB
IConfigBean iConfigBean;
@EJB
IDbs iDBS;
@EJB
IPosb iPosb;
@Override
public void doTransaction() {
System.out.println("--Bank Transaction Started--");
try {
Config config1 = getConfig(1);
iConfigBean.create(config1);
iDBS.doDBSTransaction();
Config config3 = getConfig(3);
iConfigBean.create(config3);
iPosb.doPOSBTransaction();
Config config5 = getConfig(5);
iConfigBean.create(config5);
} catch (Exception e) {
e.printStackTrace();
System.out.println("---Bank Exception--");
}
System.out.println("--Bank Transaction End--");
}
@Override
public Config getConfig(int inserttionOrderNo) {
Config config = new Config();
config.setType("EJBTransactionTESTING - " + inserttionOrderNo);
return config;
}
}
DBS.java
@Stateless
@Local
public class DBS implements IDbs {
@EJB
IConfigBean iConfigBean;
@Override
public void doDBSTransaction() {
System.out.println("--DBS Transaction Started--");
try {
Config config2 = getConfig(2);
iConfigBean.create(config2);
} catch (Exception e) {
e.printStackTrace();
System.out.println("--DBS Exception--");
}
System.out.println("--DBS Transaction End--");
}
@Override
public Config getConfig(int inserttionOrderNo) {
Config config = new Config();
config.setType("EJBTransactionTESTING - " + inserttionOrderNo);
return config;
}
}
POSB.java
@Stateless
@Local
public class POSB implements IPosb {
@EJB
IConfigBean iConfigBean;
@Override
public void doPOSBTransaction() {
System.out.println("--POSB Transaction Started--");
try {
Config config4 = getConfig(4);
iConfigBean.create(config4);
if (true) {
//For Test 1
//throw new NullPointerException();
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("--POSB Exception--");
}
if (true) {
//For Test 2
// throw new NullPointerException();
}
System.out.println("--POSB Transaction End--");
}
@Override
public Config getConfig(int inserttionOrderNo) {
Config config = new Config();
config.setType("EJBTransactionTESTING - " + inserttionOrderNo);
return config;
}
}
I am new to Stack Overflow and Its my new question so correct me If I am wrong.
Environment is..
I have Three stateless bean, Please look at the Sequence Diagram of the Transaction flow.
I purposely making NullPointer Exception at two places during the transaction to know the difference and I have marked with Lightening Bold symbol in sequence diagram.
I am not using any @TransactionAttribute to any methods.
Test 1 - Null Pointer in Inside the try block (Lightening Bold symbol with Green) When I start the testing, Got Null pointer exception and all the transaction are not marked for roll back and data also got inserted in db.
I can only see Null pointer exception in the console log.
Test 2 - Null Pointer in Outside the try - catch method (Lightening Bold symbol with Red) When I start the testing, Got Null pointer exception plus EJBTransactionRolledbackException and all the transaction marked for roll back and no data inserted in db.
I can see NullPointer and EJBTransactionRolledback Exception in the console log.
Question here is,
Thanks in advance.
Keep in mind EJB calls, all the "magic" made by container happens there, including transaction markup. It's possible due to the fact that EJB calls are not direct, but always go through proxy.
You have such calls in your code:
iPosb.doPOSBTransaction();
So, if unchecked exception (NPE for example) is thrown in this method and not caught - it's ultimately caught by container due to EJB proxy wrapping the call above. In this case transaction only could be rolled back.
Adding a call to a method of the same bean in your method (without using @EJB reference), does not change that:
@Override
public void doPOSBTransaction() {
try {
Config config4 = getConfig(4);
iConfigBean.create(config4);
if (true) {
newMethod();
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("--POSB Exception--");
}
if (true) {
newMethod();
}
}
private void newMethod(){
throw new RuntimeException();
}
You can easily check that commit/rollback behaviour is just the same in this case, no matter that a method is added to call stack.
So the important thing you have to remember is that all container tricks work only on @EJB calls. So, for example, it's pointless to place transactional annotation on a private method - it won't be used ever.
Another important point is about checked exceptions. By default these do not cause transaction rollback indeed. But it's still possible to annotate your checked exception like below to make it rollback ongoing transaction:
@ApplicationException(rollback = true)