Skip to main content

Surprising JPA (Toplink) Behaviour (glassfish v1 UR1)

43 replies [Last post]
pohl
Offline
Joined: 2006-10-27

Today my tenuous grasp on the theory of operation of JPA was shattered. I'd like to describe it on a high level, in hopes that someone can steer me in the right direction.

My team has been building a system that consists of some JAX-WS services, some JSF pages for data-entry, and a shared JPA layer through which the services and the pages read & write data. One team member was responsible for creating the JSF interface, and another for writing the services, and each cooperated on the JPA model layer where appropriate, both working within the same Netbeans project shared through an SVN repository.

The services work well, the data interface works well, and today we had our first integrated test on a real test server -- as opposed to the developer's desktops.

This is the context where I observed some very surprising behaviour: After spending some time entering some data through the JSF pages, I hit one of the web services and noticed that the new (or sometimes changed) rows were not showing up in the results from the services.

Isn't that curious? All this time I had assumed that merely by sharing a common JPA model layer, these two halves of my system would never have entity-freshness problems. Shouldn't the default behaviour be for one piece of JPA-using client code to always be able to see the results of other client code's changes? And vice-versa?

I admit this is my first project with all of these technologies, and there's probably some subtle one-liner that I'm missing. But where? Is it something the JSF managed beans are doing when they write? Is it something the web service is doing incorrectly when it selects? Is it some funky annotation parameter that I'm lacking?

Any help would be appreciated.

Here's an example idiom from the web services layer for selecting...

private static List runDescriptionQuery(){
EntityManager em = emf.createEntityManager();
List queryList = null;
//Query to get a List of all the available Wines
try{
Query query = em.createNamedQuery("WineCategories.findAllWineCategories");
queryList = query.getResultList();
}finally{
em.close();
}
return queryList;
}

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
koenhautekeete
Offline
Joined: 2006-05-25

Thanks for your replies,

It makes sense indeed to do a lookup instead of keeping the EntityManager reference in a ThreadLocal instance. Next to that, it avoids problems related to (ab)using a ThreadLocal instance.

Regards,

Koen

mvatkina
Offline
Joined: 2005-04-04

Koen,

You also need to keep in mind that an injected entity manager is a container-specific proxy that verifies expected transaction association and persistence context propagation rules. By passing the proxy around, you can break those rules.

regards,
-marina

pohl
Offline
Joined: 2006-10-27

I have finally resolved my stale data issue. You asked the question that pointed me in the
right direction (thank you for that):

[i]Now back to your stale data issue - is it a field data or a relationship reference?[/i]

Indeed, the code in our JSF pages was written assuming that the JPA layer would take care
of relationships automagically, and we've gone back and corrected that mistake. No more
stale data issues.

The whole business about the EMs and EMFs was good to discover & correct also,
but was not related to the symptom that I wanted to correct.

Thank you all for your help.

gyorke
Offline
Joined: 2005-06-21

JoinTransaction is only used for an ApplicationManaged Entity Manager.
[i][b]Section 5.7: [/b]When a JTA application-managed entity manager is used, if the entity manager is created outside the
scope of the current JTA transaction, it is the responsibility of the application to associate the entity
manager with the transaction (if desired) by calling EntityManager.joinTransaction.[/i]

All Application Managed Entity Managers are Extended, and that is the only option.
Container Managed Entity Managers can either be transactional or extended.

Is it possible for you to create a small example of what you are doing which reproduces your stale data issue? Perhaps you can provide a pseudo-code overview of the steps including the transactional boundaries?
--Gordon

mvatkina
Offline
Joined: 2005-04-04

Some thought and questions to add to the discussion...

1. A Container Managed EMF can be either a) injected via a @PersistenceUnit annotation, which is guaranteed to be available only in the list of managed components specified by the spec, or b) via JNDI lookup, which is available in any place a JNDI lookup is supported (i.e. in a wider range of classes).

Note, that if you use UserTransaction with a Container Managed EMF, an EM created from such EMF might need to join the transaction if such transaction began after the EM has been created:

EntityManager em = emf.createEntityManager();
utx.begin();
em.joinTransaction();
...
utx.commit();
em.close()

2. You can also use a Container Managed EM via either @PersistenceContext or the JNDI lookup. (same rules as above apply). See section 5 in the JPA spec for more information and basic examples.

3. Any Container Managed artifact (either EMF or EM) usually results in the proxy created by the container, i.e. its hashCode might not represent that actual inctance that handles the requests.

4. What kind of stale data are we talking about? Updates to a basic field or property should be visible to EM2 if EM1 has committed its transaction before the entity has been accessed in EM2 for the 1st time. Now, if EM2 has an EXTENDED persistence context, and that entity has been already loadded by EM2 in a previous transaction, its values will not get updated, unless either a) em.refresh() is called on that entit, b) em.clear() is called prior to accessing the entity again, or c) provider-specific hints used in the JPQL query.

thanks,
-marina

pohl
Offline
Joined: 2006-10-27

