Gordon ,
Thanks.. I shouldn't have used 'serialize' (poor choice of words). I meant locking. :-)
I will try what you mentioned below.. Hopefully it will take care of my problem.. I'll let you know..
Thanks .
Mauro Almeida
________________________________
From: Gordon Yorke [mailto:gordon.yorke_at_oracle.com]
Sent: Friday, April 17, 2009 8:45 AM
To: persistence_at_glassfish.dev.java.net
Subject: Re: multiple threads trying to modfiy an entity
You should not serialize the access that would prevent concurrent access to your application. What you need to ensure is that you are managing concurrent access through appropriate locking. If these conflicts occur rarely then I recommend using optimistic locking. Add @Version field to your entity (there are EclipseLink extensions to JPA if you can not update your entities). The @Version field will ensure any conflicts will be reported through an OptimisticLockException. If these conflicts are not rare then I recommend using pessimistic locking. JPA 1.0 did not provide support for pessimistic locking but if you switch your find to a JPQL query and add the hint. query.setHint(QueryHints.PESSIMISTIC_LOCK, PessimisticLock.Lock); Then each thread will have exclusive access to the corresponding row.
--Gordon
Mauro Almeida wrote:
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> <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>
<
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*
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>
<
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/persistencehttp:/java.sun.com/xml/ns/persistence/persistence_1_0.xsd>
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>
<
http://java.sun.com/xml/ns/persistencehttp:/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