HHH-952 : subqueries with joins using DetatchedCriteria

git-svn-id: https://svn.jboss.org/repos/hibernate/core/branches/Branch_3_2@14209 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Gail Badner 2007-11-29 01:36:04 +00:00
parent 012bf08a0d
commit dbfcafa8bf
28 changed files with 499 additions and 182 deletions

View File

@ -21,7 +21,11 @@ public final class CollectionRecreateAction extends CollectionAction {
}
public void execute() throws HibernateException {
final PersistentCollection collection = getCollection();
final boolean stats = getSession().getFactory().getStatistics().isStatisticsEnabled();
long startTime = 0;
if ( stats ) startTime = System.currentTimeMillis();
final PersistentCollection collection = getCollection();
getPersister().recreate( collection, getKey(), getSession() );
@ -31,9 +35,9 @@ public final class CollectionRecreateAction extends CollectionAction {
evict();
if ( getSession().getFactory().getStatistics().isStatisticsEnabled() ) {
if ( stats ) {
getSession().getFactory().getStatisticsImplementor()
.recreateCollection( getPersister().getRole() );
.recreateCollection( getPersister().getRole(), System.currentTimeMillis() - startTime);
}
}

View File

@ -25,7 +25,11 @@ public final class CollectionRemoveAction extends CollectionAction {
}
public void execute() throws HibernateException {
if ( !emptySnapshot ) getPersister().remove( getKey(), getSession() );
final boolean stats = getSession().getFactory().getStatistics().isStatisticsEnabled();
long startTime = 0;
if ( stats ) startTime = System.currentTimeMillis();
if ( !emptySnapshot ) getPersister().remove( getKey(), getSession() );
final PersistentCollection collection = getCollection();
if (collection!=null) {
@ -36,9 +40,9 @@ public final class CollectionRemoveAction extends CollectionAction {
evict();
if ( getSession().getFactory().getStatistics().isStatisticsEnabled() ) {
if ( stats ) {
getSession().getFactory().getStatisticsImplementor()
.removeCollection( getPersister().getRole() );
.removeCollection( getPersister().getRole(), System.currentTimeMillis() - startTime);
}
}

View File

@ -32,6 +32,9 @@ public final class CollectionUpdateAction extends CollectionAction {
final CollectionPersister persister = getPersister();
final PersistentCollection collection = getCollection();
boolean affectedByFilters = persister.isAffectedByEnabledFilters(session);
final boolean stats = session.getFactory().getStatistics().isStatisticsEnabled();
long startTime = 0;
if ( stats ) startTime = System.currentTimeMillis();
if ( !collection.wasInitialized() ) {
if ( !collection.hasQueuedOperations() ) throw new AssertionFailure( "no queued adds" );
@ -62,9 +65,9 @@ public final class CollectionUpdateAction extends CollectionAction {
evict();
if ( getSession().getFactory().getStatistics().isStatisticsEnabled() ) {
if ( stats ) {
getSession().getFactory().getStatisticsImplementor().
updateCollection( getPersister().getRole() );
updateCollection( getPersister().getRole(), System.currentTimeMillis() - startTime);
}
}

View File

@ -44,6 +44,9 @@ public final class EntityDeleteAction extends EntityAction {
EntityPersister persister = getPersister();
SessionImplementor session = getSession();
Object instance = getInstance();
final boolean stats = session.getFactory().getStatistics().isStatisticsEnabled();
long startTime = 0;
if ( stats ) startTime = System.currentTimeMillis();
boolean veto = preDelete();
@ -93,9 +96,9 @@ public final class EntityDeleteAction extends EntityAction {
postDelete();
if ( getSession().getFactory().getStatistics().isStatisticsEnabled() && !veto ) {
if ( stats && !veto ) {
getSession().getFactory().getStatisticsImplementor()
.deleteEntity( getPersister().getEntityName() );
.deleteEntity( getPersister().getEntityName(), System.currentTimeMillis() - startTime);
}
}

View File

@ -38,7 +38,10 @@ public final class EntityIdentityInsertAction extends EntityAction {
final EntityPersister persister = getPersister();
final SessionImplementor session = getSession();
final Object instance = getInstance();
final boolean stats = session.getFactory().getStatistics().isStatisticsEnabled();
long startTime = 0;
if ( stats ) startTime = System.currentTimeMillis();
boolean veto = preInsert();
// Don't need to lock the cache here, since if someone
@ -65,9 +68,9 @@ public final class EntityIdentityInsertAction extends EntityAction {
postInsert();
if ( session.getFactory().getStatistics().isStatisticsEnabled() && !veto ) {
if ( stats && !veto ) {
session.getFactory().getStatisticsImplementor()
.insertEntity( getPersister().getEntityName() );
.insertEntity( getPersister().getEntityName(), System.currentTimeMillis() - startTime);
}
}

View File

@ -46,6 +46,10 @@ public final class EntityInsertAction extends EntityAction {
Object instance = getInstance();
Serializable id = getId();
final boolean stats = session.getFactory().getStatistics().isStatisticsEnabled();
long startTime = 0;
if ( stats ) startTime = System.currentTimeMillis();
boolean veto = preInsert();
// Don't need to lock the cache here, since if someone
@ -96,7 +100,7 @@ public final class EntityInsertAction extends EntityAction {
// boolean put = persister.getCache().insert(ck, cacheEntry);
boolean put = persister.getCache().insert( ck, cacheEntry, version );
if ( put && factory.getStatistics().isStatisticsEnabled() ) {
if ( put && stats ) {
factory.getStatisticsImplementor()
.secondLevelCachePut( getPersister().getCache().getRegionName() );
}
@ -105,9 +109,9 @@ public final class EntityInsertAction extends EntityAction {
postInsert();
if ( factory.getStatistics().isStatisticsEnabled() && !veto ) {
if ( stats && !veto ) {
factory.getStatisticsImplementor()
.insertEntity( getPersister().getEntityName() );
.insertEntity( getPersister().getEntityName(), System.currentTimeMillis() - startTime);
}
}

View File

@ -65,7 +65,11 @@ public final class EntityUpdateAction extends EntityAction {
boolean veto = preUpdate();
final SessionFactoryImplementor factory = getSession().getFactory();
Object previousVersion = this.previousVersion;
final boolean stats = factory.getStatistics().isStatisticsEnabled();
long startTime = 0;
if ( stats ) startTime = System.currentTimeMillis();
Object previousVersion = this.previousVersion;
if ( persister.isVersionPropertyGenerated() ) {
// we need to grab the version value from the entity, otherwise
// we have issues with generated-version entities that may have
@ -158,9 +162,9 @@ public final class EntityUpdateAction extends EntityAction {
postUpdate();
if ( factory.getStatistics().isStatisticsEnabled() && !veto ) {
if ( stats && !veto ) {
factory.getStatisticsImplementor()
.updateEntity( getPersister().getEntityName() );
.updateEntity( getPersister().getEntityName(), System.currentTimeMillis() - startTime);
}
}

View File

@ -1997,7 +1997,7 @@ public final class HbmBinder {
Iterator iter = subnode.elementIterator( "param" );
while ( iter.hasNext() ) {
Element childNode = (Element) iter.next();
params.setProperty( childNode.attributeValue( "name" ), childNode.getText() );
params.setProperty( childNode.attributeValue( "name" ), childNode.getTextTrim() );
}
model.setIdentifierGeneratorProperties( params );

View File

@ -1,17 +1,18 @@
//$Id$
package org.hibernate.criterion;
import java.util.HashMap;
import org.hibernate.Criteria;
import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.engine.QueryParameters;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.TypedValue;
import org.hibernate.impl.CriteriaImpl;
import org.hibernate.loader.criteria.CriteriaJoinWalker;
import org.hibernate.loader.criteria.CriteriaQueryTranslator;
import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.sql.Select;
import org.hibernate.type.Type;
/**
@ -24,7 +25,8 @@ public abstract class SubqueryExpression implements Criterion {
private String op;
private QueryParameters params;
private Type[] types;
private CriteriaQueryTranslator innerQuery;
protected Type[] getTypes() {
return types;
}
@ -39,34 +41,23 @@ public abstract class SubqueryExpression implements Criterion {
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
final SessionImplementor session = ( (CriteriaImpl) criteria ).getSession(); //ugly!
final SessionFactoryImplementor factory = session.getFactory();
final SessionFactoryImplementor factory = criteriaQuery.getFactory();
final OuterJoinLoadable persister = (OuterJoinLoadable) factory.getEntityPersister( criteriaImpl.getEntityOrClassName() );
CriteriaQueryTranslator innerQuery = new CriteriaQueryTranslator(
factory,
criteriaImpl,
criteriaImpl.getEntityOrClassName(), //implicit polymorphism not supported (would need a union)
criteriaQuery.generateSQLAlias(),
criteriaQuery
);
params = innerQuery.getQueryParameters(); //TODO: bad lifecycle....
types = innerQuery.getProjectedTypes();
//String filter = persister.filterFragment( innerQuery.getRootSQLALias(), session.getEnabledFilters() );
String sql = new Select( factory.getDialect() )
.setWhereClause( innerQuery.getWhereCondition() )
.setGroupByClause( innerQuery.getGroupBy() )
.setSelectClause( innerQuery.getSelect() )
.setFromClause(
persister.fromTableFragment( innerQuery.getRootSQLALias() ) +
persister.fromJoinFragment( innerQuery.getRootSQLALias(), true, false )
)
.toStatementString();
createAndSetInnerQuery( criteriaQuery, factory );
CriteriaJoinWalker walker = new CriteriaJoinWalker(
persister,
innerQuery,
factory,
criteriaImpl,
criteriaImpl.getEntityOrClassName(),
new HashMap(),
innerQuery.getRootSQLALias());
String sql = walker.getSQLString();
final StringBuffer buf = new StringBuffer()
.append( toLeftSqlString(criteria, criteriaQuery) );
if (op!=null) buf.append(' ').append(op).append(' ');
@ -77,13 +68,49 @@ public abstract class SubqueryExpression implements Criterion {
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException {
Type[] types = params.getPositionalParameterTypes();
Object[] values = params.getPositionalParameterValues();
TypedValue[] tv = new TypedValue[types.length];
for ( int i=0; i<types.length; i++ ) {
tv[i] = new TypedValue( types[i], values[i], EntityMode.POJO );
//the following two lines were added to ensure that this.params is not null, which
//can happen with two-deep nested subqueries
SessionFactoryImplementor factory = criteriaQuery.getFactory();
createAndSetInnerQuery(criteriaQuery, factory);
Type[] ppTypes = params.getPositionalParameterTypes();
Object[] ppValues = params.getPositionalParameterValues();
TypedValue[] tv = new TypedValue[ppTypes.length];
for ( int i=0; i<ppTypes.length; i++ ) {
tv[i] = new TypedValue( ppTypes[i], ppValues[i], EntityMode.POJO );
}
return tv;
}
/**
* Creates the inner query used to extract some useful information about
* types, since it is needed in both methods.
* @param criteriaQuery
* @param factory
*/
private void createAndSetInnerQuery(CriteriaQuery criteriaQuery, final SessionFactoryImplementor factory) {
if ( innerQuery == null ) {
//with two-deep subqueries, the same alias would get generated for
//both using the old method (criteriaQuery.generateSQLAlias()), so
//that is now used as a fallback if the main criteria alias isn't set
String alias;
if ( this.criteriaImpl.getAlias() == null ) {
alias = criteriaQuery.generateSQLAlias();
}
else {
alias = this.criteriaImpl.getAlias() + "_";
}
innerQuery = new CriteriaQueryTranslator(
factory,
criteriaImpl,
criteriaImpl.getEntityOrClassName(), //implicit polymorphism not supported (would need a union)
alias,
criteriaQuery
);
params = innerQuery.getQueryParameters();
types = innerQuery.getProjectedTypes();
}
}
}

View File

@ -357,10 +357,6 @@ public class DB2Dialect extends Dialect {
return false;
}
public String getCurrentTimestampSQLFunctionName() {
return "sysdate";
}
// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public boolean supportsEmptyInList() {

View File

@ -121,7 +121,7 @@ public class Oracle8iDialect extends Dialect {
registerFunction( "current_time", new NoArgSQLFunction("current_timestamp", Hibernate.TIME, false) );
registerFunction( "current_timestamp", new NoArgSQLFunction("current_timestamp", Hibernate.TIMESTAMP, false) );
registerFunction( "lastday", new StandardSQLFunction("lastday", Hibernate.DATE) );
registerFunction( "last_day", new StandardSQLFunction("last_day", Hibernate.DATE) );
registerFunction( "sysdate", new NoArgSQLFunction("sysdate", Hibernate.DATE, false) );
registerFunction( "systimestamp", new NoArgSQLFunction("systimestamp", Hibernate.TIMESTAMP, false) );
registerFunction( "uid", new NoArgSQLFunction("uid", Hibernate.INTEGER, false) );

View File

@ -103,7 +103,7 @@ public class Oracle9Dialect extends Dialect {
registerFunction( "current_time", new NoArgSQLFunction("current_timestamp", Hibernate.TIME, false) );
registerFunction( "current_timestamp", new NoArgSQLFunction("current_timestamp", Hibernate.TIMESTAMP, false) );
registerFunction( "lastday", new StandardSQLFunction("lastday", Hibernate.DATE) );
registerFunction( "last_day", new StandardSQLFunction("last_day", Hibernate.DATE) );
registerFunction( "sysdate", new NoArgSQLFunction("sysdate", Hibernate.DATE, false) );
registerFunction( "systimestamp", new NoArgSQLFunction("systimestamp", Hibernate.TIMESTAMP, false) );
registerFunction( "uid", new NoArgSQLFunction("uid", Hibernate.INTEGER, false) );

View File

@ -93,7 +93,11 @@ public final class TwoPhaseLoad {
final PostLoadEvent postLoadEvent) throws HibernateException {
//TODO: Should this be an InitializeEntityEventListener??? (watch out for performance!)
final SessionFactoryImplementor factory = session.getFactory();
final boolean stats = factory.getStatistics().isStatisticsEnabled();
long startTime = 0;
if ( stats ) startTime = System.currentTimeMillis();
final PersistenceContext persistenceContext = session.getPersistenceContext();
EntityEntry entityEntry = persistenceContext.getEntry(entity);
if ( entityEntry == null ) {
@ -128,7 +132,6 @@ public final class TwoPhaseLoad {
persister.setPropertyValues( entity, hydratedState, session.getEntityMode() );
final SessionFactoryImplementor factory = session.getFactory();
if ( persister.hasCache() && session.getCacheMode().isPutEnabled() ) {
if ( log.isDebugEnabled() )
@ -208,8 +211,8 @@ public final class TwoPhaseLoad {
MessageHelper.infoString( persister, id, session.getFactory() )
);
if ( factory.getStatistics().isStatisticsEnabled() ) {
factory.getStatisticsImplementor().loadEntity( persister.getEntityName() );
if ( stats) {
factory.getStatisticsImplementor().loadEntity( persister.getEntityName(), System.currentTimeMillis() - startTime);
}
}

View File

@ -233,6 +233,9 @@ public class CollectionLoadContext {
}
final SessionImplementor session = getLoadContext().getPersistenceContext().getSession();
final EntityMode em = session.getEntityMode();
final boolean stats = session.getFactory().getStatistics().isStatisticsEnabled();
long startTime = 0;
if ( stats ) startTime = System.currentTimeMillis();
boolean hasNoQueuedAdds = lce.getCollection().endRead(); // warning: can cause a recursive calls! (proxy initialization)
@ -260,8 +263,8 @@ public class CollectionLoadContext {
log.debug( "collection fully initialized: " + MessageHelper.collectionInfoString(persister, lce.getKey(), session.getFactory() ) );
}
if ( session.getFactory().getStatistics().isStatisticsEnabled() ) {
session.getFactory().getStatisticsImplementor().loadCollection( persister.getRole() );
if ( stats ) {
session.getFactory().getStatisticsImplementor().loadCollection( persister.getRole(), System.currentTimeMillis() - startTime);
}
}

View File

@ -33,6 +33,9 @@ public class DefaultInitializeCollectionEventListener implements InitializeColle
PersistentCollection collection = event.getCollection();
SessionImplementor source = event.getSession();
final boolean stats = source.getFactory().getStatistics().isStatisticsEnabled();
long startTime = 0;
if ( stats ) startTime = System.currentTimeMillis();
CollectionEntry ce = source.getPersistenceContext().getCollectionEntry(collection);
if (ce==null) throw new HibernateException("collection was evicted");
@ -60,10 +63,10 @@ public class DefaultInitializeCollectionEventListener implements InitializeColle
ce.getLoadedPersister().initialize( ce.getLoadedKey(), source );
log.trace("collection initialized");
if ( source.getFactory().getStatistics().isStatisticsEnabled() ) {
if ( stats ) {
source.getFactory().getStatisticsImplementor().fetchCollection(
ce.getLoadedPersister().getRole()
);
ce.getLoadedPersister().getRole(),
System.currentTimeMillis() - startTime);
}
}
}

View File

@ -392,15 +392,19 @@ public class DefaultLoadEventListener extends AbstractLockUpgradeEventListener i
final EntityKey keyToLoad,
final LoadEventListener.LoadType options) throws HibernateException {
final SessionImplementor source = event.getSession();
Object entity = persister.load(
final boolean stats = source.getFactory().getStatistics().isStatisticsEnabled();
long startTime = 0;
if ( stats ) startTime = System.currentTimeMillis();
Object entity = persister.load(
event.getEntityId(),
event.getInstanceToLoad(),
event.getLockMode(),
source
);
if ( event.isAssociationFetch() && source.getFactory().getStatistics().isStatisticsEnabled() ) {
source.getFactory().getStatisticsImplementor().fetchEntity( event.getEntityClassName() );
if ( event.isAssociationFetch() && stats) {
source.getFactory().getStatisticsImplementor().fetchEntity( event.getEntityClassName(), System.currentTimeMillis() - startTime);
}
return entity;

View File

@ -336,7 +336,8 @@ public class DotNode extends FromReferenceNode implements DisplayableNode, Selec
joinIsNeeded = generateJoin && !isReferenceToPrimaryKey( parentAsDotNode.propertyName, entityType );
}
else if ( ! getWalker().isSelectStatement() ) {
joinIsNeeded = false;
// in non-select queries, the only time we should need to join is if we are in a subquery from clause
joinIsNeeded = getWalker().getCurrentStatementType() == SqlTokenTypes.SELECT && getWalker().isInFrom();
}
else if ( REGRESSION_STYLE_JOIN_SUPPRESSION ) {
// this is the regression style determination which matches the logic of the classic translator

View File

@ -120,7 +120,7 @@ public class OptimizerFactory {
}
}
public Serializable generate(AccessCallback callback) {
public synchronized Serializable generate(AccessCallback callback) {
if ( lastSourceValue < 0 ) {
lastSourceValue = callback.getNextValue();
while ( lastSourceValue <= 0 ) {
@ -168,7 +168,7 @@ public class OptimizerFactory {
}
}
public Serializable generate(AccessCallback callback) {
public synchronized Serializable generate(AccessCallback callback) {
if ( hiValue < 0 ) {
value = callback.getNextValue();
if ( value < 1 ) {

View File

@ -314,4 +314,14 @@ public class StatisticsService implements StatisticsServiceMBean {
public String getQueryExecutionMaxTimeQueryString() {
return stats.getQueryExecutionMaxTimeQueryString();
}
public void setOperationThreshold(long threshold) {
stats.setOperationThreshold(threshold);
}
public long getOperationThreshold() {
return stats.getOperationThreshold();
}
}

View File

@ -26,12 +26,16 @@ import org.hibernate.util.CollectionHelper;
public abstract class AbstractEntityJoinWalker extends JoinWalker {
private final OuterJoinLoadable persister;
private String alias;
private final String alias;
public AbstractEntityJoinWalker(OuterJoinLoadable persister, SessionFactoryImplementor factory, Map enabledFilters) {
this( persister, factory, enabledFilters, null );
}
public AbstractEntityJoinWalker(OuterJoinLoadable persister, SessionFactoryImplementor factory, Map enabledFilters, String alias) {
super( factory, enabledFilters );
this.persister = persister;
alias = generateRootAlias( persister.getEntityName() );
this.alias = ( alias == null ) ? generateRootAlias( persister.getEntityName() ) : alias;
}
protected final void initAll(
@ -39,9 +43,7 @@ public abstract class AbstractEntityJoinWalker extends JoinWalker {
final String orderByString,
final LockMode lockMode)
throws MappingException {
walkEntityTree( persister, getAlias() );
List allAssociations = new ArrayList();
allAssociations.addAll(associations);
allAssociations.add( new OuterJoinableAssociation(

View File

@ -8,7 +8,6 @@ import java.util.Set;
import org.hibernate.Criteria;
import org.hibernate.FetchMode;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.MappingException;
import org.hibernate.engine.CascadeStyle;
@ -18,7 +17,6 @@ import org.hibernate.loader.AbstractEntityJoinWalker;
import org.hibernate.persister.entity.Joinable;
import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.sql.JoinFragment;
import org.hibernate.type.AssociationType;
import org.hibernate.type.Type;
import org.hibernate.type.TypeFactory;
@ -57,9 +55,19 @@ public class CriteriaJoinWalker extends AbstractEntityJoinWalker {
final SessionFactoryImplementor factory,
final CriteriaImpl criteria,
final String rootEntityName,
final Map enabledFilters)
throws HibernateException {
super(persister, factory, enabledFilters);
final Map enabledFilters) {
this(persister, translator, factory, criteria, rootEntityName, enabledFilters, null);
}
public CriteriaJoinWalker(
final OuterJoinLoadable persister,
final CriteriaQueryTranslator translator,
final SessionFactoryImplementor factory,
final CriteriaImpl criteria,
final String rootEntityName,
final Map enabledFilters,
final String alias) {
super(persister, factory, enabledFilters, alias);
this.translator = translator;

View File

@ -208,4 +208,17 @@ public interface Statistics {
* that occurred
*/
public long getOptimisticFailureCount();
/**
* Set the operationThreshold to a value greater than zero to enable logging of long running operations.
* @param threshold (milliseconds)
*/
public void setOperationThreshold(long threshold);
/**
*
* @return Operationthreshold, if greater than zero, operations that exceed the level will be logged.
*/
public long getOperationThreshold();
}

View File

@ -46,8 +46,11 @@ public class StatisticsImpl implements Statistics, StatisticsImplementor {
private long secondLevelCacheHitCount;
private long secondLevelCacheMissCount;
private long secondLevelCachePutCount;
private long queryExecutionCount;
private long operationThreshold = 0; // log operations that take longer than this value (in milliseconds)
// We don't log anything if operationThreshold == 0
private long queryExecutionCount;
private long queryExecutionMaxTime;
private String queryExecutionMaxTimeQueryString;
private long queryCacheHitCount;
@ -68,7 +71,20 @@ public class StatisticsImpl implements Statistics, StatisticsImplementor {
/** entity statistics per query string (HQL or SQL) */
private final Map queryStatistics = new HashMap();
public StatisticsImpl() {
static final String OPERATION_LOAD = "load ";
static final String OPERATION_FETCH = "fetch ";
static final String OPERATION_UPDATE = "update ";
static final String OPERATION_INSERT = "insert ";
static final String OPERATION_DELETE = "delete ";
static final String OPERATION_LOADCOLLECTION = "loadCollection ";
static final String OPERATION_FETCHCOLLECTION = "fetchCollection ";
static final String OPERATION_UPDATECOLLECTION = "updateCollection ";
static final String OPERATION_RECREATECOLLECTION = "recreateCollection ";
static final String OPERATION_REMOVECOLLECTION = "removeCollection ";
static final String OPERATION_EXECUTEQUERY = "executeQuery ";
static final String OPERATION_ENDTRANSACTION = "endTransaction ";
public StatisticsImpl() {
clear();
}
@ -140,16 +156,43 @@ public class StatisticsImpl implements Statistics, StatisticsImplementor {
public synchronized void connect() {
connectCount++;
}
public synchronized void loadEntity(String entityName) {
entityLoadCount++;
getEntityStatistics(entityName).loadCount++;
}
public synchronized void fetchEntity(String entityName) {
entityFetchCount++;
getEntityStatistics(entityName).fetchCount++;
}
public synchronized void setOperationThreshold(long threshold) {
operationThreshold = threshold;
}
public synchronized long getOperationThreshold() {
return operationThreshold;
}
private void logOperation(String operation, String entityName, long time) {
if(entityName != null)
log.info(operation+entityName + " " + time + "ms");
else
log.info(operation); // just log that the event occurred
}
public void loadEntity(String entityName, long time) {
synchronized(this) {
entityLoadCount++;
getEntityStatistics(entityName).loadCount++;
}
if(operationThreshold > 0 && operationThreshold < time) {
logOperation(OPERATION_LOAD,entityName, time);
}
}
public void fetchEntity(String entityName, long time) {
synchronized(this) {
entityFetchCount++;
getEntityStatistics(entityName).fetchCount++;
}
if(operationThreshold > 0 && operationThreshold < time) {
logOperation(OPERATION_FETCH,entityName, time);
}
}
/**
* find entity statistics per name
@ -165,26 +208,41 @@ public class StatisticsImpl implements Statistics, StatisticsImplementor {
}
return es;
}
public synchronized void updateEntity(String entityName) {
entityUpdateCount++;
EntityStatistics es = getEntityStatistics(entityName);
es.updateCount++;
}
public synchronized void insertEntity(String entityName) {
entityInsertCount++;
EntityStatistics es = getEntityStatistics(entityName);
es.insertCount++;
}
public void updateEntity(String entityName, long time) {
synchronized(this) {
entityUpdateCount++;
EntityStatistics es = getEntityStatistics(entityName);
es.updateCount++;
}
if(operationThreshold > 0 && operationThreshold < time) {
logOperation(OPERATION_UPDATE,entityName, time);
}
}
public synchronized void deleteEntity(String entityName) {
entityDeleteCount++;
EntityStatistics es = getEntityStatistics(entityName);
es.deleteCount++;
}
public void insertEntity(String entityName, long time) {
synchronized(this) {
entityInsertCount++;
EntityStatistics es = getEntityStatistics(entityName);
es.insertCount++;
}
if(operationThreshold > 0 && operationThreshold < time) {
logOperation(OPERATION_INSERT,entityName, time);
}
}
/**
public void deleteEntity(String entityName, long time) {
synchronized(this) {
entityDeleteCount++;
EntityStatistics es = getEntityStatistics(entityName);
es.deleteCount++;
}
if(operationThreshold > 0 && operationThreshold < time) {
logOperation(OPERATION_DELETE,entityName, time);
}
}
/**
* Get collection statistics per role
*
* @param role collection role
@ -199,30 +257,55 @@ public class StatisticsImpl implements Statistics, StatisticsImplementor {
return cs;
}
public synchronized void loadCollection(String role) {
collectionLoadCount++;
getCollectionStatistics(role).loadCount++;
}
public void loadCollection(String role, long time) {
synchronized(this) {
collectionLoadCount++;
getCollectionStatistics(role).loadCount++;
}
if(operationThreshold > 0 && operationThreshold < time) {
logOperation(OPERATION_LOADCOLLECTION,role, time);
}
}
public synchronized void fetchCollection(String role) {
collectionFetchCount++;
getCollectionStatistics(role).fetchCount++;
}
public void fetchCollection(String role, long time) {
synchronized(this) {
collectionFetchCount++;
getCollectionStatistics(role).fetchCount++;
}
if(operationThreshold > 0 && operationThreshold < time) {
logOperation(OPERATION_FETCHCOLLECTION,role, time);
}
}
public synchronized void updateCollection(String role) {
collectionUpdateCount++;
getCollectionStatistics(role).updateCount++;
}
public void updateCollection(String role, long time) {
synchronized(this) {
collectionUpdateCount++;
getCollectionStatistics(role).updateCount++;
}
if(operationThreshold > 0 && operationThreshold < time) {
logOperation(OPERATION_UPDATECOLLECTION,role, time);
}
}
public synchronized void recreateCollection(String role) {
collectionRecreateCount++;
getCollectionStatistics(role).recreateCount++;
}
public void recreateCollection(String role, long time) {
synchronized(this) {
collectionRecreateCount++;
getCollectionStatistics(role).recreateCount++;
}
if(operationThreshold > 0 && operationThreshold < time) {
logOperation(OPERATION_RECREATECOLLECTION,role, time);
}
}
public synchronized void removeCollection(String role) {
collectionRemoveCount++;
getCollectionStatistics(role).removeCount++;
}
public void removeCollection(String role, long time) {
synchronized(this) {
collectionRemoveCount++;
getCollectionStatistics(role).removeCount++;
}
if(operationThreshold > 0 && operationThreshold < time) {
logOperation(OPERATION_REMOVECOLLECTION,role, time);
}
}
/**
* Second level cache statistics per region
@ -257,17 +340,23 @@ public class StatisticsImpl implements Statistics, StatisticsImplementor {
getSecondLevelCacheStatistics(regionName).missCount++;
}
public synchronized void queryExecuted(String hql, int rows, long time) {
queryExecutionCount++;
if (queryExecutionMaxTime<time) {
queryExecutionMaxTime=time;
queryExecutionMaxTimeQueryString = hql;
}
if (hql!=null) {
QueryStatistics qs = getQueryStatistics(hql);
qs.executed(rows, time);
}
}
public void queryExecuted(String hql, int rows, long time) {
synchronized(this) {
queryExecutionCount++;
if (queryExecutionMaxTime<time) {
queryExecutionMaxTime=time;
queryExecutionMaxTimeQueryString = hql;
}
if (hql!=null) {
QueryStatistics qs = getQueryStatistics(hql);
qs.executed(rows, time);
}
}
if(operationThreshold > 0 && operationThreshold < time) {
logOperation(OPERATION_EXECUTEQUERY,hql, time);
}
}
public synchronized void queryCacheHit(String hql, String regionName) {
queryCacheHitCount++;
@ -556,10 +645,17 @@ public class StatisticsImpl implements Statistics, StatisticsImplementor {
}
}
public void endTransaction(boolean success) {
transactionCount++;
if (success) commitedTransactionCount++;
}
public void endTransaction(boolean success) {
synchronized(this) {
transactionCount++;
if (success) commitedTransactionCount++;
}
// The end transaction message can get too verbose (output log fills up with just end tx messages)
//if(operationThreshold > 0) { // show endTransaction operations if we are logging operations that exceed a threshold.
// logOperation(OPERATION_ENDTRANSACTION,null, 0);
//}
}
public long getSuccessfulTransactionCount() {
return commitedTransactionCount;

View File

@ -11,16 +11,16 @@ public interface StatisticsImplementor {
public void closeSession();
public void flush();
public void connect();
public void loadEntity(String entityName);
public void fetchEntity(String entityName);
public void updateEntity(String entityName);
public void insertEntity(String entityName);
public void deleteEntity(String entityName);
public void loadCollection(String role);
public void fetchCollection(String role);
public void updateCollection(String role);
public void recreateCollection(String role);
public void removeCollection(String role);
public void loadEntity(String entityName, long time);
public void fetchEntity(String entityName, long time);
public void updateEntity(String entityName, long time);
public void insertEntity(String entityName, long time);
public void deleteEntity(String entityName, long time);
public void loadCollection(String role, long time);
public void fetchCollection(String role, long time);
public void updateCollection(String role, long time);
public void recreateCollection(String role, long time);
public void removeCollection(String role, long time);
public void secondLevelCachePut(String regionName);
public void secondLevelCacheHit(String regionName);
public void secondLevelCacheMiss(String regionName);

View File

@ -16,7 +16,6 @@ import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projection;
@ -154,8 +153,8 @@ public class CriteriaQueryTest extends FunctionalTestCase {
.list();
session.createCriteria(Student.class)
.add( Property.forName("name").eqAll(dc) )
.list();
.add( Property.forName("name").eqAll(dc) )
.list();
session.createCriteria(Student.class)
.add( Subqueries.in("Gavin King", dc) )
@ -169,8 +168,7 @@ public class CriteriaQueryTest extends FunctionalTestCase {
.add( Subqueries.eq("Gavin King", dc2) )
.list();
//TODO: join in subselect: HHH-952
/*DetachedCriteria dc3 = DetachedCriteria.forClass(Student.class, "st")
DetachedCriteria dc3 = DetachedCriteria.forClass(Student.class, "st")
.createCriteria("enrolments")
.createCriteria("course")
.add( Property.forName("description").eq("Hibernate Training") )
@ -178,7 +176,7 @@ public class CriteriaQueryTest extends FunctionalTestCase {
session.createCriteria(Enrolment.class, "e")
.add( Subqueries.eq("Gavin King", dc3) )
.list();*/
.list();
session.delete(enrolment2);
session.delete(gavin);
@ -398,8 +396,8 @@ public class CriteriaQueryTest extends FunctionalTestCase {
.add( Projections.property("studentNumber"), "stNumber" )
.add( Projections.property("courseCode"), "cCode" ) )
)
.add( Expression.gt( "studentNumber", new Long(665) ) )
.add( Expression.lt( "studentNumber", new Long(668) ) )
.add( Restrictions.gt( "studentNumber", new Long(665) ) )
.add( Restrictions.lt( "studentNumber", new Long(668) ) )
.addOrder( Order.asc("stNumber") )
.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP)
.list();

View File

@ -10,7 +10,9 @@ import junit.framework.Test;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;
import org.hibernate.junit.functional.FunctionalTestCase;
import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
@ -171,6 +173,82 @@ public class DiscriminatorTest extends FunctionalTestCase {
s.close();
}
public void testLoadSuperclassProxyPolymorphicAccess() {
Session s = openSession();
s.beginTransaction();
Employee e = new Employee();
e.setName( "Steve" );
e.setSex( 'M' );
e.setTitle( "grand poobah" );
s.save( e );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
// load the superclass proxy.
Person pLoad = ( Person ) s.load( Person.class, new Long( e.getId() ) );
assertTrue( pLoad instanceof HibernateProxy);
Person pGet = ( Person ) s.get( Person.class, new Long( e.getId() ));
Person pQuery = ( Person ) s.createQuery( "from Person where id = :id" )
.setLong( "id", e.getId() )
.uniqueResult();
Person pCriteria = ( Person ) s.createCriteria( Person.class )
.add( Restrictions.idEq( new Long( e.getId() ) ) )
.uniqueResult();
// assert that executing the queries polymorphically returns the same proxy
assertSame( pLoad, pGet );
assertSame( pLoad, pQuery );
assertSame( pLoad, pCriteria );
// assert that the proxy is not an instance of Employee
assertFalse( pLoad instanceof Employee );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
s.delete( e );
s.getTransaction().commit();
s.close();
}
public void testLoadSuperclassProxyEvictPolymorphicAccess() {
Session s = openSession();
s.beginTransaction();
Employee e = new Employee();
e.setName( "Steve" );
e.setSex( 'M' );
e.setTitle( "grand poobah" );
s.save( e );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
// load the superclass proxy.
Person pLoad = ( Person ) s.load( Person.class, new Long( e.getId() ) );
assertTrue( pLoad instanceof HibernateProxy);
// evict the proxy
s.evict( pLoad );
Employee pGet = ( Employee ) s.get( Person.class, new Long( e.getId() ));
Employee pQuery = ( Employee ) s.createQuery( "from Person where id = :id" )
.setLong( "id", e.getId() )
.uniqueResult();
Employee pCriteria = ( Employee ) s.createCriteria( Person.class )
.add( Restrictions.idEq( new Long( e.getId() ) ) )
.uniqueResult();
// assert that executing the queries polymorphically returns the same Employee instance
assertSame( pGet, pQuery );
assertSame( pGet, pCriteria );
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
s.delete( e );
s.getTransaction().commit();
s.close();
}
}

View File

@ -451,6 +451,17 @@ public class BulkManipulationTest extends FunctionalTestCase {
s.close();
}
public void testInsertWithSelectListUsingJoins() {
// this is just checking parsing and syntax...
Session s = openSession();
s.beginTransaction();
s.createQuery( "insert into Animal (description, bodyWeight) select h.description, h.bodyWeight from Human h where h.mother.mother is not null" ).executeUpdate();
s.createQuery( "delete from Animal" ).executeUpdate();
s.getTransaction().commit();
s.close();
}
// UPDATES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public void testIncorrectSyntax() {

View File

@ -8,11 +8,12 @@ import java.util.List;
import junit.framework.Test;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.NonUniqueObjectException;
import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
import org.hibernate.Session;
import org.hibernate.StaleObjectStateException;
import org.hibernate.Transaction;
import org.hibernate.criterion.Projections;
import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
/**
* @author Gavin King
@ -27,6 +28,39 @@ public class MergeTest extends AbstractOperationTestCase {
return new FunctionalTestClassTestSuite( MergeTest.class );
}
public void testMergeStaleVersionFails() throws Exception {
Session s = openSession();
s.beginTransaction();
VersionedEntity entity = new VersionedEntity( "entity", "entity" );
s.persist( entity );
s.getTransaction().commit();
s.close();
// make the detached 'entity' reference stale...
s = openSession();
s.beginTransaction();
VersionedEntity entity2 = ( VersionedEntity ) s.get( VersionedEntity.class, entity.getId() );
entity2.setName( "entity-name" );
s.getTransaction().commit();
s.close();
// now try to reattch it
s = openSession();
s.beginTransaction();
try {
s.merge( entity );
s.getTransaction().commit();
fail( "was expecting staleness error" );
}
catch ( StaleObjectStateException expected ) {
// expected outcome...
}
finally {
s.getTransaction().rollback();
s.close();
}
}
public void testMergeBidiPrimayKeyOneToOne() throws Exception {
Session s = openSession();
s.beginTransaction();
@ -121,7 +155,7 @@ public class MergeTest extends AbstractOperationTestCase {
assertInsertCount( 0 );
///////////////////////////////////////////////////////////////////////
cleanup();
// cleanup();
}
public void testNoExtraUpdatesOnMergeWithCollection() throws Exception {
@ -162,7 +196,7 @@ public class MergeTest extends AbstractOperationTestCase {
assertInsertCount( 1 );
///////////////////////////////////////////////////////////////////////
cleanup();
// cleanup();
}
public void testNoExtraUpdatesOnMergeVersioned() throws Exception {
@ -201,7 +235,7 @@ public class MergeTest extends AbstractOperationTestCase {
assertInsertCount( 0 );
///////////////////////////////////////////////////////////////////////
cleanup();
// cleanup();
}
public void testNoExtraUpdatesOnMergeVersionedWithCollection() throws Exception {
@ -245,7 +279,7 @@ public class MergeTest extends AbstractOperationTestCase {
assertInsertCount( 1 );
///////////////////////////////////////////////////////////////////////
cleanup();
// cleanup();
}
public void testPersistThenMergeInSameTxnWithVersion() {
@ -267,7 +301,7 @@ public class MergeTest extends AbstractOperationTestCase {
tx.commit();
s.close();
cleanup();
// cleanup();
}
public void testPersistThenMergeInSameTxnWithTimestamp() {
@ -289,7 +323,7 @@ public class MergeTest extends AbstractOperationTestCase {
tx.commit();
s.close();
cleanup();
// cleanup();
}
public void testMergeDeepTree() {
@ -447,7 +481,7 @@ public class MergeTest extends AbstractOperationTestCase {
assertInsertCount(1);
assertUpdateCount(2);
cleanup();
// cleanup();
}
public void testMergeTreeWithGeneratedId() {
@ -482,7 +516,7 @@ public class MergeTest extends AbstractOperationTestCase {
assertInsertCount(1);
assertUpdateCount(2);
cleanup();
// cleanup();
}
public void testMergeManaged() {
@ -524,7 +558,7 @@ public class MergeTest extends AbstractOperationTestCase {
s.close();
cleanup();
// cleanup();
}
public void testRecursiveMergeTransient() {
@ -544,7 +578,7 @@ public class MergeTest extends AbstractOperationTestCase {
tx.commit();
s.close();
cleanup();
// cleanup();
}
public void testDeleteAndMerge() throws Exception {
@ -567,7 +601,7 @@ public class MergeTest extends AbstractOperationTestCase {
s.getTransaction().commit();
s.close();
cleanup();
// cleanup();
}
public void testMergeManyToManyWithCollectionDeference() throws Exception {
@ -610,11 +644,16 @@ public class MergeTest extends AbstractOperationTestCase {
tx.commit();
s.close();
// cleanup();
}
protected void cleanupTest() throws Exception {
cleanup();
super.cleanupTest();
}
private void cleanup() {
Session s = openSession();
Session s = sfi().openSession();
s.beginTransaction();
s.createQuery( "delete from NumberedNode where parent is not null" ).executeUpdate();
s.createQuery( "delete from NumberedNode" ).executeUpdate();