HHH-16541 - (Jakarta EE 10 Platform TCK) jpa/core/lock/query/Client.java#getResultListTest1 test regression
This commit is contained in:
parent
03003c3794
commit
17a01358fa
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* 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.orm.test.locking.jpa;
|
||||||
|
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Basic;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Table(name="departments")
|
||||||
|
public class Department {
|
||||||
|
@Id
|
||||||
|
private Integer id;
|
||||||
|
@Basic
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
protected Department() {
|
||||||
|
// for Hibernate use
|
||||||
|
}
|
||||||
|
|
||||||
|
public Department(Integer id, String name) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* 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.orm.test.locking.jpa;
|
||||||
|
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.FetchType;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Basic;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Table(name = "employees")
|
||||||
|
public class Employee {
|
||||||
|
@Id
|
||||||
|
private Integer id;
|
||||||
|
@Basic
|
||||||
|
private String name;
|
||||||
|
@Basic
|
||||||
|
private float salary;
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@JoinColumn(name = "dept_fk")
|
||||||
|
private Department department;
|
||||||
|
|
||||||
|
protected Employee() {
|
||||||
|
// for Hibernate use
|
||||||
|
}
|
||||||
|
|
||||||
|
public Employee(Integer id, String name, float salary, Department department) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.salary = salary;
|
||||||
|
this.department = department;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getSalary() {
|
||||||
|
return salary;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSalary(float salary) {
|
||||||
|
this.salary = salary;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Department getDepartment() {
|
||||||
|
return department;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDepartment(Department department) {
|
||||||
|
this.department = department;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
* 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.orm.test.locking.jpa;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.query.spi.QueryImplementor;
|
||||||
|
|
||||||
|
import org.hibernate.testing.jdbc.SQLStatementInspector;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import jakarta.persistence.LockModeType;
|
||||||
|
import jakarta.persistence.LockTimeoutException;
|
||||||
|
import jakarta.persistence.PessimisticLockException;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.fail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@DomainModel(annotatedClasses = { Employee.class, Department.class })
|
||||||
|
@SessionFactory(useCollectingStatementInspector = true)
|
||||||
|
public class FollowOnLockingTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testQueryLockingWithoutFollowOn(SessionFactoryScope scope) {
|
||||||
|
testQueryLocking( scope, false );
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
public void testQueryLockingWithFollowOn(SessionFactoryScope scope) {
|
||||||
|
testQueryLocking( scope, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testQueryLocking(SessionFactoryScope scope, boolean followOnLocking) {
|
||||||
|
SQLStatementInspector statementInspector = scope.getCollectingStatementInspector();
|
||||||
|
scope.inSession( (s) -> {
|
||||||
|
// After a transaction commit, the lock mode is set to NONE, which the TCK also does
|
||||||
|
scope.inTransaction(
|
||||||
|
s,
|
||||||
|
session -> {
|
||||||
|
final Department engineering = new Department( 1, "Engineering" );
|
||||||
|
session.persist( engineering );
|
||||||
|
|
||||||
|
session.persist( new Employee( 1, "John", 9F, engineering ) );
|
||||||
|
session.persist( new Employee( 2, "Mary", 10F, engineering ) );
|
||||||
|
session.persist( new Employee( 3, "June", 11F, engineering ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
scope.inTransaction(
|
||||||
|
s,
|
||||||
|
session -> {
|
||||||
|
statementInspector.clear();
|
||||||
|
|
||||||
|
final QueryImplementor<Employee> query = session.createQuery(
|
||||||
|
"select e from Employee e where e.salary > 10",
|
||||||
|
Employee.class
|
||||||
|
);
|
||||||
|
if ( followOnLocking ) {
|
||||||
|
query.setFollowOnLocking( true );
|
||||||
|
}
|
||||||
|
query.setLockMode( LockModeType.PESSIMISTIC_READ );
|
||||||
|
final List<Employee> employees = query.list();
|
||||||
|
|
||||||
|
assertThat( employees ).hasSize( 1 );
|
||||||
|
final LockModeType appliedLockMode = session.getLockMode( employees.get( 0 ) );
|
||||||
|
assertThat( appliedLockMode ).isIn(
|
||||||
|
LockModeType.PESSIMISTIC_READ,
|
||||||
|
LockModeType.PESSIMISTIC_WRITE
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( followOnLocking ) {
|
||||||
|
statementInspector.assertExecutedCount( 2 );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
statementInspector.assertExecutedCount( 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// with the initial txn still active (locks still held), try to update the row from another txn
|
||||||
|
scope.inTransaction( (session2) -> {
|
||||||
|
final Employee june = session2.find( Employee.class, 3 );
|
||||||
|
june.setSalary( 90000F );
|
||||||
|
} );
|
||||||
|
fail( "Locked entity update was allowed" );
|
||||||
|
}
|
||||||
|
catch (PessimisticLockException | LockTimeoutException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void dropTestData(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
session.createMutationQuery( "delete Employee" ).executeUpdate();
|
||||||
|
session.createMutationQuery( "delete Department" ).executeUpdate();
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue