• Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

How to trigger javax.persistence.PessimisticLockException

 
Daniel Jabonete
Ranch Hand
Posts: 84
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Greetings!

I would like to kindly ask how to trigger or hit a “javax.persistence.PessimisticLockException” runtime exception upon locking an entity.

I am hoping for your assistance, and insights in relation to this question.

Thanks very much in advance, I appreciate your time and effort!

Best regards,
Daniel
 
Daniel Jabonete
Ranch Hand
Posts: 84
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think the "javax.persistence.PessimisticLockException" can be triggered by setting the lock timeout to "0", but it is considered an issue, please see reference bug filed under "Bug 326424 - SELECT FOR UPDATE *NOWAIT* causes syntax error on MySQL".

I was hoping to hit or trigger the "javax.persistence.PessimisticLockException" by using the Entity Manger's find method, passing the Pessimistic Write Lock Type then lock the entity and proceed with the update. And then the other user who tries to update the same entity (with a stale values of the entity) will get the exception. This might also sound optimistic locking, but the main idea would be that the other user cannot update the same entity the 1st user locked for update.

Any ideas about these matters?

Thanks!
 
Rafael de Sousa
Greenhorn
Posts: 12
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I tried the following to fire an javax.persistence.PessimisticLockException:


But since pessimistic locks are synchronous, when the code execution reaches the line 20, it waits until the transaction created at line 9 commits and release the lock. Thus the exception it's never thrown. If we replace the locking mode at line 23 to:



An OptimisticLockException would be thrown at line 23 since the entity version has changed, as you already assumed.

 
Daniel Jabonete
Ranch Hand
Posts: 84
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Rafael,

Thanks for your reply!

As for my test and setup, I am using a single Entity Manager and in a Web Application accessing by concurrent users.

Although, OptimisticLockException would be sufficient, and I am thinking of eagerly or exclusively acquiring the lock for an entity update.

Any ideas?
 
Rafael de Sousa
Greenhorn
Posts: 12
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Daniel,

Are you tryin' to block two or more concurrent entity update calls? What is the expected behavior when a user tries to update an entity that it's already been updated by other user? The user should wait until the other finishes the entity update or an exception should be thrown in order to inform that entity it's been updated by someone else?
 
Daniel Jabonete
Ranch Hand
Posts: 84
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Rafael,

The test scenario would be User1 and User2 accessed the Web Application, then querying the Employee table and list it after find all.

Both users selected the same Employee record with the intention of updating the salary. User1 acquired a pessimistic lock to Employee 10001A at the other end User2 also selected Employee 10001A with the intention of updating the salary. Up onto this point User2 should not be able to acquire a lock to the record since User1 acquired an exclusive pessimistic lock to it.

Should the Pessimistic Lock Exception had been thrown here or if User1 commits his update and User2 also made his with stale copy of the entity?

I am trying to trigger or hit the "PessimisticLockException" in a Web Application context using a stateless session bean with an Entity Manager locking each entity with Pessimistic Lock Type.

Any thought or insights in relation to these?

Thanks very much, appreciate it!

Cheers!
Daniel
 
Rafael de Sousa
Greenhorn
Posts: 12
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Daniel,

Since you're using a Stateless to find and update the entity instance, here goes some points:

1 - When you first call a method on Stateless session bean to find the specific Employee(10001A) for user1, the container starts a new transaction, then you set pessimistic lock and the search method finishes.
2 - When the method finishes, the container commits the transaction, releasing the previously lock on the managed entity.
3 - At this point, the user1 is changing a detached Employee(10001A) entity

The steps above fits to you scenario? Can you post your code that performs the update on Employee entity?
 
Daniel Jabonete
Ranch Hand
Posts: 84
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Rafael,

Its seems these were the case. It started a transaction and closes it once done.

I am calling a flush from the Entity Manager to commit the update immediately to the database.

Hence, from your reply with regards to the behavior of "Stateless" Session Bean, I create a "Stateful" Session Bean with an extended Persistent Context Type, please see below:



From these changes I still cannot hit the "PessimisticLockException". It seem that the only way to throw this exception is to compare the before & after state of an entity and throw it manually.

Sorry for the late response.

Any more ideas or insights about this puzzle.

Thanks!
 
Frits Walraven
Creator of Enthuware JWS+ V6
Saloon Keeper
Pie
Posts: 2536
113
Android Chrome Eclipse IDE
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Guys,

Good question and nice discussion!

I tried it myself and I got the PessimisticLockException. Let me explain the strategy I used.

