alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Hibernate example source code file (JPALockTest.java)

This example Hibernate source code file (JPALockTest.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Hibernate tags/keywords

abstractjpatest, item, item, long, myentity, session, session, string, test, test, throwable, transaction, transaction, upgrade

The Hibernate JPALockTest.java source code

package org.hibernate.test.jpa.lock;

import org.hibernate.LockMode;
import org.hibernate.Session;
import org.hibernate.Transaction;

import org.junit.Test;

import org.hibernate.testing.DialectChecks;
import org.hibernate.testing.RequiresDialectFeature;
import org.hibernate.test.jpa.AbstractJPATest;
import org.hibernate.test.jpa.Item;
import org.hibernate.test.jpa.MyEntity;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

/**
 * Tests specifically relating to section 3.3.5.3 [Lock Modes] of the
 * JPA persistence specification (as of the <i>Proposed Final Draft).
 *
 * @author Steve Ebersole
 */
@RequiresDialectFeature( DialectChecks.DoesReadCommittedNotCauseWritersToBlockReadersCheck.class )
public class JPALockTest extends AbstractJPATest {
	/**
	 * Test the equivalent of EJB3 LockModeType.READ
	 * <p/>
	 * From the spec:
	 * <p/>
	 * If transaction T1 calls lock(entity, LockModeType.READ) on a versioned object, the entity
	 * manager must ensure that neither of the following phenomena can occur:<ul>
	 * <li>P1 (Dirty read): Transaction T1 modifies a row. Another transaction T2 then reads that row and
	 * obtains the modified value, before T1 has committed or rolled back. Transaction T2 eventually
	 * commits successfully; it does not matter whether T1 commits or rolls back and whether it does
	 * so before or after T2 commits.
	 * <li>P2 (Non-repeatable read): Transaction T1 reads a row. Another transaction T2 then modifies or
	 * deletes that row, before T1 has committed. Both transactions eventually commit successfully.
	 * <p/>
	 * This will generally be achieved by the entity manager acquiring a lock on the underlying database row.
	 * Any such lock may be obtained immediately (so long as it is retained until commit completes), or the
	 * lock may be deferred until commit time (although even then it must be retained until the commit completes).
	 * Any implementation that supports repeatable reads in a way that prevents the above phenomena
	 * is permissible.
	 * <p/>
	 * The persistence implementation is not required to support calling lock(entity, LockMode-Type.READ)
	 * on a non-versioned object. When it cannot support such a lock call, it must throw the
	 * PersistenceException. When supported, whether for versioned or non-versioned objects, LockMode-Type.READ
	 * must always prevent the phenomena P1 and P2. Applications that call lock(entity, LockModeType.READ)
	 * on non-versioned objects will not be portable.
	 * <p/>
	 * EJB3 LockModeType.READ actually maps to the Hibernate LockMode.OPTIMISTIC
	 */
	@Test
	public void testLockModeTypeRead() {
		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 );
		t1.commit();
		s1.close();

		Long itemId = item.getId();

		// do the isolated update
		s1 = sessionFactory().openSession();
		t1 = s1.beginTransaction();
		item = (Item) s1.get( Item.class, itemId );
		s1.lock( item, LockMode.UPGRADE );
		item.setName( "updated" );
		s1.flush();

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

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

		item2 = (Item) s2.get( Item.class, itemId );
		assertEquals( "repeatable read not maintained", initialName, item2.getName() );
		t2.commit();
		s2.close();

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

	/**
	 * 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 before 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();
	}
}

Other Hibernate examples (source code examples)

Here is a short list of links related to this Hibernate JPALockTest.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.