HHH-11097 - Performance problem if cached entity has attribute state with an expensive toString() method (LOB, etc)
This commit is contained in:
parent
a00a30f488
commit
c7c9e42145
|
@ -18,7 +18,6 @@ import org.hibernate.event.spi.EventSource;
|
||||||
import org.hibernate.event.spi.EventType;
|
import org.hibernate.event.spi.EventType;
|
||||||
import org.hibernate.event.spi.PreLoadEvent;
|
import org.hibernate.event.spi.PreLoadEvent;
|
||||||
import org.hibernate.event.spi.PreLoadEventListener;
|
import org.hibernate.event.spi.PreLoadEventListener;
|
||||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.type.TypeHelper;
|
import org.hibernate.type.TypeHelper;
|
||||||
|
|
||||||
|
@ -29,8 +28,9 @@ import org.hibernate.type.TypeHelper;
|
||||||
*/
|
*/
|
||||||
public class StandardCacheEntryImpl implements CacheEntry {
|
public class StandardCacheEntryImpl implements CacheEntry {
|
||||||
private final Serializable[] disassembledState;
|
private final Serializable[] disassembledState;
|
||||||
private final String subclass;
|
private final String disassembledStateText;
|
||||||
private final Object version;
|
private final Object version;
|
||||||
|
private final String subclass;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a StandardCacheEntryImpl
|
* Constructs a StandardCacheEntryImpl
|
||||||
|
@ -57,12 +57,18 @@ public class StandardCacheEntryImpl implements CacheEntry {
|
||||||
session,
|
session,
|
||||||
owner
|
owner
|
||||||
);
|
);
|
||||||
subclass = persister.getEntityName();
|
this.disassembledStateText = TypeHelper.toLoggableString(
|
||||||
|
state,
|
||||||
|
persister.getPropertyTypes(),
|
||||||
|
session.getFactory()
|
||||||
|
);
|
||||||
|
this.subclass = persister.getEntityName();
|
||||||
this.version = version;
|
this.version = version;
|
||||||
}
|
}
|
||||||
|
|
||||||
StandardCacheEntryImpl(Serializable[] state, String subclass, Object version) {
|
StandardCacheEntryImpl(Serializable[] state, String disassembledStateText, String subclass, Object version) {
|
||||||
this.disassembledState = state;
|
this.disassembledState = state;
|
||||||
|
this.disassembledStateText = disassembledStateText;
|
||||||
this.subclass = subclass;
|
this.subclass = subclass;
|
||||||
this.version = version;
|
this.version = version;
|
||||||
}
|
}
|
||||||
|
@ -163,6 +169,6 @@ public class StandardCacheEntryImpl implements CacheEntry {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "CacheEntry(" + subclass + ')' + ArrayHelper.toString( disassembledState );
|
return "CacheEntry(" + subclass + " {" + disassembledStateText + "})";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import java.util.Set;
|
||||||
|
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
import org.hibernate.type.TypeHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Structured CacheEntry format for entities. Used to store the entry into the second-level cache
|
* Structured CacheEntry format for entities. Used to store the entry into the second-level cache
|
||||||
|
@ -48,7 +49,12 @@ public class StructuredCacheEntry implements CacheEntryStructure {
|
||||||
for ( int i = 0; i < names.length; i++ ) {
|
for ( int i = 0; i < names.length; i++ ) {
|
||||||
state[i] = (Serializable) map.get( names[i] );
|
state[i] = (Serializable) map.get( names[i] );
|
||||||
}
|
}
|
||||||
return new StandardCacheEntryImpl( state, subclass, version );
|
return new StandardCacheEntryImpl(
|
||||||
|
state,
|
||||||
|
TypeHelper.toLoggableString( state, subclassPersister.getPropertyTypes(), factory ),
|
||||||
|
subclass,
|
||||||
|
version
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -38,4 +38,5 @@ public class BlobType extends AbstractSingleColumnStandardBasicType<Blob> {
|
||||||
protected Blob getReplacement(Blob original, Blob target, SharedSessionContractImplementor session) {
|
protected Blob getReplacement(Blob original, Blob target, SharedSessionContractImplementor session) {
|
||||||
return session.getJdbcServices().getJdbcEnvironment().getDialect().getLobMergeStrategy().mergeBlob( original, target, session );
|
return session.getJdbcServices().getJdbcEnvironment().getDialect().getLobMergeStrategy().mergeBlob( original, target, session );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import java.io.Serializable;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
|
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
|
||||||
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl;
|
import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl;
|
||||||
import org.hibernate.tuple.NonIdentifierAttribute;
|
import org.hibernate.tuple.NonIdentifierAttribute;
|
||||||
|
@ -360,4 +361,18 @@ public class TypeHelper {
|
||||||
return trimmed;
|
return trimmed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String toLoggableString(
|
||||||
|
Object[] state,
|
||||||
|
Type[] types,
|
||||||
|
SessionFactoryImplementor factory) {
|
||||||
|
final StringBuilder buff = new StringBuilder();
|
||||||
|
for ( int i = 0; i < state.length; i++ ) {
|
||||||
|
if ( i > 0 ) {
|
||||||
|
buff.append( ", " );
|
||||||
|
}
|
||||||
|
buff.append( types[i].toLoggableString( state[i], factory ) );
|
||||||
|
}
|
||||||
|
return buff.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,11 @@ public class BlobTypeDescriptor extends AbstractTypeDescriptor<Blob> {
|
||||||
super( Blob.class, BlobMutabilityPlan.INSTANCE );
|
super( Blob.class, BlobMutabilityPlan.INSTANCE );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String extractLoggableRepresentation(Blob value) {
|
||||||
|
return value == null ? "null" : "BLOB{...}";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString(Blob value) {
|
public String toString(Blob value) {
|
||||||
final byte[] bytes;
|
final byte[] bytes;
|
||||||
|
|
|
@ -55,6 +55,11 @@ public class ClobTypeDescriptor extends AbstractTypeDescriptor<Clob> {
|
||||||
super( Clob.class, ClobMutabilityPlan.INSTANCE );
|
super( Clob.class, ClobMutabilityPlan.INSTANCE );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String extractLoggableRepresentation(Clob value) {
|
||||||
|
return value == null ? "null" : "CLOB{...}";
|
||||||
|
}
|
||||||
|
|
||||||
public String toString(Clob value) {
|
public String toString(Clob value) {
|
||||||
return DataHelper.extractString( value );
|
return DataHelper.extractString( value );
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,11 @@ public class NClobTypeDescriptor extends AbstractTypeDescriptor<NClob> {
|
||||||
super( NClob.class, NClobMutabilityPlan.INSTANCE );
|
super( NClob.class, NClobMutabilityPlan.INSTANCE );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String extractLoggableRepresentation(NClob value) {
|
||||||
|
return value == null ? "null" : "NCLOB{...}";
|
||||||
|
}
|
||||||
|
|
||||||
public String toString(NClob value) {
|
public String toString(NClob value) {
|
||||||
return DataHelper.extractString( value );
|
return DataHelper.extractString( value );
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue