persistence@glassfish.java.net

Re: multiple threads trying to modfiy an entity

From: Gordon Yorke <gordon.yorke_at_oracle.com>
Date: Thu, 16 Apr 2009 16:02:48 -0300

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