HHH-8576 - Query not properly locking non-versioned entities associated with PersistenceContext

This commit is contained in:
Steve Ebersole 2013-09-30 13:43:30 -05:00
parent 7c6b358d4f
commit ffa67243b8
2 changed files with 84 additions and 15 deletions

View File

@ -1539,7 +1539,7 @@ private void instanceAlreadyLoaded(
final Loadable persister,
final EntityKey key,
final Object object,
final LockMode lockMode,
final LockMode requestedLockMode,
final SessionImplementor session)
throws HibernateException, SQLException {
if ( !persister.isInstance( object ) ) {
@ -1547,23 +1547,18 @@ private void instanceAlreadyLoaded(
"loaded object was of wrong class " + object.getClass(),
key.getIdentifier(),
persister.getEntityName()
);
);
}
if ( LockMode.NONE != lockMode && upgradeLocks() ) { //no point doing this if NONE was requested
final boolean isVersionCheckNeeded = persister.isVersioned() &&
session.getPersistenceContext().getEntry(object)
.getLockMode().lessThan( lockMode );
// we don't need to worry about existing version being uninitialized
// because this block isn't called by a re-entrant load (re-entrant
// loads _always_ have lock mode NONE)
if (isVersionCheckNeeded) {
if ( LockMode.NONE != requestedLockMode && upgradeLocks() ) { //no point doing this if NONE was requested
final EntityEntry entry = session.getPersistenceContext().getEntry( object );
if ( entry.getLockMode().lessThan( requestedLockMode ) ) {
//we only check the version when _upgrading_ lock modes
checkVersion( i, persister, key.getIdentifier(), object, rs, session );
if ( persister.isVersioned() ) {
checkVersion( i, persister, key.getIdentifier(), object, rs, session );
}
//we need to upgrade the lock mode to the mode requested
session.getPersistenceContext().getEntry(object)
.setLockMode(lockMode);
entry.setLockMode( requestedLockMode );
}
}
}

View File

@ -23,9 +23,14 @@
*/
package org.hibernate.jpa.test.lock;
import java.util.List;
import java.util.Map;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.Id;
import javax.persistence.LockModeType;
import javax.persistence.Query;
import javax.persistence.Table;
import org.junit.Test;
@ -49,7 +54,7 @@
public class QueryLockingTest extends BaseEntityManagerFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] { Lockable.class };
return new Class[] { Lockable.class, LocalEntity.class };
}
@Override
@ -279,4 +284,73 @@ public void testOptimisticSpecific() {
em.getTransaction().commit();
em.close();
}
/**
* lock some entities via a query and check the resulting lock mode type via EntityManager
*/
@Test
public void testEntityLockModeStateAfterQueryLocking() {
// Create some test data
EntityManager em = getOrCreateEntityManager();
em.getTransaction().begin();
em.persist( new LocalEntity( 1, "test" ) );
em.getTransaction().commit();
// em.close();
// issue the query with locking
// em = getOrCreateEntityManager();
em.getTransaction().begin();
Query query = em.createQuery( "select l from LocalEntity l" );
assertEquals( LockModeType.NONE, query.getLockMode() );
query.setLockMode( LockModeType.PESSIMISTIC_READ );
assertEquals( LockModeType.PESSIMISTIC_READ, query.getLockMode() );
List<LocalEntity> results = query.getResultList();
// and check the lock mode for each result
for ( LocalEntity e : results ) {
assertEquals( LockModeType.PESSIMISTIC_READ, em.getLockMode( e ) );
}
em.getTransaction().commit();
em.close();
// clean up test data
em = getOrCreateEntityManager();
em.getTransaction().begin();
em.createQuery( "delete from LocalEntity" ).executeUpdate();
em.getTransaction().commit();
em.close();
}
@Entity( name = "LocalEntity" )
@Table( name = "LocalEntity" )
public static class LocalEntity {
private Integer id;
private String name;
public LocalEntity() {
}
public LocalEntity(Integer id, String name) {
this.id = id;
this.name = name;
}
@Id
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}