By default, transactions in EJBs are automatically managed by the container.
This means that you normally don't need to do anything if you want your application to be "transactional".
Every EJB that you have created so far has used transactions. When you used JPA, the EntityManager would automatically save all of its changes on transaction commit (i.e., when your method returns).
Java EE allows you to override the default transaction behavior.
For this activity, you will explore what happens when methods with different "TransactionAttributeType"s interact with each other.
Challenge
What happens when a method with TransactionAttributeType.REQUIRED calls a method with TransactionAttributeType.NEVER?
(Hint: an exception is thrown but what is the exception and why is it thrown?)
What happens when a method with TransactionAttributetype.NOT_SUPPORTED calls a method with TransactionAttributeType.MANDATORY?
(Hint: an exception is thrown but what is the exception and why is it thrown?)
Your challenge is to write some Java code to help you answer these questions.
Hints
You should create a new project. Name the project Week11. You can use a Web Application or an Enterprise Application. Ensure that you use the JavaServer Faces library if you are using a Web Application, or add JavaServer Faces to the Week11-war project.
Once you have created your project, you might create the following pages and classes:
- A JavaServer Faces page, containing a
<h:commandButton ...>
- A backing bean with a method that you will configure so that it can be called by the JSF
<h:commandButton>
- A
@Stateless
EJB (named TransactionBean) that is injected into the backing bean (e.g.,@EJB private TransactionBean transactionBean;
) - Another
@Stateless
EJB (named SecondaryBean) that is injected into the first EJB (e.g.,@EJB private SecondaryBean secondaryBean;
).
You would then write a method in your first EJB (TransactionBean) that calls a method in the second EJB (SecondaryBean) that has been annotated with a different transaction type.
Be careful: transaction attributes only work when you call an injected EJB. If you just call another method in the same class directly, the container does not create a new transaction scope.
i.e., In the following class, if you call a()
, the MANDATORY transaction type is used even when b()
is called.
To get the container to use the other transaction type, you would need to move the method b()
into a separate EJB.
@Stateless
public class MyBean {
@TransactionAttribute(TransactionAttributeType.MANDATORY)
public void a() {
b(); // this is a direct invocation
}
@TransactionAttribute(TransactionAttributeType.NEVER)
public void b() {
// this uses MANDATORY if called from a directly,
// but uses NEVER if called from outside the EJB
}
}
Reflect
In what situations would you use MANDATORY? In what situations would you use SUPPORTS? In what situations would you use NOT_SUPPORTED?
Why is the transaction attribute ignored when you do a direct method invocation?