-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 31 posts ]  Go to page 1, 2, 3  Next
Author Message
 Post subject: Nearly impossible to synchronize properly in Hibernate
PostPosted: Mon Nov 10, 2003 11:09 am 
Beginner
Beginner

Joined: Mon Sep 08, 2003 6:52 am
Posts: 46
Hi there.

I've been using Hibernate for awhile, and I really like it. But I find that there is a
major, major issue.

Synchronization.

Synchronization in an enterprise application can be extremely complicated. Libraries
such as Hibernate need to support different models of synchronization. It is completely
unreasonable for a library to dictate synchronization policy to the applications that use it.

I'm finding it extremely difficult to synchronize object access in my application.

Let's start with the JVM level cache. Hibernate stores it's own information about an entity
in the cache, but not the entity itself. So different Sessions accessing an entity will start
with the same information, but will have different copies of the entity itself. This means
synchronized methods and the synchronized keyword on the entities themselves will not work.
This basically renders the cache useless from a synchronization point of view.

Okay, so we need to do clever synchronization at the application level - as it says in the docs
"The Session is not threadsafe. We can't see why you would need to share a session between
two concurrent threads but if you must, make sure your threads carefully synchronize on the
Session object before accessing it. "

So you add all your synchronization to the session. That gets you pretty far.

Unfortunately, there are a few hidden gotchas. The objects that any given session hydrates
have their own handle to the session. An example of this is a lazily loaded collection of some
sort. When the collection needs to load, it starts calling methods on the Session object - but
there is no way to synchronize that access. There are three ways that I can see to get around
this issue. 1) make all collections non-lazy - this is likely to have a disastrous performance
impact, so isn't particulary appealing. 2) Don't use the one-to-many tag (and other similar tags) -
this doesn't strike me as a good solution, those tags are why I'm using Hibernate in the first
place. 3) Go under the covers and try to use some form of synchronized Session.

That leaves us trying to go under the covers.

For the sake of argument, let's say we want to use a class called SynchronizedSessionImpl
that is properly synchronized.

We need a way to change the behaviour of the SessionFactory to return
SynchronizedSessionImpl objects from the various openSession methods.

As it turns out, this is very, very difficult. There are a number of hurdles to overcome.

Hurdle 1) Configure only knows about SessionFactoryImpl. Solution: add a property
(to Environment I guess?) that specifies the SessionFactory class name to use. There are
secondary effects to this, like having to extend the SessionFactory interface to have some
sort of init method, where the Configuration, Properties and Interceptor are passed in.

So now we need to actually implement a SynchronizedSessionFactoryImpl.

Hurdle 2) SessionFactoryImpl is declared final. The obvious implementation is to subclass
SessionFactoryImpl, override the openSession methods, and leave the rest alone. The two
solutions to SessionFactoryImpl that I can see are either cut and paste all the code, or modify
SessionFactoryImpl to allow subclassing.

Okay say now we have a SynchronizedSessionFactoryImpl, we need SynchronizedSessionImpl
objects being returned from openSession().

Hurdle 3) SessionImpl is declared final. Again, the obvious implementation is to sublcass
and add the synchronization to the subclass. But we can't. And since it's the SessionImpl class
does the magic and binds itself to hydrated entities, wrapping the SessionImpl won't work. So,
again, we either need to cut and paste, or modify SessionImpl lto allow subclassing.

It's an awful lot of work to get proper synchronization going, isn't it?

The only other solution that I can see to my synchronization issues it to serialize all
accesses to a session and it's objects...

Any thoughts/comments?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 10, 2003 11:21 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Synchronization is evil. Don't do it. Not unless you don't care about scalability. We jump though all sorts of hoops to avoid any use of synchronization in Hibernate and what that means for you is that you don't need to worry, because we did the hard work already.


Top
 Profile  
 
 Post subject: Are you kidding me?
PostPosted: Mon Nov 10, 2003 1:22 pm 
Beginner
Beginner

Joined: Mon Sep 08, 2003 6:52 am
Posts: 46
gavin wrote:
Synchronization is evil. Don't do it. Not unless you don't care about scalability. We jump though all sorts of hoops to avoid any use of synchronization in Hibernate and what that means for you is that you don't need to worry, because we did the hard work already.


