Exemplo n.º 1
0
  /**
   * Test the equivalent of EJB3 LockModeType.WRITE
   *
   * <p>From the spec:
   *
   * <p>If transaction T1 calls lock(entity, LockModeType.WRITE) on a versioned object, the entity
   * manager must avoid the phenomena P1 and P2 (as with LockModeType.READ) and must also force an
   * update (increment) to the entity's version column. A forced version update may be performed
   * immediately, or may be deferred until a flush or commit. If an entity is removed beforeQuery a
   * deferred version update was to have been applied, the forced version update is omitted, since
   * the underlying database row no longer exists.
   *
   * <p>The persistence implementation is not required to support calling lock(entity,
   * LockMode-Type.WRITE) on a non-versioned object. When it cannot support a such lock call, it
   * must throw the PersistenceException. When supported, whether for versioned or non-versioned
   * objects, LockMode-Type.WRITE must always prevent the phenomena P1 and P2. For non-versioned
   * objects, whether or not LockModeType.WRITE has any additional behaviour is vendor-specific.
   * Applications that call lock(entity, LockModeType.WRITE) on non-versioned objects will not be
   * portable.
   *
   * <p>Due to the requirement that LockModeType.WRITE needs to force a version increment, a new
   * Hibernate LockMode was added to support this behavior: {@link org.hibernate.LockMode#FORCE}.
   */
  @Test
  public void testLockModeTypeWrite() {
    if (!readCommittedIsolationMaintained("ejb3 lock tests")) {
      return;
    }
    final String initialName = "lock test";
    // set up some test data
    Session s1 = sessionFactory().openSession();
    Transaction t1 = s1.beginTransaction();
    Item item = new Item();
    item.setName(initialName);
    s1.save(item);
    MyEntity myEntity = new MyEntity();
    myEntity.setName("Test");
    s1.save(myEntity);
    t1.commit();
    s1.close();

    Long itemId = item.getId();
    long initialVersion = item.getVersion();

    s1 = sessionFactory().openSession();
    t1 = s1.beginTransaction();
    item = (Item) s1.get(Item.class, itemId);
    s1.lock(item, LockMode.FORCE);
    assertEquals("no forced version increment", initialVersion + 1, item.getVersion());

    myEntity = (MyEntity) s1.get(MyEntity.class, myEntity.getId());
    s1.lock(myEntity, LockMode.FORCE);
    assertTrue("LockMode.FORCE on a un-versioned entity should degrade nicely to UPGRADE", true);

    s1.lock(item, LockMode.FORCE);
    assertEquals("subsequent LockMode.FORCE did not no-op", initialVersion + 1, item.getVersion());

    Session s2 = sessionFactory().openSession();
    Transaction t2 = s2.beginTransaction();
    Item item2 = (Item) s2.get(Item.class, itemId);
    assertEquals("isolation not maintained", initialName, item2.getName());

    item.setName("updated-1");
    s1.flush();
    // currently an unfortunate side effect...
    assertEquals(initialVersion + 2, item.getVersion());

    t1.commit();
    s1.close();

    item2.setName("updated");
    try {
      t2.commit();
      fail("optimistic lock should have failed");
    } catch (Throwable ignore) {
      // expected behavior
      t2.rollback();
    } finally {
      s2.close();
    }

    s1 = sessionFactory().openSession();
    t1 = s1.beginTransaction();
    s1.delete(item);
    s1.delete(myEntity);
    t1.commit();
    s1.close();
  }