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 13:15:32 -0600

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
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