[i]Note, that if you use UserTransaction with a Container Managed EMF, an EM created from such EMF might need to join the transaction if such transaction began after the EM has been created:[/i]

I'm confused by this. The javadoc for that method says "This method should be called on a JTA [b]application managed EntityManager[/b] that was created outside the scope of the active transaction." Whereas you say that an EM one makes from a [b]container-managed EMF[/b] should do it.

Is the javadoc in conflict with what you wrote? Or is an EM considered application-managed even if it sprung from a container-managed EMF by way of emf.createEntityManager()?

http://java.sun.com/javaee/5/docs/api/javax/persistence/EntityManager.html#joinTransaction()

[i]Now, if EM2 has an EXTENDED persistence context, and that entity has been already loadded by EM2 in a previous transaction, its values will not get updated, unless either a) em.refresh() is called on that entit, b) em.clear() is called prior to accessing the entity again, or c) provider-specific hints used in the JPQL query.[/i]

Are EXTENDED persistence contexts the default? Nowhere does my application specify the persistence context type.

Here's some observations that stemmed from your suggestion, though: calling em.refresh() on the selecting code did, indeed, act as a workaround for the stale data issues I'm seeing.

I also tried em.clear() prior to the select. That, by itself, made no difference however.

mvatkina
Offline
Joined: 2005-04-04

Here are the answers to your questions that I have found in the spec:

[b]5.2.1 Obtaining an Entity Manager in the Java EE Environment[/b]
A container-managed entity manager is obtained by the application through dependency injection, or direct lookup of the entity manager in the JNDI namespace.[/b]

And in the example in this section:
[code]
@PersistenceContext(type=PersistenceContextType.EXTENDED)
EntityManager orderEM;
[/code]

[b]5.2.2 Obtaining an Application-managed Entity Manager[/b]
An application-managed entity manager is obtained by the application from an entity manager factory.

[b]3.3 Persistence Context Lifetime[/b]
By default, the lifetime of the persistence context of a container-managed entity manager corresponds to the scope of a transaction (i.e., it is of type PersistenceContextType.TRANSACTION).
...
The scope of the persistence context of an application-managed entity manager is extended.

[b]5.6.4.2 Container-managed Extended Persistence Context[/b]
[code]
@Stateful
@Transaction(REQUIRES_NEW)
public class ShoppingCartImpl implements ShoppingCart {
@PersistenceContext(type=EXTENDED)
EntityManager em;
[/code]

Now back to your stale data issue - is it a field data or a relationship reference? If it's that latter, it's the user responsibility to maintain the relationships on both sides. Another possible problem would be an update from 2 EMs of the same PK. If in EM1 the only change is in the field 'x' and in EM2 an entity with the same PK is changed in the field 'y', then the update statement to the database will include only the changed columns, but the cached data will have the last committed view of the entity with this PK.

regards,
-marina

gyorke
Offline
Joined: 2005-06-21

Marina,
Your last statement here is incorrect. The cached data will receive the same updates as the database and mirror the data in the database. Only the changes from each EM will be placed in the cache not the entire state of the EM as suggested by you.
--Gordon

mvatkina
Offline
Joined: 2005-04-04

Sorry for the confusion.

-marina

cprashantreddy
Offline
Joined: 2004-04-19

> with the new TopLink is a bug ( https://glassfish.dev.java.net/issues/show_bug.cgi?id=2643 ).

I have seen this exception even when application does *not* use ApplicationManaged EMF and ContainerManaged EMF on same PU.

I see this exception when i undeploy the WAR which uses ApplicationManaged EMF only, usually following not clean undeployment because of JarLocking.

I will try and code up a replication.

-Prashant

gyorke
Offline
Joined: 2005-06-21

What type of container are you running in? Have you considered using a Container Managed Entity Manager instead of an Application Managed one? The exception you are seeing is most likely the result of a race condition between two or more threads attempting to initialize the Persistence Unit. Persistence Units are lazily initialized when Application Managed and it appears from looking at the code that when deployed without the java agent (ie. in a container) a race condition exists that can result in this exception. If you can stagger the calls to the first createEntityManager() call or call createEntityManager() when you first create the EMF then discard the EntityManager the race condition should be removed. I have filed issue numbered 2640.
--Gordon

pohl
Offline
Joined: 2006-10-27

I just got a fine education on #glassfish, wherein I opened the conversation by confessing that
there are two distinct halves of my codebase, and each one obtains their EMFs differently.

One half is a bunch of JSF managed-beans that were generated by Netbeans. they get their
EMFs by way of an annotation:

@PersistenceUnit(unitName = "RCCLPU")
private EntityManagerFactory emf;

The other half of the code is some helper POJOs that are called by some JAX-WS services. These were written by a different developer, who decided to get EMF references via...

private static EntityManagerFactory emf = Persistence.createEntityManagerFactory("RCCLPU");

It wasn't until the two halves of the code were used together that this situation arose.

gyorke
Offline
Joined: 2005-06-21

So this is the root cause of these issues. What you were getting in the older version of TopLink was 2 separate Persistence Units and the cache was not synched requiring not using a shared cache or repeated refreshes. This separate PU behaviour and the exception with the new TopLink is a bug ( https://glassfish.dev.java.net/issues/show_bug.cgi?id=2643 ).

The solution for your code is to choose either Application Managed EMFs or Container Managed EMFs. I would recommend Container Managed EMFs.
--Gordon

pohl
Offline
Joined: 2006-10-27

I agree that I need to pick one or the other (container managed EMFs versus application-managed), and I'm choosing container-managed.

I was able to perform a simple experiment. I took a simple servlet in my system called "Startup". It exists only for the sake if its init() method -- I wanted to load some configuration and needed a startup event and that's the best thing I could think of.

I figured this would be a perfect place to put my @PersistenceUnit annotation, and in the body of the init() method I set the emf into a static member of the POJO that formerly used application-managed EMFs.

After testing this, however, I'm still observing the stale-data problem (where jax-ws services are not showing data entered into the JSF pages). So apparently, even though both regions of code are now using "container managed" EMFs, they're not actually getting the same EMF. To test this theory, I logged the hashcode of each EMF and they are, indeed different.

XMLFileGenerator: receiving EntityManagerFactory, hash=1848253
RestaurantMenuItemsController: emf=12769563

Any idea what gyrations I can go through to make sure glassfish hands me the same EMF in my JSF managed beans as I'm getting in my servlet?

pohl
Offline
Joined: 2006-10-27

And it keeps getting more interesting. I decided that I wanted to be able to guarantee that all code is getting the same EMF, just for the sake of sanity. So I created a little singleton/factory pattern, and replaced all @PersistenceUnit annotations with calls to MyFactory.getEMF(), and I replaced all of the Persistence.createEntityManagerFactory() calls with the same.

Logging the hashcodes has confirmed that everything is using the same EMF now. w00t!

Oh, but here's the sad part...I'm still getting the same stale-data behaviour: I enter data into my JSF pages and it doesn't show up in my web services.

There must be something else we're doing wrong. :-(

pohl
Offline
Joined: 2006-10-27

The above post is innaccurate, sorry. Now the behaviour is that the data is not making it into the database at all when I enter it into the JSF pages.

Marina Vatkina

If you switched from injection to Persistence.createEMF, you need to use
EntityTransaction to commit the changes.

-marina

glassfish@javadesktop.org wrote:
> The above post is innaccurate, sorry. Now the behaviour is that the data is not making it into the database at all when I enter it into the JSF pages.
> [Message sent by forum member 'pohl' (pohl)]
>
> http://forums.java.net/jive/thread.jspa?messageID=208524
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@glassfish.dev.java.net
> For additional commands, e-mail: users-help@glassfish.dev.java.net
>

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@glassfish.dev.java.net
For additional commands, e-mail: users-help@glassfish.dev.java.net

pohl
Offline
Joined: 2006-10-27

Wow, thank you for pointing that out. I never would have discovered that on my own. I'm now wondering the same thing that this blogger asked over a year ago...

http://trycatchfinally.blogspot.com/2006/01/why-entitytransaction.html

...Anyway, this is not at all an appealing prospect -- to have to go through all of these JSF managed beans and rewrite all of the persistence methods with uncertain outcome.

At this point, it would be much nicer if I could get container-managed EMF injection to place nice.

Marina Vatkina

The new interface was added for the cases when UserTransaction is not available.
And (IMHO) to simplify a complicated enough combination of configurations, it
was chosen as the only one for EMs obtained via Persistence.createEMF.

You can always replace an injection with JNDI lookup if the location is not that
of a component that supports the injection.

HTH,
-marina

glassfish@javadesktop.org wrote:
> Wow, thank you for pointing that out. I never would have discovered that on my own. I'm now wondering the same thing that this blogger asked over a year ago...
>
> http://trycatchfinally.blogspot.com/2006/01/why-entitytransaction.html
>
> ...Anyway, this is not at all an appealing prospect -- to have to go through all of these JSF managed beans and rewrite all of the persistence methods with uncertain outcome.
>
> At this point, it would be much nicer if I could get container-managed EMF injection to place nice.
> [Message sent by forum member 'pohl' (pohl)]
>
> http://forums.java.net/jive/thread.jspa?messageID=208527
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@glassfish.dev.java.net
> For additional commands, e-mail: users-help@glassfish.dev.java.net
>

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@glassfish.dev.java.net
For additional commands, e-mail: users-help@glassfish.dev.java.net

pohl
Offline
Joined: 2006-10-27

It keeps getting more interesting. I tried our code on v2b39 to see if it behaved differently, and discovered an exception...Not sure what to make of it...

Exception [TOPLINK-28009] (Oracle TopLink Essentials - 2.0 (Build b39-rc (03/13/2007))): oracle.toplink.essentials.exceptions.EntityManagerSetupException
Exception Description: Attempted to redeploy a session named file:/Users/pohl/RCCL/build/web/WEB-INF/classes/-RCCLPU without closing it.
at oracle.toplink.essentials.exceptions.EntityManagerSetupException.attemptedRedeployWithoutClose(EntityManagerSetupException.java:76)
at oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerSetupImpl.addSessionToGlobalSessionManager(EntityManagerSetupImpl.java:262)
at oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerSetupImpl.initServerSession(EntityManagerSetupImpl.java:879)
at oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:188)
at oracle.toplink.essentials.internal.ejb.cmp3.base.EntityManagerFactoryImpl.getServerSession(EntityManagerFactoryImpl.java:78)
at oracle.toplink.essentials.internal.ejb.cmp3.base.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:111)
at oracle.toplink.essentials.internal.ejb.cmp3.base.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:105)
at oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:76)
at com.sun.enterprise.util.EntityManagerFactoryWrapper.createEntityManager(EntityManagerFactoryWrapper.java:91)
at net.nanonation.rccl.beans.RestaurantsController.getEntityManager(RestaurantsController.java:52)

...so it looks like I need a process-wide singleton of the emf, which should be easy to accomplish. That will be my next experiment.

Marina Vatkina

Before you make a change, can you please file a bug with your existing code that
reproduces the exception?

thanks,
-marina

glassfish@javadesktop.org wrote:
> It keeps getting more interesting. I tried our code on v2b39 to see if it behaved differently, and discovered that createEntityManagerFactory() throws a hissy fit if it's called multiple times witih the same PU name. Or, at least, that's what I'm guessing this exception means...
>
> Exception [TOPLINK-28009] (Oracle TopLink Essentials - 2.0 (Build b39-rc (03/13/2007))): oracle.toplink.essentials.exceptions.EntityManagerSetupException
> Exception Description: Attempted to redeploy a session named file:/Users/pohl/RCCL/build/web/WEB-INF/classes/-RCCLPU without closing it.
> at oracle.toplink.essentials.exceptions.EntityManagerSetupException.attemptedRedeployWithoutClose(EntityManagerSetupException.java:76)
> at oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerSetupImpl.addSessionToGlobalSessionManager(EntityManagerSetupImpl.java:262)
> at oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerSetupImpl.initServerSession(EntityManagerSetupImpl.java:879)
> at oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:188)
> at oracle.toplink.essentials.internal.ejb.cmp3.base.EntityManagerFactoryImpl.getServerSession(EntityManagerFactoryImpl.java:78)
> at oracle.toplink.essentials.internal.ejb.cmp3.base.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:111)
> at oracle.toplink.essentials.internal.ejb.cmp3.base.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:105)
> at oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:76)
> at com.sun.enterprise.util.EntityManagerFactoryWrapper.createEntityManager(EntityManagerFactoryWrapper.java:91)
> at net.nanonation.rccl.beans.RestaurantsController.getEntityManager(RestaurantsController.java:52)
>
>
> ...so it looks like I need a process-wide singleton of the emf, which should be easy to accomplish. That will be my next experiment.
> [Message sent by forum member 'pohl' (pohl)]
>
> http://forums.java.net/jive/thread.jspa?messageID=208484
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@glassfish.dev.java.net
> For additional commands, e-mail: users-help@glassfish.dev.java.net
>

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@glassfish.dev.java.net
For additional commands, e-mail: users-help@glassfish.dev.java.net

koenhautekeete
Offline
Joined: 2006-05-25

We encounter the same problem with toplink-essentials.

Architecture:
Container managed persistence and container managed transactions using JTA.
The EntityManager is injected in a Stateless Session Bean. During the execution of the business method/transaction, the same EntityManager is used, it is contained in a ThreadLocal variable to provide easy access to it.

The Stateless Session Bean is the only way to update data in the database.
The session bean is used by the web container and by a Java EE client application (batch processing).

When we first encountered the stale object problem, we could solve it by adding the following rule to persistence.xml:

This solved the stale object problem, or so we thought...

It seems that we still have the stale object problem (probably a reference(collection) that is stale). We are still tracing to find the exact cause - we cannot always reproduce the problem.

We are not using any toplink specific query hints to refresh the objects. That should not be needed - even if the same objects are loaded and modified in subsequent calls to a business method - since the default PersistenceContextType is TRANSACTION, and not EXTENDED.

The main difference with the problem stated in this thread is that glassfish is used. Our application runs on OC4J 10.1.3.1 with toplink-essentials. (The problem is not cluster related).

mvatkina
Offline
Joined: 2005-04-04

I'm not sure I understand your description. Are you saying that you store the injected EntityManager reference in a ThreadLocal? Or do you expect the container to do it?

thanks,
-marina

koenhautekeete
Offline
Joined: 2006-05-25

Excuse me if it my description is not clear.

The EntityManager is injected in the Stateless Session Bean as follows:

@PersistenceContext(unitName = "default")
private EntityManager em;

