Enterprise Java Development@TOPIC@
Declarative interface to transactions
Declarative attributes tell container to execute a method
within a transaction (MADATORY, REQUIRED, REQUIRES_NEW, SUPPORTS)
without a transaction (SUPPORTS, UNSUPPORTED, NEVER)
Container completes transaction protocol prior to marshaling return objects
Container must suspend any active transaction
Figure 101.1. Transaction Not Supported
@Override
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public Product createProductAndShipments_NotSupported(Product product, List<Shipment> shipments)
throws UnexpectedState {
When called with transaction active:
Caller transaction suspended during call
Caller transaction resumed after call
Caller transaction is not impacted by resource managers used during call
Caller transaction not passed to anything this method calls
Container must invoke method with transaction active
Figure 101.2. Transaction Required
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public Product createProduct(Product product) {
When called with transaction active:
Caller transaction context passed to method (unless @Asynchronous)
Caller transaction context passed to anything this method calls
Resource manager(s) called by method are enlisted in caller's transaction context
When called without transaction active:
New transaction started
Transaction committed after method returns
Container can invoke method with transaction either active or inactive
Figure 101.3. Transaction Supports
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
public int getShipmentCount(int productId) {
When called with transaction active:
Caller transaction context passed to method (unless @Asynchronous)
When called without transaction active:
No transaction started
Container must invoke method with new transaction active
Figure 101.4.
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public Shipment createShipment_RequiresNew(Shipment shipment) {
New transaction started
Transaction committed after method returns and prior to returning result to client
When called with transaction active:
Caller transaction suspended during call
Caller transaction resumed after call
Caller transaction is not impacted by resource managers used during call
Caller transaction not passed to anything this method calls
Caller must already have transaction active
When called with transaction active:
Caller transaction context passed to method
When called without transaction active:
javax.ejb.EJBTransactionRequiredException
Caller must never invoke method with transaction active
When called with transaction active:
javax.ejb.EJBException
When called without transaction active:
Called method continues without transaction
Figure 101.8. @Asynchronous Method with REQUIRED
@Asynchronous
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void addQuantity(int productId, int quantity) {
EJB transactions cannot propagate across @Asynchronous methods
Use of REQUIRED in @Asynchronous method will act like REQUIRES_NEW
Methods
@PostConstruct
@PreDestroy
@PrePassivate (Stateful)
@PostActivate (Stateful)
Operate by default in an undefined transaction context
May be defined with REQUIRES_NEW or NOT_SUPPORTED
Any transactions created during a lifecycle method will not be a part of the client's transaction
Figure 101.9. EJB Lifecycle Methods with Container-Managed Transactions
@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
public class WarehouseTxEJB {
@TransactionAttribute(TransactionAttributeType.REQUIRED)
@PostConstruct
public void init() {
logger.debug("*** {}:init({}) ***", getClass().getSimpleName(), super.hashCode());
updateBeanCount(1);
}
@TransactionAttribute(TransactionAttributeType.REQUIRED)
@PreDestroy
public void destroy() {
logger.debug("*** {}:destroy({}) ***", getClass().getSimpleName(), super.hashCode());
updateBeanCount(-1);
}
private void updateBeanCount(int value) {
String beanName = getClass().getSimpleName();
BeanCount count=em.find(BeanCount.class,
beanName,
LockModeType.PESSIMISTIC_WRITE);
if (count!=null) {
count.setCount(count.getCount()+value);
} else {
count = new BeanCount(beanName);
count.setCount(value);
em.persist(count);
}
logger.debug("updatedBeanCount({}) to {}", count.getName(), count.getCount());
}
Must be either
REQUIRED - message receipt integrated with JTA transaction
NOT_SUPPORTED - message receipt not part of JTA transaction
EJB cannot access transaction
EJB has no means to commit transaction -- commit managed by container
EJB can only mark the transaction for rollback -- rollback managed by container
Unchecked exceptions automatically mark the transaction for rollback
Figure 101.10. EJBContext
public interface javax.ejb.EJBContext {
...
javax.transaction.UserTransaction getUserTransaction() throws java.lang.IllegalStateException;
void setRollbackOnly() throws java.lang.IllegalStateException;
boolean getRollbackOnly() throws java.lang.IllegalStateException;
...
}
@Resource
SessionContext ctx;
...
ctx.setRollbackOnly();
...
getUserTransaction()
Returned instance can use used to demarcate transactions
Restricted to EJBs using bean-managed transactions
getRollbackOnly()
Tests whether current transaction is going to be rolled back at the end
Restricted to EJBs using container-managed transactions
setRollbackOnly()
Allows EJBs to trigger the current transaction to be rolled back at the end
Restricted to EJBs using container-managed transactions
Figure 101.11. Example: Explicit Rollback thru EJB/SessionContext
@Resource
private SessionContext ctx;
@Override
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public Product createProductAndRollback(Product product) {
//create a product in the database
Product p=beanA.createProduct(product);
beanA.flush(); //here just to highlight the impact of the rollback
ctx.setRollbackOnly();
return p; //return the product even thow we are going to roll it back
}
Resources created/modified within the transaction -- including resources operated on by called EJBs -- will be rolled back.
Figure 101.12. Example: IT Client Triggers Rollback
Product product = warehouse.createProductAndRollback(new Product("thing", 6));
//since we did not throw an exception -- we get a normal return object
assertEquals("unexpected quantity for product", 6, product.getQuantity());
//since we setRollbackOnly() prior to the return -- our product will not be there
Product p2 = warehouse.getProduct(product.getId());
assertNull("unexpected/rolled back product found", p2);
Even though the application did not throw an exception and gracefully returned a result -- the IT test shows the entity was not stored during the callback
Two types
Checked/Application
Unchecked/Runtime
Checked/Application exceptions, by default, do not rollback the transaction when throw
Unchecked/Runtime exceptions do rollback the transaction when thrown
No automatic rollback by default
Figure 101.13. Example: Checked/Business Exception
public class MyCheckedProductException extends Exception {
private Product product;
public MyCheckedProductException(Product product, String message) {
super(message);
this.product = product;
}
Checked exceptions, but default, do not trigger rollbacks
Figure 101.14. Example: EJB Method Commits Data, Throws Checked Exception
@Override
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public Product createProductAndThrowChecked(Product product)
throws MyCheckedProductException {
//create a product in the database
Product p=beanA.createProduct(product);
//throw a checked exception -- the product will still be committed
throw new MyCheckedProductException(p, "planned checked exception");
}
An error in processing can be reported with an exception without rollback
Figure 101.15. Example: Client Triggers Exception and Verifies Data Committed
Product product = null;
try {
warehouse.createProductAndThrowChecked(new Product("thing", 6));
fail("planned exception not thrown");
} catch (MyCheckedProductException ex) {
//the *checked* exception contains the product in the exception
product = ex.getProduct();
assertEquals("unexpected quantity for product", 6, product.getQuantity());
}
//our product should exist
Product p2 = warehouse.getProduct(product.getId());
assertEquals("product not updated async", 6, p2.getQuantity());
IT test verifies entity thrown with the exception was persisted
Checked/Application exceptions can be configured to trigger a rollback
Figure 101.16. Example: Checked/Business Exception
import javax.ejb.ApplicationException;
@ApplicationException(rollback=true)
public class MyCheckedRollbackProductException extends Exception {
Annotation tells container to automatically rollback transaction if thrown
Figure 101.17. Example: EJB Method Throws Checked Exception to Automatically Rollback
@Override
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public Product createProductAndThrowCheckedRollback(Product product) throws MyCheckedRollbackProductException {
//create a product in the database
Product p=beanA.createProduct(product);
beanA.flush(); //here just to highlight the impact of the rollback
//throw a checked exception marked for rollback -- the product will *NOT* be committed
throw new MyCheckedRollbackProductException(p, "planned checked exception");
}
An error in processing can be reported with an exception without rollback
Figure 101.18. Example: Client Triggers Exception and Verifies Data Committed
Product product = null;
try {
warehouse.createProductAndThrowCheckedRollback(new Product("thing", 6));
fail("planned exception not thrown");
} catch (MyCheckedRollbackProductException ex) {
//the *checked* exception contains the product in the exception
product = ex.getProduct();
assertEquals("unexpected quantity for product", 6, product.getQuantity());
}
//since we used a rollback=true checked exception -- our product will not be there
Product p2 = warehouse.getProduct(product.getId());
assertNull("unexpected/rolled back product found", p2);
IT test verifies entity thrown with the exception was persisted
Persistence contexts can also get propagated
Stateless EJB can propagate its tx-scope persistence context to a called EJB
Stateful EJB can propagate its tx-scoped or extended persistence context to a called EJB
Stateless EJB can work with extended persistence context provided by upstream Stateful client
Stateful EJB cannot transform propagated tx-scope persistence context into an extended
EJB Facade can act as sharing point for common persistence context