persistence@glassfish.java.net

RE: Re: multiple threads trying to modfiy an entity

From: Mauro Almeida <malmeida_at_localmatters.com>
Date: Thu, 16 Apr 2009 14:32:12 -0600

In the error scenario the db has one row, that's updated everytime an event happens in the application.

basically, a counter is increment by one.
When the app sends this sessionbean, let's say 24 messages, to have it update it counter, some msg are 'lost'

Counter shows only 23, 14, etc.... instead of 24.

How can I serialize the access?

Another way to say is: how can several client updated concurrently the DB, based on it's previous state.,
Thanks !


yes s and s1 was just an was just an email issue..



-----Original Message-----
From: Gordon Yorke [mailto:gordon.yorke_at_oracle.com]
Sent: Thu 4/16/2009 3:33 PM
To: persistence_at_glassfish.dev.java.net
Subject: Re: multiple threads trying to modfiy an entity
 
If any number of threads perform a find within different transactions
then these threads will not find the Entity with the specified ID and
these threads will attempt to persist an Entity with that same ID and
all but the first to write the data to the database will fail. This is
expected behaviour. You will need to retry that transaction.
How many updates are lost? Can you provide specifics on what and when
the updates are lost.

I see your code also has a typo (s1 vs s) but this must be an email
issue as this code would not compile otherwise.
               if (s == null) {

                    Stats *s* =
createStat(id);

                    // Now increment the proper count, based on the type
o msg received

                    switch (type) {

                        case TOTAL:

                            *s1*.setTotal(*s1*.getTotal()+1);

                            break;

                        case PARTIAL:

                            *s1*.setPartial(*s1*.getPartial()+1);

                            break;

                    }

                    em.persist(s1);

                    em.flush();

                } else {


--Gordon



Mauro Almeida wrote:
>
> The App is the one creating the ID. It is not auto sequentially generated
>
>
>
> That's why I was first doing a em.find() to see if entry already
> exists. (99% of my cases, it will exist) than I just em.merge().
>
>
>
> If em.find returned me null I would try to em.persit(). As you can see
> in the snippet below.
>
>
>
> The problems are:
>
> When table is emptyl.. I get a duplicated entry (2 threads trying to
> persist the same id)
>
> When there are entries...... Some updates are lost. The counter in the
> DB do not add up to the number of messages received by the sessionbean
>
> Thanks!
>
>
>
>
>
> Mauro Almeida
>
> ------------------------------------------------------------------------
>
> *From:* Gordon Yorke [mailto:gordon.yorke_at_oracle.com]
> *Sent:* Thursday, April 16, 2009 3:03 PM
> *To:* persistence_at_glassfish.dev.java.net
> *Subject:* Re: multiple threads trying to modfiy an entity
>
>
>
> For the duplicate inserts who is creating the Id? If multiple threads
> attempt to insert the same PK then you should expect Unique Constraint
> violations as multiple threads would have attempted to insert the same
> object in different transaction.
> What are the problems you are still experiencing with this SessionBean?
> --Gordon
>
> Mauro Almeida wrote:
>
> Gordon,
>
>
>
> Thanks.. I think I'm on the right track but it still not working.
>
>
>
> So. I'm injecting the the emf using @PersistenceUnit into the class
>
> Every method call, emf.createEntityManager()
>
> Then I join em.joinTransaction() before I do my find(), merge(), persist()
>
>
>
> I still have some race condition. I also have a different façade to a
> different Entity, and the results a much more off (the updates seems
> to get lost more often)
>
> I continue to have cache turned off on persistence.xml
>
>
>
> Any Ideas...?? THANKS !
>
>
>
>
>
> Following the code
>
>
>
> @Stateless
>
> public class MyFacade implements IMyFacade ()
>
>
>
> @PersistenceUnit(unitName="myUnit")
>
> Private EntityManagerFactory emf;
>
>
>
> public void updateEntry (StatsType type, int id)
> {
>
>
>
> EntityManager em = emf.CreateEntityManager()
>
> em.joinTransaction()
>
> try {
>
> Stats s = em.find(Stats.class, id);
>
> // if could not find entry in the DB, create it
>
> if (s == null) {
>
> Stats s =
> createStat(id);
>
> // Now increment the proper count, based on the
> type o msg received
>
> switch (type) {
>
> case TOTAL:
>
> s1.setTotal(s1.getTotal()+1);
>
> break;
>
> case PARTIAL:
>
> s1.setPartial(s1.getPartial()+1);
>
> break;
>
> }
>
> em.persist(s1);
>
> em.flush();
>
> } else {
>
> switch (type) {
>
> case TOTAL:
>
> s.setTotal(s.getTotal()+1);
>
> break;
>
> case PARTIAL:
>
> s.setPartial(s.getPartial()+1);
>
> break;
>
> }
>
> em.merge(s);
>
> em.flush();
>
> }
>
> } catch (Exception ex) {
>
> ex.printStackTrace();
>
> }
>
> If (em.isOpen())
>
> em.close();
>
> }
>
>
>
>
>
> }
>
>
>
> ------------------------------------------------------------------------
>
> *From:* Gordon Yorke [mailto:gordon.yorke_at_oracle.com]
> *Sent:* Thursday, April 16, 2009 8:53 AM
> *To:* persistence_at_glassfish.dev.java.net
> <mailto:persistence_at_glassfish.dev.java.net>
> *Subject:* Re: multiple threads trying to modfiy an entity
>
>
>
> Stateless session beans can be used by more than one client. The best
> practise is to inject an EntityManagerFactory and then for each
> invocation create an EntityManager within the method. Otherwise
> multiple threads may be using the same EM.
> --Gordon
>
> Mauro Almeida wrote:
>
> Hi,
>
>
>
> I have the following problem.
>
>
>
> I have a facade (a stateless bean, CMT) that has an entity Manager and
> a method where several threads can call to have for an entry updated..
>
>
>
> What is happening is that the database is not updated properly.
> Sometimes the counter is not incremented, which seems to me something
> related to the attachment of the entity with the DB. Also, when the
> table is initially empty and all N updates come at the same to the
> same row, it tells me it has a duplicate key.
>
>
>
> I'm using sailfing build 60g. The DB is a JavaDB database
>
>
>
> The façade looks like:
>
> @Stateless
>
> @TransactionManagement(TransactionManagermentType.CONTAINER)
>
> public class MyFacade implements IMyFacade ()
>
>
>
> @PersistenceContext(unitName="myunit")
>
> private EntityManager em;
>
>
>
> @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
>
> public void updateEntry (StatsType type, int id)
> {
>
> try {
>
> Stats s = em.find(Stats.class, id);
>
> // if could not find entry in the DB, create it
>
> if (s == null) {
>
> Stats s =
> createStat(id);
>
> // Now increment the proper count, based on the
> type o msg received
>
> switch (type) {
>
> case TOTAL:
>
> s1.setTotal(s1.getTotal()+1);
>
> break;
>
> case PARTIAL:
>
> s1.setPartial(s1.getPartial()+1);
>
> break;
>
> }
>
> em.persist(s1);
>
> em.flush();
>
> } else {
>
> switch (type) {
>
> case TOTAL:
>
> s.setTotal(s.getTotal()+1);
>
> break;
>
> case PARTIAL:
>
> s.setPartial(s.getPartial()+1);
>
> break;
>
> }
>
> em.merge(s);
>
> em.flush();
>
> }
>
> } catch (Exception ex) {
>
> ex.printStackTrace();
>
> }
>
> }
>
>
>
> The transactionManagement, the em.flush and TransactionAttributes
> annotation I've put then after my original attempts failed.
>
>
>
> persistence.xml looks like:
>
> <?xml version="1.0" encoding="UTF-8"?>
>
> <persistence version="1.0"
> xmlns="http://java.sun.com/xml/ns/persistence"
> <http://java.sun.com/xml/ns/persistence> xmlns:xsi=*MailScanner has
> detected a possible fraud attempt from "www.w3.org" claiming to be*
> "http://www.w3.org/2001/XMLSchema-instance"
> <http://www.w3.org/2001/XMLSchema-instance>
> xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
> http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
> <http://java.sun.com/xml/ns/persistencehttp:/java.sun.com/xml/ns/persistence/persistence_1_0.xsd>>
>
> <persistence-unit name="myunit" transaction-type="JTA">
>
> <jta-data-source>jdbc/castats</jta-data-source>
>
> <properties>
>
> <property name="toplink.jdbc.user" value="username"/>
>
> <property name="toplink.jdbc.password" value="passed"/>
>
> <!-- <property name="toplink.cache.type.default"
> value="NONE"/> -->
>
> </properties>
>
> </persistence-unit>
>
> </persistence>
>
>
>
>
>
> Can someone point in the right direction? Why Do I have this race
> condition?
>
>
>
>
>
>
>
> Mauro Almeida
>
>
>