If a business method is executed, the em instance is manually (not by the container) set in a ThreadLocal variable, so we can use it "everywhere" we need it during the execution of our business method.

Regards,

Koen

ksak
Offline
Joined: 2005-05-20

Hi Koen,

ThreadLocal is not an API that should be used by application code to pass context around.
If you need access to a container-managed EntityManager from code other than the ejb
bean class itself you can always retrieve the same dependency from its component
environment. Any Class, Field, or Method-level Java EE environment annotation always
corresponds to an entry within the component environment in which it is declared.
If the case of field annotation, the dependency name is specified by either the name()
attribute or defaults to /.

So, given your example, any other utility code running within the scope of the SLSB
invocation would retrieve the container-managed entity manager as follows :

EntityManager em = (EntityManager) new InitialContext().lookup
("java:comp/env//em");

Providing the name() attribute when declaring the dependency makes things easier :
@PersistenceContext(name="myem_ref", unitName="default")

then the lookup is :

EntityManager em = (EntityManager) new InitialContext().lookup("java:comp/env/myem_ref");

koenhautekeete
Offline
Joined: 2006-05-25

Hi ksak,

Are there any drawbacks by using a ThreadLocal for this purpose? I mean, can we expect unexpected behaviour of the persistence layer?

I can easily change the way context is passed around, since the ThreadLocal is encapsulated in its own class.

Regards,

Koen

ksak
Offline
Joined: 2005-05-20

ThreadLocal is not part of the Java EE programming model. It's much too low-level.
It's typically used by system-level code as part of the Java EE container itself, so it's not
something that is recommended. It's much better to use a portable, application-level
approach to acquire any resources you need. Container-managed EntityManagers were
designed with persistence context propagation in mind.

--ken

gyorke
Offline
Joined: 2005-06-21

I am quite surprised that you are having stale data issues when working with the same JPA layer. Are you sure that all processes are using the same Persistence Unit; the same EntityManagerFactory?
The code you supplied appears to be creating a new EntityManager for every access is this true of your entire system or is an EntityManager being used repeatedly by different requests?
Is it possible that the stale data is already managed within the EntityManager being queried? Changes made in one EntityManager will not automatically appear in entities already managed in another EntityManager.

The only time a refresh should be required is if you have another non JPA application modifying the database (in which case setting non-shared caching through persistence.xml properties may be suggested if the quantity of conflicts is large) or if you wish to refresh an active EntityManager with changes from another EntityManager.
--Gordon

pohl
Offline
Joined: 2006-10-27

I have been going to great lengths to explore the various options that I have in order
to unify the schizophrenic codebase that I have before me. I am reluctant to change
everything into being application-managed, because of the annoying need to switch from
UserTransaction to EntityTransaction (thankfully pointed out by Marina Vatkina above.)

I don't think that I have the time to figure out how to make everything use @PersistenceUnit
literally, because i have a lot of JPA code that doesn't reside directly in managed components,
and therefore they don't get any annotation-processor love like the JSF managed beans do. And,
frankly, it's not clear what sort of managed-component I'd stuff that code into anyway. I'd like
my application to be deployable in a plain WAR -- that seems to limit my managed-component
options to servlets, jax-ws services, and JSF managed-beans.

But what if I can take an EMF that I obtain in these managed-components out into the
other code -- that should ensure that everything is using the same EMF, and hopefully
alleviate the stale data woes, correct? Regardless of whether I am correct in that assumption,
(and please do tell me if it's ill-conceived) I did proceed from it with experiment, at length.

The basic idea was to start by logging the hashcode of the EMFs used by different parts of
the code and keep playing around until I could get both halves of the code to be using the
same EMF. This turns out to have been much, much harder than it sounds like it should be.

The reason that it was difficult is that the POJO code needs to get an EMF very early in
the startup process, because one of the first things that my application does is generate
some xml files and write them to the static docroot. This code may again be triggered
later to regenerate the xml files after the JSF pages have done some edits to the database.
The JSF managed-beans, on the other hand, may never be instantiated -- for example, say
no-one needs to do any data entry on that day -- and may therefore never be able to inject
an EMF into my hand-rolled singleton/factory.

So, to be clear, my general strategy was to pick some managed component, arm it with
@PersistenceUnit, and a @PostConstruct method that calls a static setter on MyFactory.

Sensible?

The first managed component that I chose was a servlet I had lying around (the one that
triggered the xml-generation from its init() method) and decided to have it provide the EMF
for the other half of the code. The result? The hashcodes revealed that the JSF managed-bean
used during data-entry is still using a different EMF han the servlet provided
to the POJO code.

Darn. Well, maybe that's because my servlet had nothing to do with JSF. So I wrote a replacement
for the FacesServlet, one that makes a private FacesServlet instance and delegates
all calls to it. Although the exercise resulted in a fully-functioning replacement for FacesServlet,
the EMF that it injected into my POJO code is also different from the EMF being used by the
relevant JSF managed-bean that does the data entry. Moreover, it's different from the EMF that
glassfish provided to the first servlet.

So I added the @PersistenceUnit/@PostConstruct directly to the JSF managed bean in
question. Even though i can't depending on this managed-bean being instantiated, I was
desparate to see what would happen if both halves of my system ended up using the same
EMF. Finally, the logging showed hashcodes that proved that both the POJO code and
the JSF managed-bean were using the same EMF. W00t! Sadly, this did not alleviate
the stale data issues. (!?) Pardon me, but shouldn't it have?

Also, there's something I'd like to know: if EMFs are so dreadfully expensive to create, why
doesn't glassfish bother to inject the same one into all of these different managed components?
Let me show you the astonishing collection of different EMF instances that I'm seeing in my
logs...

RCCL PersistenceUnitInjector: injecting emf @PostConstruct. // my FacesServlet facade
RCCL ServerConfig receiving EntityManagerFactory: 9271677
RCCL DashboardController: injected emf = 1456184 // one JSF managed-bean
RCCL RestaurantsController: injected emf=9319553 // another JSF managed-bean
RCCL RestaurantMenuItemsController: injected emf=12990151 // another JSF managed-bean
RCCL RestaurantCategoriesController: injected emf=2363461 // another JSF managed-bean.

It goes on, and on, and on. Apparently glassfish doesn't think it's important that all of my
code use the same EMF, which I find surprising since I'm getting the sense in this forum
that glassfish ought to think otherwise.

But perhaps that is all besides the point, since the one thing that I did managed to learn from
all of this is that even when I did manage to finally get the same EMF into both halves of
my code I'm still getting staleness of data.

gyorke
Offline
Joined: 2005-06-21

As long as you are not expecting any active Entity Manager to be updated with changes from another Entity Manager then you should not have stale data issues when using only a single EMF (or EMFs from the same PU). Unless your issues are with updates outside of JPA?

EMFs in TopLink Essentials are not heavy weight objects. They are backed by a shared heavy weight object called a ServerSession.

--Gordon

pohl
Offline
Joined: 2006-10-27

[i]As long as you are not expecting any active Entity Manager to be updated with changes from another Entity Manager then you should not have stale data issues when using only a single EMF (or EMFs from the same PU). [/i]

This first version of my system calls emf.createEntityManager for each interaction
with the database, and calls em.close() in the finally block. I only have one PU.

[i]Unless your issues are with updates outside of JPA?[/i]

There is no other process that touches the database, nor is there any plain JDBC code
in the same application that touches the database. Everything that interacts with the
database is JPA code within the same WAR.

[i]EMFs in TopLink Essentials are not heavy weight objects. They are backed by a shared heavy weight object called a ServerSession.[/i]

Well, at least I can stop obsessing about having a singleton EMF. Thank you.

legolas

Very good discussion and I learned some good points from this thread.
But i have some basic questions regard to this thread content:

-What is different between two following mechanisms?

[code]
@PersistenceUnit(unitName = "RCCLPU")
private EntityManagerFactory emf;
[/code]

and

[code]
private static EntityManagerFactory emf =
Persistence.createEntityManagerFactory("RCCLPU");
[/code]

- What are different between UserTransaction and EntityTransaction ?

- What are differences between "Container Managed" Entity Manager and
"Application Managed" one?

Thanks

--
View this message in context: http://www.nabble.com/Surprising-JPA-%28Toplink%29-Behaviour--%28glassfi...
Sent from the java.net - glassfish users mailing list archive at Nabble.com.

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@glassfish.dev.java.net
For additional commands, e-mail: users-help@glassfish.dev.java.net

rickcarson
Offline
Joined: 2004-03-04

The big difference between the two mechanisms is that one of them relies upon annotation processing.

If you were deploying to Tomcat for instance in a JAX-WS web service and wanted to use the annotation, then you might very well find yourself entirely out of luck.

My understanding of the process is this:
You deploy the Webservice (eg to Tomcat)
The JAX-WS aware annotation processor goes "oh! I know what this is!" and it processes the JAX-WS annotations. (Produces the WSDL etc)
The JAX-WS aware annotation processor hits the EJB 3.0 annotation for injecting the EJB 3.0 Persistence Unit. It goes "I have no fscking clue what this horrible thing is".
The JAX-WS aware annotation processor pitches a fit, tosses its toys out of the cot and/or spits the dummy.
This is a bad thing (tm).

Now you might say "that sucks! JAX-WS is stupid". However, this seems to be a limitation with annotations, you may or may not be able to mix different kinds of annotations, depending on how the system will be delivered.

Additionally, not having to write your own WSDL is such an enormously huge benefit, that it massively outweighs any other disadvantages, such as having to slap in 2-3 extra lines of code per EJB driven sertvice. (And it is boiler plate code, so there are OO ways of handling it anyway).

-------

Recommendations:

(1) have a look into the Hibernate (JBoss??) Tree Cache - a cache distributed across multiple machines.

(2) EJB 3.0 has (if I remember correctly) a veritable plethora of ways to check if the write/read is working with dirty data, which may be worth investigating. I think you have to add a number or a timestamp to each row in the database, and then every time you do a write it checks to make sure that you are dealing with the most recent timestamp, if not it assumes it is dirty, bad, evil and wrong (tm).

See also:

EntityManager.refresh(Object)

refresh
void refresh(Object entity)Refresh the state of the instance from the database, overwriting changes made to the entity, if any.

Parameters:
entity -
Throws:
IllegalStateException - if this EntityManager has been closed.
IllegalArgumentException - if not an entity or entity is not managed
TransactionRequiredException - if invoked on a container-managed entity manager of type PersistenceContextType.TRANSACTION and there is no transaction.
EntityNotFoundException - if the entity no longer exists in the database.

rickcarson
Offline
Joined: 2004-03-04

The annotation for row versioning for the dirty read/write problem is... @Version

javax.persistence
Annotation Type Version

--------------------------------------------------------------------------------

@Target(value={METHOD,FIELD})
@Retention(value=RUNTIME)
public @interface VersionThis annotation specifies the version field or property of an entity class that serves as its optimistic lock value. The version is used to ensure integrity when performing the merge operation and for optimistic concurrency control.

Only a single Version property or field should be used per class; applications that use more than one Version property or field will not be portable.

The Version property should be mapped to the primary table for the entity class; applications that map the Version property to a table other than the primary table will not be portable.

The following types are supported for version properties: int, Integer, short, Short, long, Long, Timestamp.

Example:

@Version
@Column(name="OPTLOCK")
protected int getVersionNum() { return versionNum; }

Since:
Java Persistence 1.0

mayankmishra
Offline
Joined: 2006-03-13

Just wondering, have you tried Toplink JPA query hints. There is a hint for toplink.refresh, which controls toplinks cache.

You can use that as in the query,
@QueryHint(name=REFRESH, value=HintValues.TRUE)

Hope this helps. :)

