I was reading this article https://www.baeldung.com/jpa-pessimistic-locking, where it's written that
PESSIMISTIC_WRITE – allows us to obtain an exclusive lock and prevent the data from being read, updated, or deleted
So I tried to confirm this.
In Transaction(TX1), I took a PESSIMISTIC_WRITE lock on an entity1. Then called a Thread.sleep(5).
While TX1 is going on, I did a GET API call on the same entity1, which returned the data with 200 status. After which TX1 got completed.
Maybe my implementation is wrong here, Could anyone help me in understanding this?
Resources used: JAVA 8, Mysql version: 5.6.34, Engine: InnoDB
If I'm able to read a locked entity, then this may lead to a dirty update.
So in TX2, I did a plain findById and then did an update on entity1. Here TX2 is waiting till TX1 is completed because of locking but TX2 will do a dirty update as it is not aware of the changes made by TX1.
Related
I am learning JPA pessimistic lock. I found the following explanation
PESSIMISTIC_READ - The Entity is locked on the database, prevents any
other transaction from acquiring a PESSIMISTIC_WRITE lock.
PESSIMISTIC_WRITE - The Entity is locked on the database, prevents any
other transaction from acquiring a PESSIMISTIC_READ or
PESSIMISTIC_WRITE lock.
If I understand it right, then if we have three users (A, B, C) and user A gets READ lock, then user B can get READ lock too, but user C can't get WRITE lock until users A and B releases their locks. And if user A gets a WRITE lock then user B and user C can't get nothing until user A releases the lock.
However, for my client-server application I want the following logic. If users want only to read an entity their open the entity in READ-ONLY mode (unlimited number of users can do it at the same time). If some user wants to edit the entity he opens it in WRITE mode - no one can open the same entity in WRITE mode (until the user releases the WRITE lock) but all other can still open the entity in READ-ONLY mode.
And I have two questions:
Is my understanding of JPA pessimistic lock right?
Is it possible to make JPA do the logic I need (using JPA lock mechanisms)?
Is my understanding of JPA pessimistic lock right?
Yes, that's exactly how read/write locking works
...but all other can still open the entity in READ-ONLY mode
I'm not exactly sure what you mean. We are still talking about multiple transactions executing simultaneously, right (I have a strange feeling that's not what you mean)? If that's the case, then in your logic, holding a 'READ_ONLY' lock accomplishes nothing.
Locking means 'I'm freezing this resource so that certain other transactions cannot proceed until I'm done'. But, in the logic you described, when you're holding the 'READ_ONLY' lock, both a transaction holding the 'READ_ONLY' lock and the transaction holding the 'WRITE' lock are allowed to proceed.
I had a problem in my software that sometimes caused a lock on the SQL server.
This was caused by a process that selects a group of records and starts processing them.
Based on some values and a calculation the records get updated.
When a record is being updated the page where that record is on, is locked by the SQL server for select. Which results in a lock that never solves itself.
To solve the problem we have created a second table, from which we select, the main table is copied into it before the process starts, the table that is updated is not being selected in that way and no lock can appear.
What I am looking for is simple and better solution for this problem, because for me it is like a workaround for something I'm doing the wrong way and would really like to improve the processing.
Try to change TRANSACTION ISOLATION LEVEL on database. Here is link.
I guess your default isolation level is set to repeatable read, which causes the select to set a shared lock on the returned records, deadlock happens when concurrent requests come in. To solve this you should take a locking select (to lock records with X lock rather than S lock).
I'm developing an application with JPA2.1. I have the followed trouble.
I'm trying to lock an entity in this way :
Book book = em.find(Book.class, 12);
em.lock(book, LockModeType.PESSIMISTIC_WRITE);
but if try to access from another windows browser or client to entity with id=12 , the system doesn't thrown PessimisticLockException?
Where am I wrong?
The lock will be effective during the lifetime of the transaction but certainly not across multiple request-response loop (unless you have configured your entity manager and transaction manager to manage long time transaction).
The transaction MUST be a short-time living object (for performance reasons).
Optimistic write-lock means that book will not be modified by any other thread between the lock instruction and the end of the transaction. But the book object itself may live longer of course.
I suppose that in another window/browser you try the same thing: to acquire a PESSIMISTIC_WRITE lock.
The problem that you have, is that the lock is released when the method returns (as the transaction ends), meaning that when you open the second browser/window, there is no lock anymore.
You should probably explain us the problem/scenario that you want to try to solve/test.
For the general situation:
Another possible cause could be that your database table does not support row-level locking. For example in MySql only the InnoDB storage engine supports "SELECT * FOR UPDATE" (which the PESSIMISTIC_WRITE lock is translated into).
I am trying to understand whats the effect of calling EntityManager.lock(entity, LockModeType.READ). The API documentation sounds very confusing for me.
If I have to concurrent threads and Thread 1 calls lock(entity, LockModeType.READ), can Thread 2 still read and write the entity?
What I have learned so far:
The lock type READ in JPA1 is the same as OPTIMISTIC in JPA2. If such a lock is set, the EntityManager checks the version attribute before commiting the transaction, but does not update it. I found an explanation for the OPTIMISTIC lock mode: Link. Search for OPTIMISTIC (READ) LockMode Example.
As fas as I understand this, setting a read lock in Thread 1 has no effect on Threads 2 ... n. All other threads can still read and write the entity. But when the transaction in Thread 1 commits and an other Thread has updated the entity, the transaction in Thread 1 is rolled back.
Am I understanding this correct?
Read is curently deprecated anyway but just for your understanding:
A READ lock will ensure that the state of the object does not change on commit, because the READ lock allows other transactions to update or delete it then if Thread 1 does some change and then commits it first checks the state (the version) of the entity if it checks, it is commited, if not it is not allowed,
so basicly your understanding is correct.
there is also OPTIMISTIC_READ which is the modern way of using it(aslo there is _WRITE).
UPDATE
Ok this article helped me a lot in understanding hope this helps.
I'm using the EclipseLink implementation of the JPA 2.0 which allows pessimistic locking. I know how to lock an entity but how do I release the lock? At first I thought this was all taken care of within a transaction (in other words, the entity is locked until you commit the transaction), but that does not seem to be the case.
I tried a quick google search (seems like this should be pretty obvious), but I haven't found anything...
After getting some sleep... and doing some more testing in the morning, I believe I have figured out my problem.
So the lock is actually taken care of within a transaction. However, when I was testing my code, I was able to retrieve a locked row using the EntityManager.find(Class, key) method (no locking strategy specified).
I erroneously thought that by putting a lock on a row, the row could not be read, period. However, I reread the JPA definitions of PESSIMISTIC_READ and PESSIMISTIC_WRITE and noticed my problem:
PESSIMISTIC_READ - The Entity is locked on the database, prevents any other transaction from acquiring a PESSIMISTIC_WRITE lock.
PESSIMISTIC_WRITE - The Entity is locked on the database, prevents any other transaction from acquiring a PESSIMISTIC_READ or PESSIMISTIC_WRITE lock.
The lock doesn't necessarily prevent all reads, it just prevents another transaction from putting a READ or WRITE lock on the row.