Look, I'm not trying to criticize the library - I really really like it.

Either I am missing something crucial, or you must be joking.

The way Hibernate currently works, if we don't jump through all sorts of hoops,

We lose data!

We have a web based application where different people can simultaneously add or update data -
we have to synchronize!!

If I'm missing something obvious, please let me know, but telling me "Synchronization is evil" is
incredibly naive - trust me, data loss is worse.

Hunter


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 10, 2003 1:26 pm 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
What do you want to achieve here? Make all of your concurrent threads running at "serializable" isolation?

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject: Re: Are you kidding me?
PostPosted: Mon Nov 10, 2003 1:37 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
You really must do something out of the ordinary since you say you "Loose data" !!?!

Please explain how you have built a webapp that cannot ensure data integrity with standard techniques such as:

- transactions
- optimistic or pessimistic locking
- ...

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject: Re: Are you kidding me?
PostPosted: Mon Nov 10, 2003 1:49 pm 
Beginner
Beginner

Joined: Mon Sep 08, 2003 6:52 am
Posts: 46
max wrote:
You really must do something out of the ordinary since you say you "Loose data" !!?!

Please explain how you have built a webapp that cannot ensure data integrity with standard techniques such as:

- transactions
- optimistic or pessimistic locking
- ...



Here's a very standard scenario, let me know what I'm missing or how the above can help.

We have an object, let's call it an Entry. People can comment on an Entry. We also keep track
of the number of comments on an entry.

Here's what happens:

A request to add a comment comes in. We look up the Entry by it's id. We create the comment,
add it to the Entry's set of comments, update the comment count. This all happens in
a thread associated with an HttpRequest.

Now, when if two (or more) people try to add a comment to the Entry at the same time,
_someone_ has to do some form of synchronization/locking/whatever to ensure that
both comments are added, and the update count is correct.

One way is to serialize the requests. It works, but slows things down.

The other (obvious to me) way is to synchronize the data access on the Entry - but like my
original post explains, this can get very tricky.

What would the "normal" way to do this, where "Hibernate does all the hard work" for me?

Hunter


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 10, 2003 1:58 pm 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
The database does it, of course.

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 10, 2003 2:25 pm 
Beginner
Beginner

Joined: Mon Sep 08, 2003 6:52 am
Posts: 46
christian wrote:
The database does it, of course.


No, it doesn't. All of this happens in Java.
The database cannot possibly synchronize my business logic.

My business logic logic is not able to synchronize data access and data integrity properly
becuase Hibernate does not have the correct hooks to allow my business methods
to coordinate properly. That's what my original post was trying to point out - that
it is very hard to coordinate locking/synchronizing at the business logic level.

And telling me "Hibernate does it for you" or "The database does it for you" isn't correct,
becuase it doesn't. If I don't put in business logic to coordinate access, multiple requests
simply trample over each other's updates.

H


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 10, 2003 2:40 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
yes - use the database for doing this - this is what it does well ;)

If you can't handle it with optimistic locks - then use true locks (which
is a much better way to do synchronization if you really need it ;)

AFAIK this is standard database transactions stuff?

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 10, 2003 2:42 pm 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
I can't even think why you see it like that and don't have any answer. But I'd really like to know whats going on here.

Ok, so we have two HTTP requests coming in. Both do some work on "the same" object. Both threads start a new Hibernate Session and get to work using a single database transaction on a JDBC connection.

One of them commits and the manipulated object gets saved. The other commits and overwrites the data the first one saved. Both are completely isolated. There are various levels of database transaction isolation. All of this is the job of the database, as is pessimistic locking or optimistic locking (additionally also provided at the application level with Hibernate).

Pessmistic locks and Serialized calls are not scalable as is "synchronization", which in effect, serializes calls.

Why do you have to synchronize anything in this scenario in memory?

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 10, 2003 3:00 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
retnuh wrote:
christian wrote:
The database does it, of course.


No, it doesn't. All of this happens in Java.
The database cannot possibly synchronize my business logic.

My business logic logic is not able to synchronize data access and data integrity properly
becuase Hibernate does not have the correct hooks to allow my business methods
to coordinate properly.


Have you seen the methods lock() et.al. on the session interface ?
That is for allowing your business method to coordinate properly!

Relying on in-memory synchronization on this stuff is reaaally horrible (IMHO)

Maybe i don't follow you since I hear you say: "I want to ensure no two threads must step on each other" and you want to solve that problem by "SERIALIZING the two threads access to the hibernate session or the entity object" ....well serializing two threads access to the hibernate session is not doable as you point out, but why on earth don't you want to use the databases capabilities that both allow you to SERIALIZE all access (by using proper transaction isolation) or use locks to ensure data integrity ? Please remember that the origin of the dataentity is in the database - it is a tuple in the db - the state you have in memory is just a copy! So, what happens if you want to cluster your app ? or have more than one program writing data to the db ? How do you solve that in-memory ?

Let me answer: You don't ;) ...you let the db do this ;) It is what it do good ;)

Have you read the http://www.hibernate.org/hib_docs/refer ... actions-s5 about pessimistic locking ? (note - much of this is more or less automatically handled for you)

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 10, 2003 3:03 pm 
Beginner
Beginner

Joined: Mon Sep 08, 2003 6:52 am
Posts: 46
christian wrote:
...

One of them commits and the manipulated object gets saved. The other commits and overwrites the data the first one saved. Both are completely isolated. There are various levels of database transaction isolation. All of this is the job of the database, as is pessimistic locking or optimistic locking (additionally also provided at the application level with Hibernate).
...


I don't want to overwrite the change the first has made - both changes need to take affect.
That's why I need to synchronize at a higher level.

I'm not claiming that Hibernate and the transaction/isoltion stuff is wrong - it doesn't solve my
problem.

What's worse is that it's quite difficult to extend Hibernate to allow me to solve my problem.

H


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 10, 2003 3:06 pm 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
In my scenario, both updates happen. If you don't want to overwrite data. you don't need synchronization. Synchronization doesn't prevent overwriting data.

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 10, 2003 3:16 pm 
Beginner
Beginner

Joined: Mon Sep 08, 2003 6:52 am
Posts: 46
max wrote:
Have you seen the methods lock() et.al. on the session interface ?
That is for allowing your business method to coordinate properly!

Relying on in-memory synchronization on this stuff is reaaally horrible (IMHO)

Maybe i don't follow you since I hear you say: "I want to ensure no two threads must step on each other" and you want to solve that problem by "SERIALIZING the two threads access to the hibernate session or the entity object" ....well serializing two threads access to the hibernate session is not doable as you point out, but why on earth don't you want to use the databases capabilities that both allow you to SERIALIZE all access (by using proper transaction isolation) or use locks to ensure data integrity ? Please remember that the origin of the dataentity is in the database - it is a tuple in the db - the state you have in memory is just a copy! So, what happens if you want to cluster your app ? or have more than one program writing data to the db ? How do you solve that in-memory ?

Let me answer: You don't ;) ...you let the db do this ;) It is what it do good ;)

Have you read the http://www.hibernate.org/hib_docs/refer ... actions-s5 about pessimistic locking ? (note - much of this is more or less automatically handled for you)


I have read it (a few times) but I'm a bit confused. I thought the lock modes were for the table -
or do they do the same things for Sessions that the similar locks would do on a table?

Just to be absolutely clear - I want to ensure no two threads step on each other. I'd prefer
that things weren't completely serialized - but thats a preferance, not a requirement.

What I was trying to do was synchronize thread access to the Hibernate session - I was
able to do most of it, but things like lazy collections prevent it from working without doing
some fiddling with Hibernate itself.

Maybe I should be using LockMode - I'm not sure. What would I use? LockMode.WRITE?
Does that do any better than just serializing the requests I have? And do I have to
specify the LockMode for every query, load, etc, that I do? Can I set it for an entire session?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 10, 2003 3:28 pm 
Hibernate Team
Hibernate Team

Joined: Mon Aug 25, 2003 9:11 pm
Posts: 4592
Location: Switzerland
I'm still not sure why you want to do what you are trying to do. Here are some words for Google to search: database locking concurrency. Read stuff like that:

http://www.datadirect-technologies.com/ ... ation.html

_________________
JAVA PERSISTENCE WITH HIBERNATE
http://jpwh.org
Get the book, training, and consulting for your Hibernate team.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 31 posts ]  Go to page 1, 2, 3  Next

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.