With Regards,
Mayank

Ryan de Laplante

I'm not an expert on the subject but ran into something similar. I
found that when other programs changed records in a table that I had
previously loaded using JPA entities, when I queried the table again the
fresh data was not loaded. This is because of caching. I ended up
having to disable caching using a query hint. I don't remember the
syntax off the top of my head but it was toplink specific.

Ryan

glassfish@javadesktop.org wrote:
> Today my tenuous grasp on the theory of operation of JPA was shattered. I'd like to describe it on a high level, in hopes that someone can steer me in the right direction.
>
> My team has been building a system that consists of some JAX-WS services, some JSF pages for data-entry, and a shared JPA layer through which the services and the pages read & write data. One team member was responsible for creating the JSF interface, and another for writing the services, and each cooperated on the JPA model layer where appropriate, both working within the same Netbeans project shared through an SVN repository.
>
> The services work well, the data interface works well, and today we had our first integrated test on a real test server -- as opposed to the developer's desktops.
>
> This is the context where I observed some very surprising behaviour: After spending some time entering some data through the JSF pages, I hit one of the web services and noticed that the new (or sometimes changed) rows were not showing up in the results from the services.
>
> Isn't that curious? All this time I had assumed that merely by sharing a common JPA model layer, these two halves of my system would never have entity-freshness problems. Shouldn't the default behaviour be for one piece of JPA-using client code to always be able to see the results of other client code's changes? And vice-versa?
>
> I admit this is my first project with all of these technologies, and there's probably some subtle one-liner that I'm missing. But where? Is it something the JSF managed beans are doing when they write? Is it something the web service is doing incorrectly when it selects? Is it some funky annotation parameter that I'm lacking?
>
> Any help would be appreciated.
>
> Here's an example idiom from the web services layer for selecting...
>
> private static List runDescriptionQuery(){
> EntityManager em = emf.createEntityManager();
> List queryList = null;
> //Query to get a List of all the available Wines
> try{
> Query query = em.createNamedQuery("WineCategories.findAllWineCategories");
> queryList = query.getResultList();
> }finally{
> em.close();
> }
> return queryList;
> }
> [Message sent by forum member 'pohl' (pohl)]
>
> http://forums.java.net/jive/thread.jspa?messageID=208299
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@glassfish.dev.java.net
> For additional commands, e-mail: users-help@glassfish.dev.java.net
>
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@glassfish.dev.java.net
For additional commands, e-mail: users-help@glassfish.dev.java.net

pohl
Offline
Joined: 2006-10-27

[i]I'm not an expert on the subject but ran into something similar. I
found that when other programs changed records in a table that I had
previously loaded using JPA entities, when I queried the table again the
fresh data was not loaded. This is because of caching. I ended up
having to disable caching using a query hint. I don't remember the
syntax off the top of my head but it was toplink specific.
[/i]

That's exactly the sort of behaviour that I had suspected all along. But
never in my wildest visions did I imagine seeing this phenomenon between
two pieces of code using the same JPA layer [b]in the same process[/b] in
the same WAR.

