If i have two methods inside an EJB bean, one with Transaction attribute of NOT_SUPPORTED that needs to call the other with REQUIRED, can i expect the transaction to kick in if i make the call through an injected bean:
#Stateless
#LocalBean
public class LeBean {
#EJB LeBean bean;
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public void someMethod(){
...
bean.otherMethod();
}
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public void otherMethd(){
...
}
}
or can i make the call locally like so:
#Stateless
#LocalBean
public class LeBean {
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public void someMethod(){
...
otherMethod();
}
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public void otherMethd(){
...
}
}
right now someMethod() takes a long time to process information before reaching otherMethod() and so the transaction times out, even though i have stated NOT_SUPPORTED as the transactionAttribute for the first method.
can i expect the transaction to kick in if i make the call through an
injected bean:
You HAVE to make the call through the injected bean if you want a transaction. The calls have to be made through the business interface, or else your transaction attribute will be ignored. In your case if you call otherMethod() from a method that has no transaction, or a suspended transaction (i.e. - NOT_SUPPORTED) then it is simply a POJO call.
Technically speaking otherMethod() will "ride on top of" the transaction of someMethod() if one did exist. For example you have NOT_SUPPORTED for someMethod(), but if it were REQUIRED or REQUIRES_NEW, then otherMethod() would share in that transaction. A rollback for someMethod() would also rollback operations from otherMethod().
right now someMethod() takes a long time to process information before
reaching otherMethod() and so the transaction times out
That is a different issue altogether. You may wish to increase your transaction timeout, and consider running this as a separate asynchronous process.
Related
I have a Service class like below:
#Service("MyService")
public class MyService {
#Autowired
MyDao dao;
public void process() {
getFromDao();
// getMoreFromDao();
// process();
// if all good, then
doStuff();
}
public void getFromDao() {
// do some stuff
dao.getData();
}
#Transactional(transactionManager="simpleDatasourceTxMgr", propagation=Propagation.REQUIRED)
public void doStuff() {
dao.saveData(1);
dao.saveData(2);
dao.saveData(3);
}
}
The DAO called is:
#Repository
public class MyDao {
#Autowired
#Qualifier("myjdbcTemplate")
NamedParameterJdbcTemplate jdbcTemplate;
public void saveData(obj a) {
jdbcTemplate.execute("Query", ...);
}
}
I want my doStuff() method in the service class to run within a transaction and rollback everything if there is an exception in the saveData() method. But this is not running in transaction.
If I add #Transaction to a DAO method looks like it runs in separate transaction. Is this correct?
Update: I have added a process() method to my Service and I call getFromDao() and doStuff() from process(). process() is called from the controller. So looks like if I make the service class #Transactional, then everything executes within a transaction. But I don't want getFromDao() to execute in transaction.
We use just JDBC and no Hibernate.
You can place the #Transactional annotation before an interface
definition, a method on an interface, a class definition, or a public
method on a class. However, the mere presence of the #Transactional
annotation is not enough to activate the transactional behavior. The
#Transactional annotation is simply metadata that can be consumed by
some runtime infrastructure that is #Transactional-aware and that can
use the metadata to configure the appropriate beans with transactional
behavior. In the preceding example, the
element switches on the transactional behavior.
Or if you want annotations you can enable it with
It is not sufficient to tell you simply to annotate your classes with
the #Transactional annotation, add #EnableTransactionManagement to
your configuration, and then expect you to understand how it all
works. This section explains the inner workings of the Spring
Framework’s declarative transaction infrastructure in the event of
transaction-related issues.
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/transaction.html
We have two EJB session beans as given below;
#Stateless
public class MyStatelessSessionBean{
#EJB
MyStatefulSessionBean statefulBean;
public void methodA(){
statefulBea.methodB();
}
}
#Stateful
# TransactionAttribute(TransactionAttributeType.REQUIRED)
public class MyStatefulSessionBean {
#Asynchronous
public void methodB(){
}
}
A client, which is not in any in any transaction, invoke methodA of MyStatelessSessionBean. How many distict transactions will be started by container after all processing has completed ?
There will be 2 transactions started. As EJB 3.1 specification states in point 4.5.3:
Client transaction context does not propagate with an asynchronous method invocation. From the Bean Developer’s view, there is never a transaction context flowing in from the client. This means, for example, that the semantics of the REQUIRED transaction attribute on an asynchronous method are exactly the same as REQUIRES_NEW.
In the following setup, does method B run in a (new) transaction?
An EJB, having two methods, method A and method B
public class MyEJB implements SessionBean
public void methodA() {
doImportantStuff();
methodB();
doMoreImportantStuff();
}
public void methodB() {
doDatabaseThing();
}
}
The EJB is container managed, with methodB in requires_new transaction, and method A in required transaction. thus:
<container-transaction id="MethodTransaction_1178709616940">
<method id="MethodElement_1178709616955">
<ejb-name>MyName</ejb-name>
<method-name>*</method-name>
<trans-attribute>Required</trans-attribute>
</method>
<method id="MethodElement_1178709616971">
<ejb-name>MyName</ejb-name>
<method-name>methodB</method-name>
</method>
<trans-attribute>RequiresNew</trans-attribute>
</container-transaction>
Now let another EJB call methodA with an EJB method call.
methodA now runs in an transaction. Will the subsequent call to methodB from methodA run in the same transaction, or does it run in a new transaction?
(mind, it's the actual code here. There is no explicit ejb-call to method B)
Your call to methodB() is an ordinary call of a method, not intercepted by the EJB container; at run-time the EJB container will inject a proxy and not an instance of your class, this is the way it intercepts calls and setup the environment before calling your method. If you use this you're calling a method directly and not through the proxy. Hence both methods will use the same transaction, regardless to what is defined in ejb-jar.xml for calls through EJB interfaces.
inject SessionContext, and ask it for your proxy instance:
#Stateless
public class UserFacade implements UserFacadeLocal {
#Resource
private SessionContext context;
#Override
#TransactionAttribute(TransactionAttributeType.REQUIRED)
private void create(User user) {
System.out.println("Users Count: "+count()); //invocation#1
System.out.println("Users Count Through Context: "+context.getBusinessObject(UserFacadeLocal.class).count()); //invocation#2
}
#Override
#TransactionAttribute(TransactionAttributeType.NEVER)
public int count() {
return ((Long) q.getSingleResult()).intValue();
}
}
in 'invocation#1' this is a Local call, not passing through proxy, it will return the count
in 'invocation#2' this is a call through the proxy, and hence you annotate it not to support transaction -which is now opened by create(user) method-, this invocation will throw a transaction exception:
javax.ejb.EJBException: EJB cannot be invoked in global transaction
They will use the same transaction.
If I remember well, the transaction is started by the container "before" the method is invoked and commited after it "finish".
Since "a" calls "b", "b" would use the same transaction.
:S
I guess the best thing you can do is test it to verify it! :)
I have a CDI conversation scoped action class which I am also making a stateful EJB for holding state of objects throughout the conversation life cycle.
As the action class is an EJB, so by default all methods will be transactional, which I intentionally don't want to do. I just want a single method of the action class will be transactional where I will only perform database persistence tasks. So I annotate that single method with #TransactionAttribute(TransactionAttributeType.REQUIRES_NEW). And the action class is annotated with #TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED).
When I call the transactional method from other handler methods of the same action class, there no transaction starts.
Here is the code sample.
#Stateful
#Named
#ConversationScoped
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class MyAction implements Serializable {
#PersistenceContext(type = PersistenceContextType.EXTENDED)
private EntityManager em;
........
........
........
public String handlerMethod1() {
// do some staffs.
persist();
return "view";
}
public String handlerMethod2() {
// do some staffs.
persist();
}
.......
.......
.......
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
private void persist() {
// save objects.
em.flush();
}
}
No transaction starts when invoked persist() method though I have annotated it with #TransactionAttribute(TransactionAttributeType.REQUIRES_NEW), but why?
Please help me getting rid of this.
You have two problems here:
a) persist() is not a business method. A Business method have to be (among other rules) public.
b) you are calling the persist() method with a simple object method invocation, therefore, the Container is not able to manage the code. Remember that #TransactionAttribute annotation needs to be interpreted by the Container, which doesn't occurs in this case.
One possible solution could be to create other EJB with the persist() method code and inject him in MyAction bean.
This way, every time you invoke the persist() method, the Container will intercept the call and it will create a new transaction.
Let's I have Stateless bean with CMT. I have 3 methods in bean, 2 with TransactionAttributeType.REQUIRED. And both method are called from third method. How can I check when transaction is active? i want check
#Stateless
#TransactionManagement(TransactionManagementType.CONTAINER)
public class MyBean
{
public RetType methodA()
{
methodB();
//.... is CMT active there?
methodC();
}
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public RetType methodB(){}
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public RetType methodC(){}
}
The TransactionAttributeType.REQUIRED attribute is the default for container managed transactions bean methods, so even if you didn't annotate it, methodA runs in a transaction that starts as soon as the method starts (unless you call the method from another active transaction, in that case the method simply join the current transaction).
The transaction ends when the method upon method exit (again unless called from another transaction). Any method called by methodA, unless annotated with TransactionAttributeType.REQUIRES_NEW, joins the current transaction.