in EJB 3.x for both the onMessage() method of MDBs and the #Timeout method of SLSBs and MDBs there is no transaction propagation. That is, there is no client for the execution of the method, so a transaction can't be possibly propagated.
When using Container-managed transactions, I would expect the two cases to accept the same javax.ejb.TransactionAttributeType. However, they don't.
For the onMessage() method, REQUIRED and NOT_SUPPORTED are the acceptable transaction attributes, whereas for #Timeout methods REQUIRED, REQUIRES_NEW and NOT_SUPPORTED.
In particular, for the #Timeout methods the spec says (par. 18.2.8):
Note that the container must start a
new transaction if the REQUIRED
(Required) transaction attribute is
used. This transaction attribute value
is allowed so that specification of a
transaction attribute for the timeout
callback method can be defaulted.
If I get this correctly, normally REQUIRES_NEW should be used here, but because REQUIRED is the default for an EJB, it is also allowed for #Timeout methods, giving it the same semantic as REQUIRES_NEW, since there is no possibility of a transaction to be propagated.
Questions:
Is my understanding correct?
Why isn't REQUIRES_NEW acceptable also in onMessage()? Is it different somehow in respect of transactions?
UPDATE:
The same goes for other cases where REQUIRES_NEW is supported: #Asynchronous and #PostConstruct/#PreDestroy methods.
Yes, your understanding is correct.
In my opinion, #Timeout is odd for specifying REQUIRES_NEW. The spec basically requires that the container update the persistent timer database within the same transaction as the timeout method. This isn't really any different than transactional JCA message delivery, except that it's more apparent in the JCA scenario that an external component is handling the transaction. I suppose you could argue that there is no JavaEE component driving the #Timeout method, but in my opinion, it would have been better to disallow REQUIRES_NEW for both. Regardless, the inconsistency is odd, so perhaps MDB will be updated in a later version of the spec to allow REQUIRES_NEW.
Related
I am learning about EJB's, so far I have read that multi-threading is not allowed in EJB'S, because it is the container who should care about thread-safety and let the developer only focus in the business logic, so basically that means that EJB ensures that only one thread has access at the same time to a method in a Session bean.
What happens then when we have many users accessing to the same method in a EJB?
Is the container serializing the acceses, or is creating different instances of the bean, one per thread?
Could someone explain me what is the policy about that? Also I am a bit confused, why if multithreading is not allowed, so we cannot create our own threads, why we have this #Asynchronous annotation?
Yes, it creates several instances, and pools them. See the official Oracle documentation:
Because a stateless session bean is never passivated, its lifecycle has only two stages: nonexistent and ready for the invocation of business methods. Figure 22-4 illustrates the stages of a stateless session bean.
The EJB container typically creates and maintains a pool of stateless session beans, beginning the stateless session bean’s lifecycle. The container performs any dependency injection and then invokes the method annotated #PostConstruct, if it exists. The bean is now ready to have its business methods invoked by a client.
At the end of the lifecycle, the EJB container calls the method annotated #PreDestroy, if it exists. The bean’s instance is then ready for garbage collection.
Looking for an architectural pattern to solve the following problem.
In my architecture, I have a Stateless EventDispatcher EJB that implements:
public void dispatchEvent(MyEvent ev)
This method is called by a variety of other EJBs in their business methods. The purpose of my EventDispatcher is to hide the complexity of how events are dispatched (be it JMS or other mechanism).
For now let's assume my bean is using JMS. So it simply looks at the event passed it, and builds JMS messages and dispatches them to the right topic. It can produce several JMS messages and they are only sent if the surrounding transaction ends up being committed successfully (XA transaction).
Problem: I may be looking at transactions where I send thousands of individual messages. Some messages might become invalid because of other things that happened in a transaction (object Updated and then later Deleted). So I need a good deal of logic to "scrub" messages based on a context, and make a final decision on if it is one big JMS batch message or multiple small ones.
Solutions: What I would like to is use some sort of "TransactionalContext" object and use it in my Stateless EJB to "Buffer" all the events. Then I need a callback of some sort to tell me the transaction is about to commit. This is something similar to how we use EntityManager, i can make changes to entities, and it holds onto changes and is shared between stateless EJBs. At "flush" time (transaction complete) it does its logic to figure out what SQL to execute. I need a TransactionContext available to my stateless bean that has a unique session per transaction, and, has a callback as the transaction is about to complete.
What would you do?
Note that I am NOT in a valid CDI context, some of these transactions are starting because of #Schedule timers. Other transactions begin because of JMS MDBs.
I believe the thing I am looking for is the TransactionSynchronizationRegistry.
http://docs.oracle.com/javaee/5/api/javax/transaction/TransactionSynchronizationRegistry.html#putResource(java.lang.Object
I am working on a legacy application. We are moving it from JDBC to Spring 3.2 + Hibernate 4.1.12 + JTA 2 with declarative transactions. I see that the Container-Managed Transactions (CMT) are transacting and rolling back as one would expect. We are using Infinispan as the second level cache (2LC). There is one wrinkle...
There is a portion of the code with a different entry point that is run in a different thread and uses programmatic transactions or Bean-Managed Transactions (BMT). In the BMT path, I see that in the underlying service layer, which is using CMT, the transactions are joining with the BMT as one would hope and expect.
The persistence unit, data source, etc. are the same for both entry points. In both cases, the Hibernate autoflush code is aware that there is a transaction and flushes to the database driver. In the CMT entry point, the database driver holds the data until told to commit or rollback. In the BMT path, the data is pushed into the database on flush – the later commit or rollback has no effect or apparent meaning. The transaction manager is the JtaTransactionManager. The JtaTransactionManager is defined in a #Configuration class with #EnableTransactionManagement to enable the CMT rather than the <tx:annotation-driven/> element.
The singleton JtaTransactionManager bean is wired with the ajuna UserTransaction and TransactionManager via jtaPropertyManager.getJTAEnvironmentBean().getTransactionManager() and jtaPropertyManager.getJTAEnvironmentBean().getUserTransaction(). Both the UserTransaction and TransactionManager are prototype #Bean definitions.
I am able to confirm the data is in or not in the database by a query from another query tool to verify the behavior while debugging.
When I am unit testing, the data commits and rolls back as expected for both the BMT and the CMT entry point.
The BMT is managed by a class that has the transaction begin and end in different methods. It also has methods that perform the actual unit of work. The transactions for the BMT are initiated with the PlatformTransactionManager, not the TransactionTemplate. The class is driven by another class that has the logic to manage the logic flow. I know that the transactions are beginning and ending as expected. When reading various other discussion, It seems implied that the transactional control should be within a single method. I would agree that this would be preferred but is it essential?
If a CMT-managed servlet in Spring spawns a new Thread and starts the thread with a plan thread.start(), is it reasonable to expect that a BMT within that new Thread would be able to manage its transactions as described above?
The datasource is retrieved by JNDI. Using XA or non XA does not influence the outcome.
I am unable to post the code.
As a reference, here is the link to the Spring 3.1 docs on transaction in chapter 11.
Added 2013/10/04 - I see that Spring uses the JtaTransactionManagerBeanDefinitionParser to construct the desired JtaTransactionManager based on the perceived container. When this is used, the JTA transaction manager will set into itself in the afterPropertiesSet the UserTransaction, TransactionManager, and TransactionSynchronizationRegistry.
It appears that I do actually still leak data in the CMT but that it is hard to perceive/observe this without a debugger or forcing an error unnaturally since the transactions typically commit.
It appears that my issue is that I have partially bypassed the JCA such that the JCA is using a different TransactionManager.
Partial Answer - Because I have seen this transact properly in a mix of CMT and BMT, I know that it is possible to have the BMT transaction started in one method and committed in another.
The question remains: If a CMT-managed servlet in Spring spawns a new Thread and starts the thread with a plan thread.start(), is it reasonable to expect that a BMT within that new Thread would be able to manage its transactions as described above?
From JTA 1.1 Specification (http://download.oracle.com/otn-pub/jcp/jta-1.1-spec-oth-JSpec/jta-1_1-spec.pdf) section 3.1, it is clear that the transaction is bound to the thread. This is managed by the TransactionManager. One should be able to expect the thread to be able to perform actions within a transactional context if the thread is the one that created the transaction.
Note that the support of nested transactions is optional as cited in the same portion of the JTA specification.
The actual issue I was encountering was that the managed datasource was using a different instance of the transaction manager than we had as a bean in the application. Changing the application code to do a JNDI lookup of the container-provided TransactionManager allowed the managed datasource to participate in the same transaction as the application.
I have read in the book that:
Typically, the container begins a transaction immediately before an enterprise bean method starts. It commits the transaction just before the method exits.
Suppose my stateful EJB has exposed 3 business methods and the client calls these 3 methods sequentially and want wants to run these 3 methods within a single transaction. These methods would be called across multiple requests.
Now the spec says that the transaction is committed just before the method exits. How will I be able to rollback the whole transaction, if my 1st method is successful and 2nd (or 3rd) method fails?
Please note that I don't want to use create my own transaction boundary.
Any help or the pointer in the right direction would be highly appreciated.
You are using a stateful session bean to act as a buffer. And you want a transaction around multiple calls.
From a design perspective, it's OK, if the transaction is started and committed/rollbacked from a single request (from within a single HttpServletRequest for example). In this case you can use a UserTransaction to span the transaction over multiple calls to an EJB. But a UserTransaction is bound to the current thread, so it might be difficult to pass it to the next request.
If you start and commit from different requests, you lose control over the duration of the transaction: Now a client controls the transaction. If that client crashes, the transaction won't be rolled back until the transaction timeout is reached. So the recommendation in this case is to buffer in a HttpSession for example. If all data has been collected, call a (stateless) EJB to persist it.
Create a method in the bean that calls all the other 3 methods. Then they'll be in the same transaction.
I am working on an EJB3 application with mainly stateless session beans (SLSB). They use container managed transactions (CMT).
I want the beans to be aware of the transactions (for logging, etc). I can implement the javax.ejb.SessionSynchronization to do this. I find that I can register a javax.transaction.Synchronization in a default interceptor also to get similar callbacks.
Are there any dis/advantages to using one over the other?
Multiple SLSB of the same type can be involved in the same transaction. As soon as a method exits, the SLSB is returned to a pool for use by the next invocation, so it is not safe for an SLSB instance to be "aware" of a transaction: by the time it is notified, the bean might be in use in another transaction.
As for SFSB, I would say there is no advantage between the two approaches in theory. However, the EJB container might be using Synchronization for various internal tasks, so using SessionSynchronization would allow the EJB container to have more control over the timing of the callbacks with respect to its own operations.
I just tried to use the javax.ejb.SessionSynchronization interface with a stateless session bean and was confused not to get any calls of the three implemented methods. Then I saw this comment in the javax.ejb.SessionSynchronization JavaDoc:
Only a stateful session bean with container-managed transaction demarcation can receive session synchronization notifications. Other bean types must not implement the SessionSynchronization interface or use the session synchronization annotations.
See also this thread for some more background. So my conclusion is that making stateless session beans transaction-aware using CMT can NOT be achieved with javax.ejb.SessionSynchronization.