I have got the following components:
  • HttpSessionListener - to lookup a Stateful Session Bean per client
  • A Bean Managed Stateful Session Bean - to start a transaction in one method and commit in another
  • A Servlet to invoke methods on the Stateful Session Bean


  • Let me start with the Listener (note that the methods are called for every client once per Session)

    The Stateful Session Bean (note that the transaction is started in findForEmployeeUpdate() and committed in updateEmployee()) The lock is set in the findForEmployeeUpdate() method.

    And finally the Servlet:

    I have got one Employee entry in the database with id=1.

    This is the exact sequence of events:
  • Call from one client: http://localhost:8080/PessimisticLockWeb/EmployeeUpdateServlet?Action=find
  • Call from a second client: http://localhost:8080/PessimisticLockWeb/EmployeeUpdateServlet?Action=find


  • My logging (I removed some of the stacktrace lines)

    Finest: doGet EmployeeUpdateServlet
    Finest: Action = find
    Finest: Session created
    Finest: EmployeeUpdateServiceBean created
    Finest: UserTransaction started
    Finer: client acquired: 1905241820
    Finer: TX binding to tx mgr, status=STATUS_ACTIVE
    Finer: acquire unit of work: 270608323
    Finest: Execute query ReadObjectQuery(name="readObject" referenceClass=Employee sql="SELECT ID, NAME, SALARY, VERSION FROM EMPLOYEE WHERE (ID = ?)")
    Finest: Register the existing object Employee [id=1, name=Frits, salary=12, version=1]
    Finest: Execute query ReadObjectQuery(referenceClass=Employee )
    Finer: TX beginTransaction, status=STATUS_ACTIVE
    Finest: Connection acquired from connection pool [default].
    Finest: reconnecting to external connection pool
    Fine: SELECT ID, NAME, SALARY, VERSION FROM EMPLOYEE WHERE (ID = ?) FOR UPDATE WITH RS bind => [1 parameter bound]
    Finest: track pessimistic locked object Employee [id=1, name=Frits, salary=12, version=1] with UnitOfWork 270.608.323
    Finest: Lock succeeded
    Finest: found: Employee [id=1, name=Frits, salary=12, version=1]
    Finest: doGet EmployeeUpdateServlet
    Finest: Action = find
    Finest: Session created
    Finest: EmployeeUpdateServiceBean created
    Finest: UserTransaction started
    Finer: client acquired: 1781696558
    Finer: TX binding to tx mgr, status=STATUS_ACTIVE
    Finer: acquire unit of work: 462076538
    Finest: Execute query ReadObjectQuery(name="readObject" referenceClass=Employee sql="SELECT ID, NAME, SALARY, VERSION FROM EMPLOYEE WHERE (ID = ?)")
    Finest: Register the existing object Employee [id=1, name=Frits, salary=12, version=1]
    Finest: Execute query ReadObjectQuery(referenceClass=Employee )
    Finer: TX beginTransaction, status=STATUS_ACTIVE
    Finest: Connection acquired from connection pool [default].
    Finest: reconnecting to external connection pool
    Fine: SELECT ID, NAME, SALARY, VERSION FROM EMPLOYEE WHERE (ID = ?) FOR UPDATE WITH RS bind => [1 parameter bound]
    Fine: VALUES(1)
    ...
    Finest: Lock failed
    Finer: TX afterCompletion callback, status=ROLLEDBACK
    Finest: Connection released to connection pool [default].
    Finer: release unit of work
    Finer: client released

    Warning: EJB5184:A system exception occurred during an invocation on EJB EmployeeUpdateServiceBean, method: public nl.notes.jpa.Employee nl.notes.jpa.EmployeeUpdateServiceBean.findForEmployeeUpdate(int)
    Warning: javax.ejb.EJBException: javax.persistence.PessimisticLockException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.DatabaseExceptionInternal Exception: java.sql.SQLTransactionRollbackException: A lock could not be obtained within the time
    ...
    Finest: --- FIND DIDN'T WORK ---
    Severe: javax.ejb.EJBException: javax.persistence.PessimisticLockException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.2.v20111125-r10461):
     
    Daniel Jabonete
    Ranch Hand
    Posts: 84
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Hi Fritz,

    I had tried your implementation codes and steps to hit the exception. I ran these codes in a web setting using two browsers with respective Session ID.

    Although, I was able to lock the entity and the other user wait until the first user commits his changes, it seems there were different exceptions with each scenarios, especially when the lock expires. I encountered “javax.transaction.NotSupportedException: Nested Transactions are not supported” and “java.lang.IllegalMonitorStateException”, that I believed can be treated easily, hence based on these tests the “PessimisticLockException” seems not that easy to get around and can be thrown as an explicit exception, as we intended it to be.

    I will still try and search a couple of resolutions in order to attain a much direct or straight-forward approach, and will post it here.

    My apologies for my late response to this post.

    If you guys still have other ideas or codes that you would like to show or share in relation to this topic/subject, please don’t hesitate to post it here.

    Thanks very much!

    Cheers!
    Daniel
     
    Frits Walraven
    Creator of Enthuware JWS+ V6
    Saloon Keeper
    Pie
    Posts: 2536
    113
    Android Chrome Eclipse IDE
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    hence based on these tests the “PessimisticLockException” seems not that easy to get around and can be thrown as an explicit exception, as we intended it to be.

    I am not sure what you mean with this. The JPA specs are clear about this and specifiy exactly when an JPA implementation should throw a PessimisticLockException. You don't thow such an exception yourself.

    In my example the first client calls the find method and locks the row in the underlying database

    When the second client shortly after that calls the find method (note that the transaction of the first client is not yet commited as the commit is in the updateEmployee() method of the BM Stateful Bean) it should throw a PessimisticLockException as the row is locked by the first client. The JPA specifications specify:
    3.4.4.2 PESSIMISTIC_READ, PESSIMISTIC_WRITE, PESSIMISTIC_FORCE_INCREMENT
    ...
    When the lock cannot be obtained, and the database locking failure results in transaction-level rollback, the provider must throw the PessimisticLockException and ensure that the JTA transaction or EntityTransaction has been marked for rollback. When the lock cannot be obtained, and the database
     
    • Post Reply
    • Bookmark Topic Watch Topic
    • New Topic