HHH-12968 - Flush is not flushing inserts for inherited tables before a select within a transaction
This commit is contained in:
parent
519905b99b
commit
9dfdb2b471
|
@ -77,6 +77,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
|
|||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.engine.spi.ValueInclusion;
|
||||
import org.hibernate.id.IdentifierGenerator;
|
||||
import org.hibernate.id.IdentityGenerator;
|
||||
import org.hibernate.id.PostInsertIdentifierGenerator;
|
||||
import org.hibernate.id.PostInsertIdentityPersister;
|
||||
import org.hibernate.id.insert.Binder;
|
||||
|
@ -138,8 +139,6 @@ import org.hibernate.type.Type;
|
|||
import org.hibernate.type.TypeHelper;
|
||||
import org.hibernate.type.VersionType;
|
||||
|
||||
import static org.hibernate.internal.util.StringHelper.safeInterning;
|
||||
|
||||
/**
|
||||
* Basic functionality for persisting an entity via JDBC
|
||||
* through either generated or custom SQL
|
||||
|
@ -148,7 +147,7 @@ import static org.hibernate.internal.util.StringHelper.safeInterning;
|
|||
*/
|
||||
public abstract class AbstractEntityPersister
|
||||
implements OuterJoinLoadable, Queryable, ClassMetadata, UniqueKeyLoadable,
|
||||
SQLLoadable, LazyPropertyInitializer, PostInsertIdentityPersister, Lockable {
|
||||
SQLLoadable, LazyPropertyInitializer, PostInsertIdentityPersister, Lockable {
|
||||
|
||||
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( AbstractEntityPersister.class );
|
||||
|
||||
|
@ -3129,8 +3128,9 @@ public abstract class AbstractEntityPersister
|
|||
// TODO : shouldn't inserts be Expectations.NONE?
|
||||
final Expectation expectation = Expectations.appropriateExpectation( insertResultCheckStyles[j] );
|
||||
final int jdbcBatchSizeToUse = session.getConfiguredJdbcBatchSize();
|
||||
final boolean useBatch = expectation.canBeBatched() && jdbcBatchSizeToUse > 1;
|
||||
if ( useBatch && inserBatchKey == null) {
|
||||
final boolean useBatch = expectation.canBeBatched() && jdbcBatchSizeToUse > 1 && !( getIdentifierGenerator() instanceof IdentityGenerator );
|
||||
|
||||
if ( useBatch && inserBatchKey == null ) {
|
||||
inserBatchKey = new BasicBatchKey(
|
||||
getEntityName() + "#INSERT",
|
||||
expectation
|
||||
|
|
|
@ -22,7 +22,6 @@ import javax.persistence.ManyToOne;
|
|||
|
||||
import org.hibernate.ScrollMode;
|
||||
import org.hibernate.ScrollableResults;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
|
||||
|
@ -30,6 +29,7 @@ import org.hibernate.testing.DialectChecks;
|
|||
import org.hibernate.testing.RequiresDialectFeature;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
|
@ -113,8 +113,8 @@ public class IdentityJoinedSubclassBatchingTest extends BaseCoreFunctionalTestCa
|
|||
doInHibernate( this::sessionFactory, s -> {
|
||||
int i = 0;
|
||||
ScrollableResults sr = s.createQuery(
|
||||
"select e from Employee e" )
|
||||
.scroll( ScrollMode.FORWARD_ONLY );
|
||||
"select e from Employee e" )
|
||||
.scroll( ScrollMode.FORWARD_ONLY );
|
||||
|
||||
while ( sr.next() ) {
|
||||
Employee e = (Employee) sr.get( 0 );
|
||||
|
@ -125,8 +125,8 @@ public class IdentityJoinedSubclassBatchingTest extends BaseCoreFunctionalTestCa
|
|||
doInHibernate( this::sessionFactory, s -> {
|
||||
int i = 0;
|
||||
ScrollableResults sr = s.createQuery(
|
||||
"select e from Employee e" )
|
||||
.scroll( ScrollMode.FORWARD_ONLY );
|
||||
"select e from Employee e" )
|
||||
.scroll( ScrollMode.FORWARD_ONLY );
|
||||
|
||||
while ( sr.next() ) {
|
||||
Employee e = (Employee) sr.get( 0 );
|
||||
|
@ -135,6 +135,76 @@ public class IdentityJoinedSubclassBatchingTest extends BaseCoreFunctionalTestCa
|
|||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAssertSubclassInsertedSuccessfullyAfterCommit() {
|
||||
final int nEntities = 10;
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
for ( int i = 0; i < nEntities; i++ ) {
|
||||
Employee e = new Employee();
|
||||
e.setName( "Mark" );
|
||||
e.setTitle( "internal sales" );
|
||||
e.setSex( 'M' );
|
||||
e.setAddress( "buckhead" );
|
||||
e.setZip( "30305" );
|
||||
e.setCountry( "USA" );
|
||||
s.save( e );
|
||||
}
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
long numberOfInsertedEmployee = (long) s.createQuery( "select count(e) from Employee e" ).uniqueResult();
|
||||
Assert.assertEquals( nEntities, numberOfInsertedEmployee );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
int i = 0;
|
||||
ScrollableResults sr = s.createQuery(
|
||||
"select e from Employee e" )
|
||||
.scroll( ScrollMode.FORWARD_ONLY );
|
||||
|
||||
while ( sr.next() ) {
|
||||
Employee e = (Employee) sr.get( 0 );
|
||||
s.delete( e );
|
||||
}
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAssertSubclassInsertedSuccessfullyAfterFlush() {
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Employee e = new Employee();
|
||||
e.setName( "Mark" );
|
||||
e.setTitle( "internal sales" );
|
||||
e.setSex( 'M' );
|
||||
e.setAddress( "buckhead" );
|
||||
e.setZip( "30305" );
|
||||
e.setCountry( "USA" );
|
||||
s.save( e );
|
||||
s.flush();
|
||||
|
||||
long numberOfInsertedEmployee = (long) s.createQuery( "select count(e) from Employee e" ).uniqueResult();
|
||||
Assert.assertEquals( 1L, numberOfInsertedEmployee );
|
||||
} );
|
||||
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
int i = 0;
|
||||
ScrollableResults sr = s.createQuery(
|
||||
"select e from Employee e" )
|
||||
.scroll( ScrollMode.FORWARD_ONLY );
|
||||
|
||||
while ( sr.next() ) {
|
||||
Employee e = (Employee) sr.get( 0 );
|
||||
s.delete( e );
|
||||
}
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Embeddable
|
||||
public static class Address implements Serializable {
|
||||
|
||||
|
|
|
@ -0,0 +1,357 @@
|
|||
/*
|
||||
* 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.test.joinedsubclassbatch;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Inheritance;
|
||||
import javax.persistence.InheritanceType;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.SequenceGenerator;
|
||||
|
||||
import org.hibernate.ScrollMode;
|
||||
import org.hibernate.ScrollableResults;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
|
||||
import org.hibernate.testing.DialectChecks;
|
||||
import org.hibernate.testing.RequiresDialectFeature;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
|
||||
/**
|
||||
* Test batching of insert,update,delete on joined subclasses using SEQUENCE
|
||||
*
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
@TestForIssue(jiraKey = "HHH-12968\n")
|
||||
@RequiresDialectFeature(DialectChecks.SupportsSequences.class)
|
||||
public class SequenceJoinedSubclassBatchingTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] {
|
||||
Person.class,
|
||||
Employee.class,
|
||||
Customer.class
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(Configuration cfg) {
|
||||
cfg.setProperty( Environment.STATEMENT_BATCH_SIZE, "20" );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doBatchInsertUpdateJoinedSubclassNrEqualWithBatch() {
|
||||
doBatchInsertUpdateJoined( 20, 20 );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doBatchInsertUpdateJoinedSubclassNrLessThenBatch() {
|
||||
doBatchInsertUpdateJoined( 19, 20 );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doBatchInsertUpdateJoinedSubclassNrBiggerThenBatch() {
|
||||
doBatchInsertUpdateJoined( 21, 20 );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBatchInsertUpdateSizeEqJdbcBatchSize() {
|
||||
int batchSize = sessionFactory().getSettings().getJdbcBatchSize();
|
||||
doBatchInsertUpdateJoined( 50, batchSize );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBatchInsertUpdateSizeLtJdbcBatchSize() {
|
||||
int batchSize = sessionFactory().getSettings().getJdbcBatchSize();
|
||||
doBatchInsertUpdateJoined( 50, batchSize - 1 );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBatchInsertUpdateSizeGtJdbcBatchSize() {
|
||||
int batchSize = sessionFactory().getSettings().getJdbcBatchSize();
|
||||
doBatchInsertUpdateJoined( 50, batchSize + 1 );
|
||||
}
|
||||
|
||||
public void doBatchInsertUpdateJoined(int nEntities, int nBeforeFlush) {
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
for ( int i = 0; i < nEntities; i++ ) {
|
||||
Employee e = new Employee();
|
||||
e.getId();
|
||||
e.setName( "Mark" );
|
||||
e.setTitle( "internal sales" );
|
||||
e.setSex( 'M' );
|
||||
e.setAddress( "buckhead" );
|
||||
e.setZip( "30305" );
|
||||
e.setCountry( "USA" );
|
||||
s.save( e );
|
||||
if ( i % nBeforeFlush == 0 && i > 0 ) {
|
||||
s.flush();
|
||||
s.clear();
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
int i = 0;
|
||||
ScrollableResults sr = s.createQuery(
|
||||
"select e from Employee e" )
|
||||
.scroll( ScrollMode.FORWARD_ONLY );
|
||||
|
||||
while ( sr.next() ) {
|
||||
Employee e = (Employee) sr.get( 0 );
|
||||
e.setTitle( "Unknown" );
|
||||
}
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
int i = 0;
|
||||
ScrollableResults sr = s.createQuery(
|
||||
"select e from Employee e" )
|
||||
.scroll( ScrollMode.FORWARD_ONLY );
|
||||
|
||||
while ( sr.next() ) {
|
||||
Employee e = (Employee) sr.get( 0 );
|
||||
s.delete( e );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAssertSubclassInsertedSuccessfullyAfterFlush() {
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Employee e = new Employee();
|
||||
e.setName( "Mark" );
|
||||
e.setTitle( "internal sales" );
|
||||
e.setSex( 'M' );
|
||||
e.setAddress( "buckhead" );
|
||||
e.setZip( "30305" );
|
||||
e.setCountry( "USA" );
|
||||
s.save( e );
|
||||
s.flush();
|
||||
|
||||
long numberOfInsertedEmployee = (long) s.createQuery( "select count(e) from Employee e" ).uniqueResult();
|
||||
Assert.assertEquals( 1L, numberOfInsertedEmployee );
|
||||
} );
|
||||
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
int i = 0;
|
||||
ScrollableResults sr = s.createQuery(
|
||||
"select e from Employee e" )
|
||||
.scroll( ScrollMode.FORWARD_ONLY );
|
||||
|
||||
while ( sr.next() ) {
|
||||
Employee e = (Employee) sr.get( 0 );
|
||||
s.delete( e );
|
||||
}
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
public static class Address implements Serializable {
|
||||
|
||||
public String address;
|
||||
|
||||
public String zip;
|
||||
|
||||
public String country;
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public String getZip() {
|
||||
return zip;
|
||||
}
|
||||
|
||||
public void setZip(String zip) {
|
||||
this.zip = zip;
|
||||
}
|
||||
|
||||
public String getCountry() {
|
||||
return country;
|
||||
}
|
||||
|
||||
public void setCountry(String country) {
|
||||
this.country = country;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Customer")
|
||||
public static class Customer extends Person {
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
private Employee salesperson;
|
||||
|
||||
private String comments;
|
||||
|
||||
public Employee getSalesperson() {
|
||||
return salesperson;
|
||||
}
|
||||
|
||||
public void setSalesperson(Employee salesperson) {
|
||||
this.salesperson = salesperson;
|
||||
}
|
||||
|
||||
public String getComments() {
|
||||
return comments;
|
||||
}
|
||||
|
||||
public void setComments(String comments) {
|
||||
this.comments = comments;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Employee")
|
||||
public static class Employee extends Person {
|
||||
|
||||
@Column(nullable = false, length = 20)
|
||||
private String title;
|
||||
|
||||
private BigDecimal salary;
|
||||
|
||||
private double passwordExpiryDays;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
private Employee manager;
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public Employee getManager() {
|
||||
return manager;
|
||||
}
|
||||
|
||||
public void setManager(Employee manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
public BigDecimal getSalary() {
|
||||
return salary;
|
||||
}
|
||||
|
||||
public void setSalary(BigDecimal salary) {
|
||||
this.salary = salary;
|
||||
}
|
||||
|
||||
public double getPasswordExpiryDays() {
|
||||
return passwordExpiryDays;
|
||||
}
|
||||
|
||||
public void setPasswordExpiryDays(double passwordExpiryDays) {
|
||||
this.passwordExpiryDays = passwordExpiryDays;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Person")
|
||||
@Inheritance(strategy = InheritanceType.JOINED)
|
||||
public static class Person {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.SEQUENCE)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false, length = 80)
|
||||
private String name;
|
||||
|
||||
@Column(nullable = false, updatable = false)
|
||||
private char sex;
|
||||
|
||||
@javax.persistence.Version
|
||||
private int version;
|
||||
|
||||
private double heightInches;
|
||||
|
||||
@Embedded
|
||||
private Address address = new Address();
|
||||
|
||||
public Address getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(String string) {
|
||||
this.address.address = string;
|
||||
}
|
||||
|
||||
public void setZip(String string) {
|
||||
this.address.zip = string;
|
||||
}
|
||||
|
||||
public void setCountry(String string) {
|
||||
this.address.country = string;
|
||||
}
|
||||
|
||||
public char getSex() {
|
||||
return sex;
|
||||
}
|
||||
|
||||
public void setSex(char sex) {
|
||||
this.sex = sex;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String identity) {
|
||||
this.name = identity;
|
||||
}
|
||||
|
||||
public double getHeightInches() {
|
||||
return heightInches;
|
||||
}
|
||||
|
||||
public void setHeightInches(double heightInches) {
|
||||
this.heightInches = heightInches;
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(int version) {
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue