HHH-9474 Fixing perfomance issue with ElementCollection
This commit is contained in:
parent
536b814dc8
commit
1ddcc7075f
|
@ -683,9 +683,19 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
|
|||
// the param would have to be bound twice. Until we eventually add "parameter bind points" concepts to the
|
||||
// AST in ORM 5+, handling this type of condition is either extremely difficult or impossible. Forcing
|
||||
// recreation isn't ideal, but not really any other option in ORM 4.
|
||||
if ( persister.getElementType() instanceof CompositeType ) {
|
||||
CompositeType componentType = (CompositeType) persister.getElementType();
|
||||
return !componentType.hasNotNullProperty();
|
||||
// Selecting a type used in where part of update statement
|
||||
// (must match condidion in org.hibernate.persister.collection.BasicCollectionPersister.doUpdateRows).
|
||||
// See HHH-9474
|
||||
Type whereType;
|
||||
if ( persister.hasIndex() ) {
|
||||
whereType = persister.getIndexType();
|
||||
}
|
||||
else {
|
||||
whereType = persister.getElementType();
|
||||
}
|
||||
if ( whereType instanceof CompositeType ) {
|
||||
CompositeType componentIndexType = (CompositeType) whereType;
|
||||
return !componentIndexType.hasNotNullProperty();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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.annotations.collectionelement.recreate;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
|
||||
/**
|
||||
* @author Sergey Astakhov
|
||||
*/
|
||||
@Entity
|
||||
@GenericGenerator(name = "increment", strategy = "increment")
|
||||
public class Poi {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Integer id;
|
||||
|
||||
private String name;
|
||||
|
||||
public Poi() {
|
||||
}
|
||||
|
||||
public Poi(String _name) {
|
||||
name = _name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String _name) {
|
||||
name = _name;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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.annotations.collectionelement.recreate;
|
||||
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author Sergey Astakhov
|
||||
*/
|
||||
@Embeddable
|
||||
public class PoiArrival {
|
||||
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
private Date expectedTime;
|
||||
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
private Date arriveTime;
|
||||
|
||||
public Date getExpectedTime() {
|
||||
return expectedTime;
|
||||
}
|
||||
|
||||
public void setExpectedTime(Date _expectedTime) {
|
||||
expectedTime = _expectedTime;
|
||||
}
|
||||
|
||||
public Date getArriveTime() {
|
||||
return arriveTime;
|
||||
}
|
||||
|
||||
public void setArriveTime(Date _arriveTime) {
|
||||
arriveTime = _arriveTime;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* 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.annotations.collectionelement.recreate;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.persistence.*;
|
||||
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
|
||||
/**
|
||||
* @author Sergey Astakhov
|
||||
*/
|
||||
@Entity
|
||||
@GenericGenerator(name = "increment", strategy = "increment")
|
||||
public class RaceExecution {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Integer id;
|
||||
|
||||
@ElementCollection
|
||||
@MapKeyClass(Poi.class)
|
||||
@MapKeyJoinColumn(name = "poi", nullable = false)
|
||||
@CollectionTable(name = "race_poi_arrival", joinColumns = @JoinColumn(name = "race_id"))
|
||||
private Map<Poi, PoiArrival> poiArrival;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Map<Poi, PoiArrival> getPoiArrival() {
|
||||
return poiArrival;
|
||||
}
|
||||
|
||||
public void setPoiArrival(Map<Poi, PoiArrival> _poiArrival) {
|
||||
poiArrival = _poiArrival;
|
||||
}
|
||||
|
||||
public void arriveToPoi(Poi poi, Date time) {
|
||||
if ( poiArrival == null ) {
|
||||
poiArrival = new HashMap<Poi, PoiArrival>();
|
||||
}
|
||||
|
||||
PoiArrival arrival = poiArrival.get( poi );
|
||||
if ( arrival == null ) {
|
||||
arrival = new PoiArrival();
|
||||
poiArrival.put( poi, arrival );
|
||||
}
|
||||
|
||||
arrival.setArriveTime( time );
|
||||
}
|
||||
|
||||
public void expectedArrive(Poi poi, Date time) {
|
||||
if ( poiArrival == null ) {
|
||||
poiArrival = new HashMap<Poi, PoiArrival>();
|
||||
}
|
||||
|
||||
PoiArrival arrival = poiArrival.get( poi );
|
||||
if ( arrival == null ) {
|
||||
arrival = new PoiArrival();
|
||||
poiArrival.put( poi, arrival );
|
||||
}
|
||||
|
||||
arrival.setExpectedTime( time );
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* 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.annotations.collectionelement.recreate;
|
||||
|
||||
import org.hibernate.BaseSessionEventListener;
|
||||
import org.hibernate.Session;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Sergey Astakhov
|
||||
*/
|
||||
public class RecreateCollectionTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
private static class StatementsCounterListener extends BaseSessionEventListener {
|
||||
int statements;
|
||||
|
||||
@Override
|
||||
public void jdbcExecuteStatementEnd() {
|
||||
statements++;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-9474")
|
||||
public void testUpdateCollectionOfElements() throws Exception {
|
||||
Session s = openSession();
|
||||
|
||||
s.getTransaction().begin();
|
||||
|
||||
Poi poi1 = new Poi( "Poi 1" );
|
||||
Poi poi2 = new Poi( "Poi 2" );
|
||||
|
||||
s.save( poi1 );
|
||||
s.save( poi2 );
|
||||
|
||||
RaceExecution race = new RaceExecution();
|
||||
|
||||
s.save( race );
|
||||
|
||||
Date currentTime = new Date();
|
||||
|
||||
race.arriveToPoi( poi1, currentTime );
|
||||
race.expectedArrive( poi2, new Date( currentTime.getTime() + 60 * 1000 ) );
|
||||
|
||||
s.flush();
|
||||
|
||||
assertEquals( 2, race.getPoiArrival().size() );
|
||||
|
||||
StatementsCounterListener statementsCounterListener = new StatementsCounterListener();
|
||||
|
||||
s.addEventListeners( statementsCounterListener );
|
||||
|
||||
race.arriveToPoi( poi2, new Date( currentTime.getTime() + 2 * 60 * 1000 ) );
|
||||
|
||||
s.flush();
|
||||
|
||||
assertEquals( 2, race.getPoiArrival().size() );
|
||||
|
||||
// There is should be one UPDATE statement. Without fix there is one DELETE and two INSERT-s.
|
||||
|
||||
assertEquals( 1, statementsCounterListener.statements );
|
||||
|
||||
s.getTransaction().rollback();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class[] getAnnotatedClasses() {
|
||||
return new Class[] {
|
||||
Poi.class,
|
||||
RaceExecution.class
|
||||
};
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue