• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Application-Managed Transaction without joining

 
Ranch Hand
Posts: 757
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator


In the above code, I didn't use a joinTransaction() method in the addCustomer() method. And the EntityManager is created outside the transaction scope of addCustomer() method. Because of it I though that this would gives an exception. But it works fine. How is this possible?
 
Ranch Hand
Posts: 357
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
By default method will be Container Managed Transaction, and they will be required. so even if you don't define it, the container will be managing the transactions for you, opening a new transaction if needed, committing it when the method completes, or rolling back in case of something going wrong.

although you created the entity manager in the post construct method initi(); but I think its not different that using DI to obtain it, since usually the container will resolve DI after calling the constructor of the bean, and then calls the post construct methods.
 
Treimin Clark
Ranch Hand
Posts: 757
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

omar al kababji wrote:By default method will be Container Managed Transaction,



OK, so I'm modifying the code as below:


But the code works fine.
 
Omar Al Kababji
Ranch Hand
Posts: 357
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
from the specs it says that the TransactionRequiredException is thrown if the persist method is invoked on a container-managed entity manager of type PersistenceContextType.TRANSACTION and there is no transaction. and in your case the entity manager is not container managed, so no exception is thrown.
 
Treimin Clark
Ranch Hand
Posts: 757
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
But the specs says:

Specs wrote:joinTransaction method should be called on a JTA application managed EntityManager that was created outside the scope of the active transaction to associate it with the current JTA transaction.



But I didn't use the joinTransaction here. So what is the difference?
 
Omar Al Kababji
Ranch Hand
Posts: 357
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
mmmm well i think that we have to understand whats the meaning of "outside the scope of the active transaction" from my understanding i think that you are calling your method directly so there is currently no transaction. something you can try is to call your method from another ejb method that has already started a transaction and see what happens.
 
Treimin Clark
Ranch Hand
Posts: 757
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

omar al kababji wrote:i think that you are calling your method directly so there is currently no transaction.



Nah! I'm calling to the addCustomer method from the Client program, so the client transaction exists.
 
Omar Al Kababji
Ranch Hand
Posts: 357
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
...

lets try to do something like this

Customer3 cust = //load an already existing customer
cust.setFirstName("xyz");


at this point the updates should not be persisted, because its not managed by the container. but if they got persisted then there is something going wrong.
 
Ranch Hand
Posts: 383
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Treimin,

the answer it so your first post. You are using an application-managed (and thus extended) persistent context, that is also created outside any JTA transaction. You can call persist() and others without an active transaction, but if you want to actually flush() the changes, you must enlist in a transaction with the joinTransaction() method, and the changes are flushed when it commits, as you already noted. The code you posted actually does nothing, it never changes the underlyign database - have you checked that?
To back up, here is what the specs say about extended context (3.3, page 53):


When an EntityManager with an extended persistence context is used, the persist, remove, merge, and
refresh operations may be called regardless of whether a transaction is active. The effects of these oper-
ations will be committed to the database when the extended persistence context is enlisted in a transac-
tion and the transaction commits.

The scope of the persistence context of an application-managed entity manager is extended. It is the
responsibility of the application to manage the lifecycle of the persistence context.


You never enlist in a transaction, and so it is never committed to the database.
If you really want to provoke an exception, call flush() yourself - TransactionRequiredException on the way.

Raf
 
Treimin Clark
Ranch Hand
Posts: 757
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Raf Szczypiorski wrote:
If you really want to provoke an exception, call flush() yourself - TransactionRequiredException on the way.



Raf,

I've changed the code as below:



But I'm still not getting an exception here.
 
Raf Szczypiorski
Ranch Hand
Posts: 383
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Can you change it to be stateless bean? See what happens.
 
Treimin Clark
Ranch Hand
Posts: 757
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Raf Szczypiorski wrote:Can you change it to be stateless bean? See what happens.



Changed to Stateless bean.

But no change in the output. No exception.

Raf, I've checked the database. The data was committed to the database even as in my first post!


F.Y.I: This is the persistence.xml


 
Raf Szczypiorski
Ranch Hand
Posts: 383
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi,

this made me think, and test, and here's what results I got: I have 2 persistence providers used on Glassfish v2 - TopLink (the default) and Hibernate, both of these use the same set of persistence classes. So, I invoked the same entity add routine for both, and here it goes:

* CMT without flush() called (your first post):
- hibernate just doesn't persist, and keeps the entity in its context
- toplink does persist

* CMT with flush():
- hibernate throws TransactionRequiredException
- toplink does persist, as above

* BMT with no flush():
- both toplink and hibernate store the entity in their persistence contexts, but the database is not altered

* BMT with flush():
- both fail when flush() called, with TransactionRequiredException

Also, with detailed logging, for CMT, when toplink is used, the following line can be seen:
FINER: TX beginTransaction, status=STATUS_ACTIVE
which means Toplink automatically enlists an application-managed JTA persistence context when a transaction is available, hibernate doesn't do that.

So, I guess you are using Glassfish v3 with Toplink. Is this correct? Also, as the specs says that an application-managed JTA context created outside a transaction must call joinTransaction(), and Toplink doesn't require this, it is against the specs... Hibernate, on the other hand, behaves correctly.

Maybe gurus here could contribute to this thread? It is interesting.
 
Treimin Clark
Ranch Hand
Posts: 757
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You correct Raf, I'm using GlassFish. But what are the others... TopLink? Hibernate?.... I don't know.
 
Raf Szczypiorski
Ranch Hand
Posts: 383
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You are preparing for the cert, so you must be familiar with the "persistence provider" role (this is actually one of the requirements to know the 7 roles). The provider supplies you with a set of libraries that implement the interfaces in the JPA specification. Every EJB container must provide a JPA implementation, but this is pluggable, so you can easily switch the providers / persistence implementation libraries. TopLink is a persistence provider implementation by Oracle, Hibernate is a very popular, open source project that predates JPA, and the guys who created it (JBoss guys) have been substantially contributing to the EJB, JPA specs and others (currently Web Beans, for example). So, Hibernate and ToplLink can be used with their own, native APIs, but they can also be used with JPA interfaces through their JPA bridge. Glassfish uses Toplink Essentials (a subset of TopLink, that just implements JPA, and is stripped of many non-standard extensions), and JBoss uses Hibernate by default, but if you want, you can add the jars and use any provider in any EJB container, and that's what I did. I wanted to see the differences (there are a few, actually), so I configured both TopLink and Hibernate to use the same set of persistent classes.
When you don't use a <provider> element in you persistence.xml, the container default is used, in your case it's Glassfish, so TopLink is the default.
 
Treimin Clark
Ranch Hand
Posts: 757
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Ah! I understood Raf
 
Ranch Hand
Posts: 342
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Treimin,

if you modify your code as follows,

deploy the bean and call addCustomer for the first time, the glassfish log may look like

That means, the bean was created upon the client's call of the transactional method addCustomer. Per definition the transactional context of the post construct method is "unspecified". So there may be a transactional context or not.

It seems to me that glassfish/toplink performs in this scenario both, the post construct method and addCustomer() within the same transactional context. Since the entity manager is created within this transaction, it's automatically synchronized and joinTransaction() isn't needed. As a result a flush on the persistence context is performed when the transaction commits and a customer is persisted.

If your client calls addCustomer twice (with different customer id's) in one run, the second customer won't be persisted. That's because glassfish will use the same bean instance and the entity manager wasn't created within the scope of the second transaction and joinTransaction() wasn't called. (Of course there is no real guarantee that the same bean instance is used to perform the second addCustomer method - it depends on the environment - but this seems to be the typical glassfish behavoir in such little load test scenarios).

This may be an explanation of your observation. Similar arguments apply to the stateful case.
 
Ranch Hand
Posts: 90
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Ralph,
I did not understand how you drew the conclusion you did about transactional context. To me all this is telling me is that init ran before addCustomer. I am not sure how anything about their transactional context can be derived from this. Can you explain this a little bit.



addCustomer 22:47:59.312
inti 22:47:59.187


 
Ranch Hand
Posts: 270
Eclipse IDE Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Treminin,

I dont know if you are getting TransactionRequiredException yet or not.But here is the code that i used and i am getting the exception.

StatelessSesssionBeanBean.java



Main.java




And the exception i am getting:

Caused by: javax.persistence.TransactionRequiredException
at com.sun.enterprise.util.EntityManagerWrapper.doTxRequiredCheck(EntityManagerWrapper.java:236)
at com.sun.enterprise.util.EntityManagerWrapper.doTransactionScopedTxCheck(EntityManagerWrapper.java:200)
at com.sun.enterprise.util.EntityManagerWrapper.persist(EntityManagerWrapper.java:426)
at ejb.StatelessSesssionBeanBean.addEmployee(StatelessSesssionBeanBean.java:24)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.sun.enterprise.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1067)
at com.sun.enterprise.security.SecurityUtil.invoke(SecurityUtil.java:176)
at com.sun.ejb.containers.BaseContainer.invokeTargetBeanMethod(BaseContainer.java:2895)
at com.sun.ejb.containers.BaseContainer.intercept(BaseContainer.java:3986)
at com.sun.ejb.containers.EJBObjectInvocationHandler.invoke(EJBObjectInvocationHandler.java:203)
... 17 more


 
Ralph Jaus
Ranch Hand
Posts: 342
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Promod,

I did not understand how you drew the conclusion you did about transactional context. To me all this is telling me is that init ran before addCustomer. I am not sure how anything about their transactional context can be derived from this. Can you explain this a little bit.


I configure glassfish with Maximum Pool Size = 1 and call addCustomer two times (using id = 1, 2). The result is as follows:

So, if the existing bean instance is used, no customer is inserted. That means, no flush was performed. That's because the application managed entity manager was created outside the transaction and wasn't synchronized with the transaction.

So let's consider addCustomer(1): Facts are:

1. The customer was inserted into the database. This means a flush occured.
2. We know from spec: An application managed entity manager is automatically synchronized with a transaction only if it's created within this transaction.

So the only remaining possibility is, that the entity manager was created in the scope of the transaction those context was used in the execution of addCustomer(1).

Interestingly, the timestamps above indicate not only that the post construct method is executed before the business method is executed. They show moreover, that the bean creation is perfomed directly upon the first call of the business method. Therefore I guess that the post construct method and addCustomer(1) are performed within the same transaction. At least this would explain the results in the database.

In any case, the phenomenon has to do with the bean creation and the unsprecified transaction context in post construct methods: The second call addCustomer(2) behaves as expected/specified.

 
Ranch Hand
Posts: 1277
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
great thread.. amazed to see that Raf switches the persistence providers and the servers, so quickly..

by the way, which one's are used widely in the industry..?
 
Consider Paul's rocket mass heater.
reply
    Bookmark Topic Watch Topic
  • New Topic