Transactions
@TransactionAttribute(TransactionAttributeType.REQUIRED)
This annotation can be placen on a bean or on a method. It takes several values (though REQUIRED is the default one):
- NOT_SUPPORTED - Annotated method will alwes run outside transaction scope.
- SUPPORTS - If there is a transaction, it joins it. Otherwise it runs without one.
- REQUIRED - If there is a transaction, it joins. Otherwise it starts a new one.
- REQUIRES_NEW - It always starts a new transaction.
- MANDATORY - If there is no transaction, it throws an exception.
- NEVER - If there is a transaciton, it throws an exception.
MDBs can use only NOT_SUPPORTED (no transaction) and REQUIRED (new transaction). MDB method cannot be invoked within transaction context.
With MDB, the message is a part of the transaction only in case of CMT - this means JMS provider will redeliver it. For BMT the JMS provider will not know of the failure (unless it relies on acknowledgements).
EJB endpoints do not propagate transactions, therefore MANDATORY is forbidden in this case (it can change in the future).
Transactions and PersistenceContext
EM - EntityManager. PC - PersistentContext. SFSB - StateFullSessionBean
- TX-scoped EM called outside transaction will create PC for the method duration. Entities will then become detached.
- Tx-scoped EM called within transaction will create new PC (if there isn't one already) and associate it with transaciton. If PC exists, it will use it. (It applies to injected EMs.)
- If an EJB with tx-scoped PC calls SFSB with extended PC, an error is thrown.
- If SFSB with extended PC calls an EJB with tx-scoped one, extended context is propagated.
- SFSB with extended PC, calling non-injected SFSB with extended PC, will cause an error. For injected one - PC will be shared.
You can specify transaction isolation level using JDBC API (to do so lookup dataSource, then use getConnection method): connection.setTransacitonIsolation(Connection.TRANSACITON_SERIALIZABLE);
If there are many rsources in one transaciton, each can have different isolation level. But for one resource, this level must remain the same in any number of transacitons.
Locking
@Version annotation allows you to use OptimisticLocking. The annotation is placed on a dedicated field, that gets incremented with each update. If at the end of transaction version value is greater than at the beginning - it means that entity has bean changed by someone else - and OptimisticLockingException is thrown.
You can also lock entities manually - EntityManager has method lock (Object entity, LockModeType type), with LockModeTypes: READ and WRITE. It doesn't have to work on entities without @Version field.
UserTransaction
When managing transactins programatically, the most important interface is javax.transaction.UserTransaction. EJB server has to support UserTransaction, though it does not have to support the rest of the JTA. Main methods of UserTransaction:
- begin - throws IllegalStateException if there is already a transaction connected with the thread,
- commit - can throw HeuristicRollbackException or HeuristicMixedException if one of the resources has individually decided to rollback (/commit) transaction,
- getStatus - returns int,
- rollback - can throw SecurityException if the thread is not entitled to rollback transaction,
- setRollbackOnly,
- setTransactionTimeout(seconds) - can be called only after begin. If 0 is passed, the default value will be used.
With CMT you cannot use UserTransaction. All you need here is EjbContext.get/setRollbackOnly.
With BMT you should use UserTransaction.getStatus/rollback instead.
System and application exceptions
SystemExceptions are runtimes (including EjbException) and java.rmi.remoteException.
They can be turned into ApplicationExceptions via @ApplicationException annotation (it has rollback attribute that defaults to false).
SystemException thrown by an EJB always cause a rollback (both with standard and callback methods). The container will discard the EJB after that. If a SFSB is discarded, another call would end in NoSuchEJBException (runtime).
SFSB and SessionSynchronization
If a statefull bean implements SessionSynchronization interface, it has a new lifecycle state - Transactional Method-Ready (the bean knows it's in transaction). THere are new callbacks: afterBagin, beforeCompletion and afterCompletion(boolean comitted).
If a stateful is in transaction and someone calls method with requiresNew/notSupported/never attribure, an error will be thrown.
Calling a @Remove annotated method inside a transaction will also result in an error.
The @beforeCompletion method is not called before rollback. The afterCompletion method is called before both rollback and commit.
Interceptors
Create a class MyAuditor. Write a method taking a InvocationContext argument, returning Object result. Annotate it with @javax.interceptor.AroundInvoke. Then bind it to a bean (or to a method) with @Interceptors(MyAuditor) annotation.
Alternatively, use xml:
Method-params would be needed in case the method is overloaded. If you leave method-name and method-params tags out, the interceptor will be applied to all bean methods. if you use wildcard * as ejb-name, the interceptor will become global. Then, there are @ExcludeDEfaultInterceptors and @ExcludeClassInterceptors annotations.
InvocationContext argument has methods: getTarget (the bean), getMethod, get/setParameters, getContextData(used to pass information between chained interceptors), proceed(causes the target method to execute), getTImer.
You can use @Resource, @EJB and @PersistenceContext annotations in an interceptor, just like if it was a bean.
You can create callback interceptor by putting callback annotation on an interceptor method.
You can also declare @AroundInvoke method in the bean itself. It will be the most "inner" one, thus invoked as the last one.
Brak komentarzy:
Prześlij komentarz