tags:

views:

60

answers:

3

Let's say I have methods with following signature

Object getData(int id) {  
  //create a entity manager
  //get data frm db
  //return data
}

updateData() {
  Object obj = getData(id) 
  //get entity manager
  //start transcation tx
  //update
  //commit tx
}

Now will it cause concurrency issue? Can data be stale in worst case? E.g. if I getData and by the time I update, if someone updates the data will my updateData will have stale data? Now can i use following:Will i solve the problem?

Object getData(int id,Entitymanager em) {  

      //get data frm db using em
      //return data
    }

 updateData() {
      Object obj = getData(id) 
      //get entity manager em
      //start transcation tx
      //getdata using getData(id,em)
      //commit tx
    }
+1  A: 

Yes, that can happen.

If you get an entity (version 1), someone else modifies it (creating version 2), then you modify version 1 and save it, any changes in version 2 will be lost.

To stop that from happening, use optimistic concurrency by adding a @Version attribute to your entity. If a commit has occurred between your get and update, an exception will be thrown. At the point you can choose your best option to deal with it.

GaryF
A: 

There can also be a problem in multi-threaded environment, if multiple access the same piece of code at the same time, it can create lock, for this you can use row level locking technique, that will help you.check out the below link.

http://download.oracle.com/docs/cd/B19306_01/server.102/b14220/consist.htm

Mrityunjay
Row-level locking won't help here: he's pulling all of the data outside of a transaction.
GaryF
will geting data and updating data inside same transcation will solve the problem?Plz see my new edit of original post
akp
Getting the data inside the transaction will mean that, with row locking, a concurrent update will be forced to wait on the completion of the first update. However, both will still run so your transactional block needs to take care that it doesn't overwrite anything done by another transaction.
GaryF
I still dint get it, will using the second approach in original post handle that?if now how can i solve it?.If i need to lock the row, how can i do it?
akp
@akp: i agree with your point, that row level locking wont help here, rather can u use synchronization technique, i am not too sure sure about this, as in i haven't used it , but this can help you out, as during synchronization, the synchronization manager will update all the references of that entity in a session, if others are also using it. This process is a bit costly, but can help you.
Mrityunjay
@akp : other than that you can use the approach that GaryF have written, that i also good, to have a version sort of thing in you entity.
Mrityunjay
A: 

If two separate requests access updateData() concurrently you may get stale data. You may handle the staleness by locking the fetched data in updateData(). If you're using Hibernate as your JPA provider you can lock the data as follows:

updateData() {
    Object obj = getData(id);
    Session session = (Session) em.getDelegate();
    session.refresh(obj, LockMode.UPGRADE);
}

The refresh is necessary because it may happen that between the fetching and the locking of the data another transaction completes in updateData.

Please keep in mind that the entity manager used in getData and updateData must be the same.

kraftan