I'm trying to use Container-Managed Transactions inside webservice, but transaction isn't created. I have something like that:
#WebService(...)
#Stateless
#TransactionManagment(TransactionManagmentType.CONTAINER)
public class ExampleService {
// EntityManager and other fields
#TransactionAttribure(TransactionAttributeType.REQUIRED)
public void test(String s){
// persist something with EntityManager
}
}
When I call this method, I get javax.persistence.TransactionRequiredException: The method public abstract void javax.persistence.EntityManager.persist(java.lang.Object) must be called in the context of a transaction.
What am I doing wrong?
Thanks!
From what I recall 'TransactionAttributeType.REQUIRED' means that method should be only called when transaction is already in progress for current thread (in other words 'called in context of transaction'). It's not clear who if anybody starts transaction in your case. If nobody then the exception you're getting makes perfect sense.
Now I'm not sure how or is it even currently possible to propagate transaction across Web services call. I don't think this is particularly good idea to do so even if possible.
Perhaps you what you need TransactionAttributeType.REQURES_NEW in your case so Container would start the transaction before passing control to your annotated method?
Related
I'm using a Java EE 7 + GlassFish and need to perform some operation against a number of JPA entities from a stateless bean.
#Stateless
public class JobRunner
{
public void do()
{
for (Entity entity:facade.findAll())
{
///do some work against entity
}
}
}
This JobRunner bean is injected into the servlet and I invoke do() method from the web UI.
The issue is that all entities are being changed within one transaction so if one fails everything is rolled back what is not desirable. Is there a way to start and close a new transaction for each entity (i.e. for each iteration of the loop)?
I can write an external client and make a loop there calling a stateless bean for each entity but it's not something that completely works for me as I prefer to keep an app monolithic. Can I somehow manage transactions form inside a container?
Maybe JMS helps? If I implement a doer as message listener and will be sending a message for each entity, will it start a new transaction for each one?
#Stateless
public class JobRunner
{
public void do()
{
for (Entity entity:facade.findAll())
{
sendMessageToRealDoer(entity);
}
}
}
Create another bean, specifying #TransactionAttribute(TransactionAttributeType.REQUIRES_NEW), at method or bean level:
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
#Stateless
public class JobWork {
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void doWork(Entity entity) {
// do what you would do in the loop with the Entity
// this runs in a new transaction
}
}
I wish I could tell you that you only need to annotate a method of the same bean (JobRunner) and simply call it. This is not possible (EDIT)without workarounds - check comment from Steve C(/EDIT) because when calling methods of this object in EJBs and CDI beans the interceptors do not get called. Transactions are implemented with interceptors in both cases.
Some notes:
If the total duration of the operations in the loop is expected to be long, you will get a timeout in the outer transaction, that is implicitly started for the JobRunner stateless EJB. You will want to take measure that no "outer" transaction is started.
Sending the data to a queue will work too; but queues will process them asynchronously, meaning that the execution will return to the servlet calling JobRunner.do() most probably before all items have been processed.
I have a main DB handler method, which calls other methods, which are also working with BD things.
I put #Transactional annotation for the main method, because I want to roll back everything, if something goes wrong.
My question is: should I put this annotation also for the submethods, or it will know that the submethods were called from a method which is transactional.
For example, in the deleting method an exception occurs, how can I make sure that the writing part will be also rollbacked:
#Transactional
public void maintDbTings() {
writing();
deleting();
}
#Transactional //do I need this?
public void writing() {
//no exceptions
}
#Transactional //do I need this?
public void deleting() {
//exception occurs
}
Spring begins a transaction when it encounters a method annotated with #Transactional. The transaction’s scope
covers the execution of that method, the execution of any methods that method invokes, and
so on, until the method returns. Any managed resources that are covered by the configured
PlatformTransactionManager and that you use during the transaction scope participate in the
transaction. For example, if you use the org.springframework.jdbc.datasource.DataSourceTransactionManager, a Connection retrieved from the linked DataSource
participates in the transaction automatically.
The transaction terminates one of two ways: Either the method completes execution directly and the transaction manager commits the transaction, or the method throws an exception and the transaction manager rolls the transaction back.
I hope it is clear now.
In plain english, when you have this:
#Transactional
public void maintDbTings() {
writing();
}
#Transactional //do I need this?
public void writing() {
//no exceptions
}
And call mainDbTings, the #Transactional on the writing has no effect. Meaning that the transaction that was started for mainDbThings will still be present/open in writing. So in this case you can easily drop it.
On the other hand since writing is public someone might call it expecting it to be transactional, since it is a service class most probably. In this case making writing to be #Transactional is mandatory and you can't drop it.
So it's up your needs really.
You can use propagation properties like REQUIRED, REQUIRES_NEW, NESTED according to your requirement as described in the below link:
http://docs.spring.io/spring-framework/docs/4.2.x/spring-framework-reference/html/transaction.html
I have a following code structure, I need guidence on how to start a local transaction cascaded from a NOT_SUPPORTED transaction type method in same EJB.
#Stateless
#TransactionManagement(value = TransactionManagementType.CONTAINER)
public class SessionBean implements SessionBeanInterface{
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public void methodA() {
methodB();
}
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public void methodB() {
}
}
Currently when I try this i get below exception.
No active transaction for PuId=App#EJB.jar#Persistence
The way you have called "methodB" would not give a chance to the EJB Container to start a transactional context for you. To do that you have to invoke that method through either Remote or Local views/interface.
It is the container who supplies you these additional features and hence it is necessary to route your calls through interface than. (On a side note this is Proxy Design Pattern).
If you directly call "methodB" as you have done in above code snippet, it is just another method call without container intervention.
I have a service, which uses multiple DAOs to do a unit of work like following. The DAOs fetch the data/save by creating a session and commit. In that case, why do i need to have transactional on the service when the dao is managing the session by itself? If something goes wrong in the second DAO, the data in the first DAO is already commited, how do I get around this situation?
#Transactional
public boolean testService(SomeObject obj){
userDao.save(obj.getUser()); // this dao gets the session from sessino factory and commits there itself.
addressDao.save(obj.getAddress()); // something fails here, and the above line has already commited the data, so the data is not Atomic.
return true;
}
Usually you don't put #Transactional in your DAO layer but in your service layer.
So I suggest you remove #Transactional from you DAOs and keep the one in your service.
In that case, if something goes wrong in any of your DAO everything will be rollback.
But It's up to you where you want the transaction to start and to finish.
I need to commit transactions from CMT bean by hand. There is a loop which processes multiple records and each record should be processed in its own transaction. I wanted to mark method transaction support as NOT_SUPPORTED and then control transaction from method. However I could not retrieve a UserTransaction instance neither from SessionContext neither injecting it as a JNDI resource java:/module/UserTransaction.
Are there any chance to process multiple records in CMT bean in their own transactions without introducing new BMT bean for such processing?
You should not mess around transactions yourself if you use CMT.
I recommend you create a method for the operation needs to be in transaction, mark it as REQUIRES_NEW, then call it from the loop.
Everytime the method is called, the current transaction (if any) will be suspended and a new transaction will be started for the operation.
Something like this:
#EJB
SomeEJBLocal anotherme;
public void loop() {
for(/* something */) {
anotherme.single();
}
}
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void single() {
// do stuff
}
You will have to inject another instance of the EJB and call single in order for the container to process the transaction aspects.