Is it possible to column-level optimistic locking in JPA toplink?
I studied about optimistic locking
in JPA, adding @Version annotation
with version column in DB and how it is managed by EntityManager
etc
The doc says (in my own word) optimistic lock is effective in object-level. I can tell it is indeed so because the version definition sits in entity class.
This means:
userA select row_A (just a 开发者_运维技巧row in db table)
userB select row_A
userA update row_A of username column (version changes here)
userB update row_A of username column (optimisticLockException thrown)
So far so good.
But thinking about at step4, if
userB update row_A of phoneNumber
for instance.
I know optimisticLockException is still thrown but is there any way to lock by column level instead of object-level?
For me it would be nice to have column-level lock but I'm also not sure what disadvantage would that bring even though it is possible.
No. Remember that what JPA is doing is just mapping Objects to the underlying Relational database. So each record (row) in a table ends up being an instance of an object.
Databases normally lock records not columns. Locking a whole column is pretty much nearly like an exclusive lock on a table.
The accepted answer is not entirely true. It is true at the vanilla JPA level, however, you can take advantage of provider specific functionality to obtain column level locks. For example Eclipselink, the default provider in Glassfish 3.0+, supports Optimistic lock extentions that provide greater flexibility in this area.
See Eclipselink JPA Extensions for Optimistic locking
also
Optimistic Version Locking Policies and Cascading
for details on Optimistic field locking policies for Eclipselink.
I can see the use of that sort of locking, but it would violate the atomicity of the database update. Imagine i'm writing a bank application, where people have balances and overdraft limits. Say i start with:
Customer | Balance | Overdraft Limit
Shirakawa | -30000 | -50000
Then Shirakawa-san comes along and makes two transactions at once, via different cashiers; with one, he withdraws 15000 yen, and with the other, he reduces the overdraft limit to 40000 yen. Each of those transactions is perfectly okay on its own, and would not violate any constraints in the business logic. But the result is:
Customer | Balance | Overdraft Limit
Shirakawa | -45000 | -40000
Uh-oh.
I admit this is a contrived example. But this is the general reason why column-level concurrent updates are not supported.
What you could do, though, is to factor out the concurrently updatable parts of the record into separate entities, and update them separately. To apply that to the above example, say we had an account table, as above, and also an overdraft agreement table, with a one-to-one relationship. Then we would have:
Customer | Balance
Shirakawa | -45000
Customer | Overdraft Limit
Shirakawa | -40000
And we could update those in parallel. In this case, that would be a bad idea, but it could be useful for you.
精彩评论