From: Gavin_King/Cirrus%<CI...@ci...> - 2002-03-03 00:46:35
|
> Is it possible? There's mention of optimistic locking stuff, but not the > plain old vanilla pessimistic variety. Does hibernate handle this? Even > just by asking the underlying database to do it? Of course - thats the default behaviour. If you supply your own JDBC connection, you need to setAutocommit(false) before opening the session. If you let hibernate open a connection, it will do that for you. (Well, in the case of a datasource, we assume it was already done by the appserver.) As you imply, Hibernate doesn't implement any concurrency management itself, it delegates everything to the database. So the transactional semantics are exactly what they would be if you were doing direct JDBC. (Ignore this whole "cross-transactional cache" thing, its *not* part of the core persistence engine and is disabled by default. I might even end up throwing it away.....) I could argue at length for the advantages of this approach over implementing concurrency management inside the object-relational layer, but you can probably already guess what i'm going to say. ;) |
From: Gavin_King/Cirrus%<CI...@ci...> - 2002-03-03 08:44:43
|
> Another simple question then: how do I "lock" something? If I was doing > plain old JDBC, I'd use a "SELECT ... FOR UPDATE" with or without a > NOWAIT option. Okay, I almost brought this up myself earlier. I've been concerned about it for a while. My understanding is that most databases will lock rows automatically when necessary (according to the transaction isolation level). Hibernate never uses FOR UPDATE because some databases (eg. Sybase) don't even allow this clause on a select. However, I sort of thought that some other platforms (eg. MySQL) might need it. Does anyone know more about this than me? It will be simple enough to make hibernate always select for update on those databases which need it, or we can add findForUpdate() or loadForUpdate() to the API. Are there other times when you *need* to use a select for update? ie. times when you *need* to grab a write lock immediately rather than escalating to a write lock when we issue an UPDATE? This, for sure, is something I need a really definite answer on before we go out of beta.... thanks for raising it Paul. |
From: Paul S. <pau...@ne...> - 2002-03-03 09:16:10
|
Gavin_King/Cirrus%CI...@ci... wrote: > >>Another simple question then: how do I "lock" something? If I was doing >>plain old JDBC, I'd use a "SELECT ... FOR UPDATE" with or without a >>NOWAIT option. >> > > Okay, I almost brought this up myself earlier. I've been concerned about > it for a while. My understanding is that most databases will lock rows > automatically when necessary (according to the transaction isolation > level). Hibernate never uses FOR UPDATE because some databases (eg. > Sybase) don't even allow this clause on a select. However, I sort of > thought that some other platforms (eg. MySQL) might need it. Does anyone > know more about this than me? It will be simple enough to make hibernate > always select for update on those databases which need it, or we can add > findForUpdate() or loadForUpdate() to the API. > > Are there other times when you *need* to use a select for update? ie. > times when you *need* to grab a write lock immediately rather than > escalating to a write lock when we issue an UPDATE? Without doing this you effectively get optimistic lock behaviour. That is, you find out at commit time whether everything is okay or not. Because the O/R layer will defer all SQL insert/update/delete statements until the last second, we don't have any exclusive locks as far as the underlying DB is concerned until that point, which from the Hibernate callers perspective is commit time. Consider a simple web app: a user selects something to update, a servlet (say, or JSP, or whatever) grabs the info from the database and responds with the HTML page with a form to fill in. The user submits the form, and another servlet updates the DB. If the exclusive lock is only obtained in the second servlet that handles the form being posted a possibility is that it fails. From the the user's perspective this is optimistic locking behaviour. What you need to be able to do is gain the exclusive lock in the first servlet, the one that knows the user is planning to do the update. The same applies no matter what the architecture: a fat Swing client talking directly to the DB has the same issues. PaulS. |
From: Gavin_King/Cirrus%<CI...@ci...> - 2002-03-03 13:25:26
|
> Without doing this you effectively get optimistic lock behaviour. That > is, you find out at commit time whether everything is okay or not. > Because the O/R layer will defer all SQL insert/update/delete statements > until the last second, we don't have any exclusive locks as far as the > underlying DB is concerned until that point, which from the Hibernate > callers perspective is commit time. Okay, heres what I mean by pessimistic/optimistic (you seem to be working from a different definition). pessimistic locking: Retrieval and update of data occurs in one transaction. the database is solely responsible for ensuring transaction isolation. Take sysbase, set transaction isolation to serializable. start two transactions. select the same rows from both transactions. Then, from one transaction, try to do an update. That transaction will block, waiting to see what the other transaction tries to do. Whats happened is that both transactions acquire a read lock when you issue the select. Any attempts to acquire a write lock (eg. the escalation when you try to update) will block waiting for the other transaction to release its read lock. optimistic locking: We retrieve the data in one transaction and then update it in another. To ensure consistency, we check version numbers/timestamps/etc when we update. In the previous example, the first transaction would have been allowed to proceed with the update, since there was *no* lock held by the other transaction. The second would have failed to update because its timestamp/version number would be stale. So the distinction between selection with or without "FOR UPDATE" (ie. between a read lock and a write lock is different to my distinction between optimistic (no lock) and pessimistic locking. clearly there are shades of optimism.... :) > If the exclusive lock is only obtained in the second servlet that > handles the form being posted a possibility is that it fails. From the > the user's perspective this is optimistic locking behaviour. > What you need to be able to do is gain the exclusive lock in the first > servlet, the one that knows the user is planning to do the update. hmmmmmm.....this is not usually a recommended approach in web applications. Generally people say transactions should not span "user-think-time". Still, its appropriate in some other situations..... Anyways all that is beside the point. The point is that some people probably want to do a select for update (I would imagine people using MySQL would be very keen on it). So, how is this functionality best exposed to the user: * a global property for the database ie. hibernate.select_for_update=true * on a class-by-class basis in the mapping file * as a property of the individual session ie. Session.setSelectForUpdate () * as part of the query language ie. SELECT foo FROM CLASS f.Foo FOR UPDATE * as part of the API ie. session.loadForUpdate(fooID) I figure, if paul is using this, other people will also want it..... Gavin. |
From: Paul S. <pau...@ne...> - 2002-03-03 14:18:57
|
Gavin_King/Cirrus%CI...@ci... wrote: > > Okay, heres what I mean by pessimistic/optimistic (you seem to be working > from a different definition). It seems that way. There are formal definitions - optimistic concurrency control schemes have been around for a while (and not like how you describe). The basis of this stuff happened back in the late 70's / early 80's with Field Call's, which optimistic approaches are based on - the IBM guys had this stuff in IMS soon after then. Optimistic stuff was around in the mid to late 80's. Check out: "Concurrency Control and Recovery in Database Systems" by Bernstein, Hadzilacos & Goodman (1987). >>If the exclusive lock is only obtained in the second servlet that >>handles the form being posted a possibility is that it fails. From the >>the user's perspective this is optimistic locking behaviour. >> > >>What you need to be able to do is gain the exclusive lock in the first >>servlet, the one that knows the user is planning to do the update. >> > > hmmmmmm.....this is not usually a recommended approach in web applications. Extremely debatable... > Anyways all that is beside the point. ... so I won't touch it ;) > The point is that some people > probably want to do a select for update (I would imagine people using MySQL > would be very keen on it). So, how is this functionality best exposed to > the user: > > * a global property for the database ie. hibernate.select_for_update=true > * on a class-by-class basis in the mapping file > * as a property of the individual session ie. Session.setSelectForUpdate > () > * as part of the query language ie. SELECT foo FROM CLASS f.Foo FOR > UPDATE > * as part of the API ie. session.loadForUpdate(fooID) I've had a brief look at other tools / frameworks / products for an idea of their approaches (e.g. JDO, ODMG, Castor, TOPLink, etc). I don't like any global approaches - whether it's per database, class or session. These simply won't work. I don't want every read of my Product class from the product catalog to get an exclusive lock just because someon's reading the catalog. What you really need is a way to lock a single object, and have that translate onto the correct SELECT ... FOR UPDATE call(s). For this only the last option you describe works. The others won't help at all. Something like a different locking version of the find() and load() methods in the Session interface, and a way to lock an object already loaded. Also need to consider wait vs. nowait options (and timeout values?). At the very least, the lock() method on an already loaded object would do the trick for starters. As long as the call makes its way through to the database. I'm not proposing that Hibernate do any lock processing (which is what scared me about the cache discussions) - just allow the underlying database to do it. What do you think? PaulS. |
From: Doug C. <de...@fl...> - 2002-03-03 17:04:37
|
In my experience, when people say "optimistic locking" they can mean many different things. My earliest exposure (70s) to the term was in OS design where pessimistic locks aborted on contention, and optimistic locks waited. It seems to have taken on slightly different meanings in the RDB (SQL) and ODB worlds as well, as Gavin's and Paul's definitions highlight. Anyway, I have seem other O/R tools and ODBs call the technique Gavin is describing (no lock, check version number on update) "long duration transactions" and "optimistic locking." > * a global property for the database ie. hibernate.select_for_update=true > * on a class-by-class basis in the mapping file > * as a property of the individual session ie. Session.setSelectForUpdate All too gross. > * as part of the query language ie. SELECT foo FROM CLASS f.Foo FOR UPDATE > * as part of the API ie. session.loadForUpdate(fooID) These two are good. The dialect could have a new property to indicate its support for this feature. If not available, ignore it. e |
From: Gavin_King/Cirrus%<CI...@ci...> - 2002-03-03 15:35:30
|
> It seems that way. There are formal definitions - optimistic concurrency > control schemes have been around for a while (and not like how you > describe). I went and had a good look on google to see how these terms are commonly used. Everyone agrees that optimistic locking means the application does some work by retaining a version number/timestamp and that pessimistic locking works by the database retaining a "lock" at read time. No-one seems terribly explicit as to whether a read lock constitutes a lock or not. I would have thought it did. Apparently you don't think so.... I would love to be sure of terminology here because when we come to document this I don't want to look clueless ;) > Check out: "Concurrency Control and Recovery in Database Systems" by > Bernstein, Hadzilacos & Goodman (1987). k, i will try to find it (p.s. i am a mathematician not a c.s. major so sometimes im missing authorative sources here) > At the very least, the lock() method on an already loaded object would > do the trick for starters. As long as the call makes its way through to > the database. Yup. After i posted that last email i wondered about this option. Its a nice one i think. Frees you to lock an object even sometime after you first retrieved it. All good. Im guessing its enough to just touch the row, right, ie. just select the primary key with "for update" to lock the whole row? Would probably be good to allow "for update" in query language also, since that would let you lock a bunch of rows in one query. What do we do about databases which don't support the for update syntax? throw exception? ignore it? Is there some other way to lock a row in sybase? |
From: Doug C. <de...@fl...> - 2002-03-03 17:22:19
|
> I went and had a good look on google to see how these terms are commonly > used. Everyone agrees that optimistic locking means the application does > some work by retaining a version number/timestamp and that pessimistic > locking works by the database retaining a "lock" at read time. No-one seems > terribly explicit as to whether a read lock constitutes a lock or not. I > would have thought it did. I agree. > I would love to be sure of terminology here because when we come to > document this I don't want to look clueless ;) I notice that Benjamin Chi started a thread in the open discussion called "Optimistic Locking with Versioning." I think that including the word "Versioning" in any description of the Hibernate optimistic locking feature will allay most confusion about what Hibernate is doing. Both "Optimistic Locking with Versioning" and "Long Transaction Support with Versioning" sound right to me. e |
From: Paul S. <pau...@ne...> - 2002-03-03 19:27:39
|
Doug Currie wrote: >>I went and had a good look on google to see how these terms are commonly >>used. Everyone agrees that optimistic locking means the application does >>some work by retaining a version number/timestamp and that pessimistic >>locking works by the database retaining a "lock" at read time. No-one seems >>terribly explicit as to whether a read lock constitutes a lock or not. I >>would have thought it did. >> > > I agree. Yep. The main issue I had was your description had optimistic locking spanning two transactions. The other minor detail is that timestamp or versioning is just one approach to optimistic locking. > >>I would love to be sure of terminology here because when we come to >>document this I don't want to look clueless ;) I'm no expert - I'll be the first to admit it. And there is a lot of confusion, since the same terms are used to describe different things by different people, and different terms to describe the same thing. Case in point: read lock vs. shared lock, or exclusive lock vs. update lock vs. write lock. > I notice that Benjamin Chi started a thread in the open discussion > called "Optimistic Locking with Versioning." I think that including > the word "Versioning" in any description of the Hibernate optimistic > locking feature will allay most confusion about what Hibernate is > doing. Both "Optimistic Locking with Versioning" and "Long Transaction > Support with Versioning" sound right to me. Yep - optimistic locking is one thing, and long transaction support is another (orthogonal) thing. PaulS. |
From: Paul S. <pau...@ne...> - 2002-03-03 19:46:39
|
Gavin_King/Cirrus%CI...@ci... wrote: >>It seems that way. There are formal definitions - optimistic concurrency >>control schemes have been around for a while (and not like how you >>describe). >> > > I went and had a good look on google to see how these terms are commonly > used. Everyone agrees that optimistic locking means the application does > some work by retaining a version number/timestamp and that pessimistic > locking works by the database retaining a "lock" at read time. No-one seems > terribly explicit as to whether a read lock constitutes a lock or not. I > would have thought it did. Apparently you don't think so.... I would love > to be sure of terminology here because when we come to document this I > don't want to look clueless ;) > > >>Check out: "Concurrency Control and Recovery in Database Systems" by >>Bernstein, Hadzilacos & Goodman (1987). >> > > k, i will try to find it (p.s. i am a mathematician not a c.s. major so > sometimes im missing authorative sources here) There's better stuff out there (more recent). That one's just a good summary of what had happened up until that point. For more recent stuff, check out the Morgan Kaufmann series on Data Management Systems. The Transaction Processing Concepts and Techniques by Jim Gray is a classic (althoug almost 10 years old). Somone else here might know better references? >>At the very least, the lock() method on an already loaded object would >>do the trick for starters. As long as the call makes its way through to >>the database. >> > > Yup. After i posted that last email i wondered about this option. Its a > nice one i think. Frees you to lock an object even sometime after you first > retrieved it. All good. Im guessing its enough to just touch the row, > right, ie. just select the primary key with "for update" to lock the whole > row? Yep. There is an "OF" operator in the FOR UPDATE clause that specifies columns, but it's only used to determine what tables will have rows locked. One other thing: what about the "NOWAIT" operator? Comes in handy. > Would probably be good to allow "for update" in query language also, since > that would let you lock a bunch of rows in one query. But you can't use it with the "DISTINCT" clause, so it might be an issue with the query stuff. Other restictions that exist in Oracle at least, and probably in other DB's (e.g can't use the group-by clause, not in sub-queries). Don't know which might be an issue here. I have no idea, but is there any kind of "standard" out there (explicit or de-facto) that addresses this? SQL92 or OQL? JDO? Is it part of the query language or the API in the ODMG or JDO stuff? Or both? PaulS. |
From: Steve B. <ba...@te...> - 2002-03-03 18:07:57
|
I prefer to have the pessimistic locking supported at load time -- either by the query language or through the persistence API for loading objects. Allowing explicit lock upgrades after loading would be nice for flexibility, but it also can lead to deadlocks in the database if multiple objects are being loaded and modified in a transaction. It's also effectively optimistic locking since the data initially read may have changed between the time you load the object and the time you upgrade the lock. Steve |
From: Paul S. <pau...@ne...> - 2002-03-04 06:18:45
|
Steve Bate wrote: > I prefer to have the pessimistic locking supported at load time -- > either by the query language or through the persistence > API for loading objects. Allowing explicit lock upgrades after > loading would be nice for flexibility, but it also can lead to > deadlocks in the database if multiple objects are being loaded > and modified in a transaction. Deadlocks are nothing new. Databases have deadlock detection, and there's a mountain of litreature on how to avoid avoid it in the first place. It's not just "something nice" - it's a fundamental requirement if you're using pessimistic locks. > It's also effectively optimistic > locking since the data initially read may have changed between > the time you load the object and the time you upgrade the lock. Not necessarily true. That's what things like read locks, isolation levels and cursor stability are all about. Regards, PaulS. |
From: Steve <st...@ba...> - 2002-03-04 14:00:55
|
> -----Original Message----- > From: Paul Szego [mailto:pau...@ne...] > > Steve Bate wrote: > > I prefer to have the pessimistic locking supported at load time -- > > either by the query language or through the persistence > > API for loading objects. Allowing explicit lock upgrades after > > loading would be nice for flexibility, but it also can lead to > > deadlocks in the database if multiple objects are being loaded > > and modified in a transaction. > > Deadlocks are nothing new. Databases have deadlock detection, and > there's a mountain of litreature on how to avoid avoid it in the first > place. > > It's not just "something nice" - it's a fundamental requirement if > you're using pessimistic locks. I don't understand your claim that post-load lock upgrades are a fundamental requirement of pessimistic locking. In databases that allow reads of rows with write locks (e.g. default behavior in Oracle) that behavior would be considered a form of optimistic locking. See: http://www.orafaq.com/papers/locking.pdf At least with Oracle, unless you obtain the write lock at select time the data may be altered before you update it. What are the benefits in doing a "select for update" on the PK after the data has been loaded? Why not just write the data and let the database upgrade the lock automatically? I suppose the first approach gives you a somewhat smaller window for the data to change before the update. On the other hand, it requires another access to the database. If you are developing applications with relatively long transactions I could see behavior potentially being a benefit. The systems I work on are high rate transaction processing systems with short transactions. The deferred, explicit lock upgrades are a "nice to have" but not very useful in that context. I understand that deadlocks are nothing new. As I'm sure you know, one of the techniques for avoiding deadlock is to use pessimistic locking and lock the objects in the same order in each client. The immediate load-time locking is a requirement for this strategy. A deferred lock upgrade could still lead to deadlocks. Even though the database will detect and break these deadlocks, the customers I work with prefer to avoid them in the first place. > > It's also effectively optimistic > > locking since the data initially read may have changed between > > the time you load the object and the time you upgrade the lock. > > Not necessarily true. That's what things like read locks, isolation > levels and cursor stability are all about. I'll be more specific. It is optimistic rather than pessimistic locking in databases like Oracle and others that (by default) allow reads while a row is write locked. Regards, Steve |
From: Paul S. <pau...@ne...> - 2002-03-03 06:06:52
|
Gavin_King/Cirrus%CI...@ci... wrote: >>Is it possible? There's mention of optimistic locking stuff, but not the >>plain old vanilla pessimistic variety. Does hibernate handle this? Even >>just by asking the underlying database to do it? >> > > Of course - thats the default behaviour. > > If you supply your own JDBC connection, you need to setAutocommit(false) > before opening the session. If you let hibernate open a connection, it will > do that for you. (Well, in the case of a datasource, we assume it was > already done by the appserver.) Got that bit working so far. > As you imply, Hibernate doesn't implement any concurrency management > itself, it delegates everything to the database. So the transactional > semantics are exactly what they would be if you were doing direct JDBC. Another simple question then: how do I "lock" something? If I was doing plain old JDBC, I'd use a "SELECT ... FOR UPDATE" with or without a NOWAIT option. I have no idea how to do this with Hibernate. > (Ignore this whole "cross-transactional cache" thing, its *not* part of the > core persistence engine and is disabled by default. I might even end up > throwing it away.....) > > I could argue at length for the advantages of this approach over > implementing concurrency management inside the object-relational layer, but > you can probably already guess what i'm going to say. ;) I agree - I like the approach of doing what you need to (O/R mapping), and letting the database do what it's good at (*lots* of really hard stuff - like locking). PaulS. |