HHH-12257 : Refreshing an entity clears the lock mode
(cherry picked from commit a286232da3
)
This commit is contained in:
parent
2c15a5f587
commit
771c8fdf82
|
@ -10,7 +10,11 @@ import java.io.Serializable;
|
|||
import java.util.IdentityHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.LockModeType;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.PersistentObjectException;
|
||||
import org.hibernate.UnresolvableObjectException;
|
||||
import org.hibernate.action.spi.AfterTransactionCompletionProcess;
|
||||
|
@ -173,7 +177,15 @@ public class DefaultRefreshEventListener implements RefreshEventListener {
|
|||
|
||||
String previousFetchProfile = source.getLoadQueryInfluencers().getInternalFetchProfile();
|
||||
source.getLoadQueryInfluencers().setInternalFetchProfile( "refresh" );
|
||||
Object result = persister.load( id, object, event.getLockOptions(), source );
|
||||
|
||||
// Use the entity's current LockMode if it is greater than event.getLockMode()
|
||||
final LockMode currentLockMode = e == null ? null : e.getLockMode();
|
||||
LockOptions lockOptionsToUse = event.getLockOptions();
|
||||
if ( currentLockMode != null && currentLockMode.greaterThan( event.getLockMode() ) ) {
|
||||
lockOptionsToUse = LockOptions.copy( event.getLockOptions(), new LockOptions() );
|
||||
lockOptionsToUse.setLockMode( currentLockMode );
|
||||
}
|
||||
Object result = persister.load( id, object, lockOptionsToUse, source );
|
||||
// Keep the same read-only/modifiable setting for the entity that it had before refreshing;
|
||||
// If it was transient, then set it to the default for the source.
|
||||
if ( result != null ) {
|
||||
|
|
|
@ -6,12 +6,17 @@
|
|||
*/
|
||||
package org.hibernate.test.locking;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import javax.persistence.LockModeType;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.dialect.SQLServerDialect;
|
||||
import org.hibernate.dialect.SybaseASE15Dialect;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
|
||||
import org.hibernate.testing.SkipForDialect;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
|
@ -21,6 +26,7 @@ import org.hibernate.testing.util.ExceptionUtil;
|
|||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
|
@ -136,7 +142,7 @@ public class LockModeTest extends BaseCoreFunctionalTestCase {
|
|||
// shouldn't throw an exception
|
||||
session.createQuery( "SELECT a.value FROM A a where a.id = :id" )
|
||||
.setLockMode( "a", LockMode.NONE )
|
||||
.setParameter( "id", 1L )
|
||||
.setParameter( "id", id )
|
||||
.list();
|
||||
} );
|
||||
}
|
||||
|
@ -153,6 +159,75 @@ public class LockModeTest extends BaseCoreFunctionalTestCase {
|
|||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-12257")
|
||||
public void testRefreshLockedEntity() {
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
A a = session.get( A.class, id, LockMode.PESSIMISTIC_READ );
|
||||
checkLockMode( a, LockMode.PESSIMISTIC_READ, session );
|
||||
session.refresh( a );
|
||||
checkLockMode( a, LockMode.PESSIMISTIC_READ, session );
|
||||
session.refresh( A.class.getName(), a );
|
||||
checkLockMode( a, LockMode.PESSIMISTIC_READ, session );
|
||||
session.refresh( a, Collections.emptyMap() );
|
||||
checkLockMode( a, LockMode.PESSIMISTIC_READ, session );
|
||||
session.refresh( a, null, Collections.emptyMap() );
|
||||
checkLockMode( a, LockMode.PESSIMISTIC_READ, session );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-12257")
|
||||
public void testRefreshWithExplicitLowerLevelLockMode() {
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
A a = session.get( A.class, id, LockMode.PESSIMISTIC_READ );
|
||||
checkLockMode( a, LockMode.PESSIMISTIC_READ, session );
|
||||
session.refresh( a, LockMode.READ );
|
||||
checkLockMode( a, LockMode.PESSIMISTIC_READ, session );
|
||||
session.refresh( a, LockModeType.READ );
|
||||
checkLockMode( a, LockMode.PESSIMISTIC_READ, session );
|
||||
session.refresh( a, LockModeType.READ, Collections.emptyMap() );
|
||||
checkLockMode( a, LockMode.PESSIMISTIC_READ, session );
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-12257")
|
||||
public void testRefreshWithExplicitHigherLevelLockMode() {
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
A a = session.get( A.class, id );
|
||||
checkLockMode( a, LockMode.READ, session );
|
||||
session.refresh( a, LockMode.UPGRADE_NOWAIT );
|
||||
checkLockMode( a, LockMode.UPGRADE_NOWAIT, session );
|
||||
session.refresh( a, LockModeType.PESSIMISTIC_READ );
|
||||
checkLockMode( a, LockMode.PESSIMISTIC_READ, session );
|
||||
session.refresh( a, LockModeType.PESSIMISTIC_WRITE, Collections.emptyMap() );
|
||||
checkLockMode( a, LockMode.PESSIMISTIC_WRITE, session );
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-12257")
|
||||
public void testRefreshAfterUpdate() {
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
A a = session.get( A.class, id );
|
||||
checkLockMode( a, LockMode.READ, session );
|
||||
a.setValue( "new value" );
|
||||
session.flush();
|
||||
checkLockMode( a, LockMode.WRITE, session );
|
||||
session.refresh( a );
|
||||
checkLockMode( a, LockMode.WRITE, session );
|
||||
} );
|
||||
}
|
||||
|
||||
private void checkLockMode(Object entity, LockMode expectedLockMode, Session session) {
|
||||
final LockMode lockMode =
|
||||
( (SharedSessionContractImplementor) session ).getPersistenceContext().getEntry( entity ).getLockMode();
|
||||
assertEquals( expectedLockMode, lockMode );
|
||||
}
|
||||
|
||||
private void nowAttemptToUpdateRow() {
|
||||
// here we just need to open a new connection (database session and transaction) and make sure that
|
||||
// we are not allowed to acquire exclusive locks to that row and/or write to that row. That may take
|
||||
|
|
Loading…
Reference in New Issue