I can try the Toplink-specific hints suggested by mayankmishra below,
but I'm still flummoxed that this isn't default JPA policy.

Ryan de Laplante

I don't think caching should be turned off by default, but I do think
that it is very weird for JPA's internal cache to not be updated when
you make a change using the entity manager, then load the same entity
again using the same entity manager. I would expect the loaded entity
to be up to date.

However if an external program modified the database, I would not expect
the cache to know to update itself. In that case, you would need to
disable caching.

Ryan

glassfish@javadesktop.org wrote:
> [i]I'm not an expert on the subject but ran into something similar. I
> found that when other programs changed records in a table that I had
> previously loaded using JPA entities, when I queried the table again the
> fresh data was not loaded. This is because of caching. I ended up
> having to disable caching using a query hint. I don't remember the
> syntax off the top of my head but it was toplink specific.
> [/i]
>
> That's exactly the sort of behaviour that I had suspected all along. But
> never in my wildest visions did I imagine seeing this phenomenon between
> two pieces of code using the same JPA layer [b]in the same process[/b] in
> the same WAR.
>
> I can try the Toplink-specific hints suggested by mayankmishra below,
> but I'm still flummoxed that this isn't default JPA policy.
> [Message sent by forum member 'pohl' (pohl)]
>
> http://forums.java.net/jive/thread.jspa?messageID=208408
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@glassfish.dev.java.net
> For additional commands, e-mail: users-help@glassfish.dev.java.net
>
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@glassfish.dev.java.net
For additional commands, e-mail: users-help@glassfish.dev.java.net

pohl
Offline
Joined: 2006-10-27

[i]I don't think caching should be turned off by default, but I do think
that it is very weird for JPA's internal cache to not be updated when
you make a change using the entity manager, then load the same entity
again using the same entity manager. I would expect the loaded entity
to be up to date. [/i]

Ok, well that may be the issue. Each subsystem is getting a different
EntityManager from the EntityManagerFactory each time it needs to
interact with the persistent store.

Is that contrary to what should be done? Should I keep an EntityManager
singleton around somewhere and have all code use it?

(Are they thread-safe, BTW?)

Jason Lee

EntityManager is not thread-safe, and each EM has its own
PersistenceContext, so if you have multiple threads getting an EM from
an EMF, I think they're going to be isolated from each other, so an
update with one EM will not be visible from another EM. Into what kind
of object are you injecting the EMF?

-----
Jason Lee, SCJP
Senior Software Engineer
http://www.iec-okc.com

> -----Original Message-----
> From: glassfish@javadesktop.org [mailto:glassfish@javadesktop.org]
> Sent: Friday, March 16, 2007 10:39 AM
> To: users@glassfish.dev.java.net
> Subject: Re: Surprising JPA (Toplink) Behaviour (glassfish v1 UR1)
>
> [i]I don't think caching should be turned off by default, but
> I do think that it is very weird for JPA's internal cache to
> not be updated when you make a change using the entity
> manager, then load the same entity again using the same
> entity manager. I would expect the loaded entity to be up to
> date. [/i]
>
> Ok, well that may be the issue. Each subsystem is getting a
> different EntityManager from the EntityManagerFactory each
> time it needs to interact with the persistent store.
>
> Is that contrary to what should be done? Should I keep an
> EntityManager singleton around somewhere and have all code use it?
>
> (Are they thread-safe, BTW?)
> [Message sent by forum member 'pohl' (pohl)]
>
> http://forums.java.net/jive/thread.jspa?messageID=208426
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@glassfish.dev.java.net
> For additional commands, e-mail: users-help@glassfish.dev.java.net
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@glassfish.dev.java.net
For additional commands, e-mail: users-help@glassfish.dev.java.net

pohl
Offline
Joined: 2006-10-27

[i]EntityManager is not thread-safe, and each EM has its own
PersistenceContext, so if you have multiple threads getting an EM from
an EMF, I think they're going to be isolated from each other, so an
update with one EM will not be visible from another EM. Into what kind
of object are you injecting the EMF?[/i]

Ok, so a singleton EntityManager is clearly the wrong thing.

I don't think I even have a singleton EntityManagerFactory. Each subsystem
has an object that keeps its own private static reference to an EMF. Whether
or not they're referring to the same EMF sort of depends upon the semantics
of...

emf = Persistence.createEntityManagerFactory("FooPU");

...if Persistence.createEntityManagerFactor() returns a singleton, then I have
a singleton factory. If not, then I don't.

Who knows?

gyorke
Offline
Joined: 2005-06-21

With TopLink Essentials you will be getting a different EntityManagerFactory each time Persistence.createEntityManagerFactor()is called but each of these factories will be hooked together in the back end and as long as you pass in the same Persistence Unit name (or no name for the default PU) they will all be connected to the same Persistence Unit and cache.
--Gordon

pohl
Offline
Joined: 2006-10-27

Very curious, then. We are indeed using the same PU name everywhere.