HHH-13000 - Fix for refreshing entities under PESSIMISTIC_WRITE lock

This commit is contained in:
Jan-Willem Gmelig Meyling 2018-09-30 18:24:39 +02:00 committed by Guillaume Smet
parent 6f5b1e5543
commit 415fcfd048
2 changed files with 89 additions and 3 deletions

View File

@ -183,7 +183,9 @@ public class DefaultRefreshEventListener implements RefreshEventListener {
// the requested lock-mode is less restrictive than the current one // the requested lock-mode is less restrictive than the current one
// - pass along the current lock-mode (after accounting for WRITE) // - pass along the current lock-mode (after accounting for WRITE)
lockOptionsToUse = LockOptions.copy( event.getLockOptions(), new LockOptions() ); lockOptionsToUse = LockOptions.copy( event.getLockOptions(), new LockOptions() );
if ( currentLockMode == LockMode.WRITE ) { if ( currentLockMode == LockMode.WRITE ||
currentLockMode == LockMode.PESSIMISTIC_WRITE ||
currentLockMode == LockMode.PESSIMISTIC_READ ) {
// our transaction should already hold the exclusive lock on // our transaction should already hold the exclusive lock on
// the underlying row - so READ should be sufficient. // the underlying row - so READ should be sufficient.
// //
@ -193,8 +195,9 @@ public class DefaultRefreshEventListener implements RefreshEventListener {
// locks // locks
lockOptionsToUse.setLockMode( LockMode.READ ); lockOptionsToUse.setLockMode( LockMode.READ );
// and prepare to reset the entry lock-mode to WRITE after the refresh completes // and prepare to reset the entry lock-mode to the previous lock mode after
postRefreshLockMode = LockMode.WRITE; // the refresh completes
postRefreshLockMode = currentLockMode;
} }
else { else {
lockOptionsToUse.setLockMode( currentLockMode ); lockOptionsToUse.setLockMode( currentLockMode );

View File

@ -0,0 +1,83 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.jpa.test.lock;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinTable;
import javax.persistence.LockModeType;
import javax.persistence.ManyToOne;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.testing.TestForIssue;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
@TestForIssue(jiraKey = "HHH-13000")
public class PessimisticWriteWithOptionalOuterJoinBreaksRefreshTest extends BaseEntityManagerFunctionalTestCase {
@Entity(name = "Parent")
public static class Parent {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Long id;
}
@Entity(name = "Child")
public static class Child {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Long id;
@ManyToOne(cascade = { CascadeType.PERSIST })
@JoinTable(name = "test")
Parent parent;
}
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] { Parent.class, Child.class };
}
private Child child;
@Override
protected void afterEntityManagerFactoryBuilt() {
doInJPA( this::entityManagerFactory, em -> {
child = new Child();
child.parent = new Parent();
em.persist( child );
} );
}
@Test
public void pessimisticWriteWithOptionalOuterJoinBreaksRefreshTest() {
doInJPA( this::entityManagerFactory, em -> {
child = em.find( Child.class, child.id );
em.lock( child, LockModeType.PESSIMISTIC_WRITE );
em.flush();
em.refresh( child );
} );
}
@Test
public void pessimisticReadWithOptionalOuterJoinBreaksRefreshTest() {
doInJPA( this::entityManagerFactory, em -> {
child = em.find( Child.class, child.id );
em.lock( child, LockModeType.PESSIMISTIC_READ );
em.flush();
em.refresh( child );
} );
}
}