EntityTransaction.commit() does not release a pessimistic lock

#1

It appears that EntityTransaction.commit() does not release a pessimistic lock -> test code below.

I tried it in with the current (2.7.6_01) and older versions (2.6.9, 2.5.7, 2.4.7) with the same result.

(side note: EntityTransaction.rollback() releases it correctly)


// Account.java

package icke;
import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Account {
  @Id
  private int no;
  private int balance;
  public Account(int n) {
    no = n;
    balance = 1000;
  }
  public int getNo() {
    return no;
  }
  public int getBalance() {
    return balance;
  }
  public void credit(int a) {
    balance += a;
  }
}

// Main.java

package icke;
import javax.persistence.*;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;

public class Main {
  public static void main(String[] args) {
    try {
      testLocking();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }
  public static void testLocking() {
    // persist
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("accounts.odb");
    EntityManager em = emf.createEntityManager();
    em.getTransaction().begin();
    em.persist(new Account(0));
    em.getTransaction().commit();
    // update
    EntityManager em1 = emf.createEntityManager();
    em1.getTransaction().begin();
    Account a1 = em1.find(Account.class, 0, LockModeType.PESSIMISTIC_WRITE);
    a1.credit(10);
    em1.getTransaction().commit();
    System.out.println(em1.getLockMode(a1)); // -> PESSIMISTIC_WRITE
    // try to retrieve again
    EntityManager em2 = emf.createEntityManager();
    em2.getTransaction().begin();
    Account a2 = em2.find(Account.class, 0, LockModeType.PESSIMISTIC_READ); // -> LockTimeoutException
    System.out.println(a2.getBalance());
    em2.getTransaction().commit();
  }
}
#2

You are right. Pessimistic locks are not released automatically (by default) on transaction commit. The reason is that entity objects are still in managed status with valid values after commit and the application can still use them for further processing and update. Locks are released automatically when the EntityManager is closed.

In JDO you can change the default using setDetachAllOnCommitsetDetachAllOnCommit(flag)PersistenceManager's methodSets the detachAllOnCommit setting.See JavaDoc Reference Page.... You can also use this JDO feature from JPA when you use ObjectDB. Giving an EntityManager em:

        PersistenceManager pm  = em.unwrap(PersistenceManager.class);
        pm.setDetachAllOnCommit(true);

In this case entity objects will be detached and unlocked on transaction commit.

ObjectDB Support
ObjectDB - Fast Object Database for Java (JPA/JDO)

Post Reply

To post a reply and/or subscribe to update notifications - please login