Skip to content

Commit

Permalink
HHH-11958 Make EntityManager.find() support QueryHints.HINT_READONLY
Browse files Browse the repository at this point in the history
  • Loading branch information
NathanQingyangXu authored and sebersole committed Jan 6, 2020
1 parent 49fe4f6 commit 00e9db2
Show file tree
Hide file tree
Showing 20 changed files with 289 additions and 49 deletions.
Expand Up @@ -52,12 +52,19 @@ public class LoadQueryInfluencers implements Serializable {

private final EffectiveEntityGraph effectiveEntityGraph = new EffectiveEntityGraph();

private Boolean readOnly;

public LoadQueryInfluencers() {
this( null );
this( null, null );
}

public LoadQueryInfluencers(SessionFactoryImplementor sessionFactory) {
this(sessionFactory, null);
}

public LoadQueryInfluencers(SessionFactoryImplementor sessionFactory, Boolean readOnly) {
this.sessionFactory = sessionFactory;
this.readOnly = readOnly;
}

public SessionFactoryImplementor getSessionFactory() {
Expand Down Expand Up @@ -282,4 +289,11 @@ public void setLoadGraph(final EntityGraph loadGraph) {
effectiveEntityGraph.applyGraph( (RootGraphImplementor<?>) loadGraph, GraphSemantic.LOAD );
}

public Boolean getReadOnly() {
return readOnly;
}

public void setReadOnly(Boolean readOnly) {
this.readOnly = readOnly;
}
}
Expand Up @@ -570,7 +570,8 @@ protected Object loadFromDatasource(
event.getEntityId(),
event.getInstanceToLoad(),
event.getLockOptions(),
event.getSession()
event.getSession(),
event.getReadOnly()
);

final StatisticsImplementor statistics = event.getSession().getFactory().getStatistics();
Expand Down
36 changes: 24 additions & 12 deletions hibernate-core/src/main/java/org/hibernate/event/spi/LoadEvent.java
Expand Up @@ -46,23 +46,24 @@ public LockOptions setScope(boolean scope) {
private boolean isAssociationFetch;
private Object result;
private PostLoadEvent postLoadEvent;
private Boolean readOnly;

public LoadEvent(Serializable entityId, Object instanceToLoad, EventSource source) {
this( entityId, null, instanceToLoad, DEFAULT_LOCK_OPTIONS, false, source );
public LoadEvent(Serializable entityId, Object instanceToLoad, EventSource source, Boolean readOnly) {
this( entityId, null, instanceToLoad, DEFAULT_LOCK_OPTIONS, false, source, readOnly );
}

public LoadEvent(Serializable entityId, String entityClassName, LockMode lockMode, EventSource source) {
this( entityId, entityClassName, null, lockMode, false, source );
public LoadEvent(Serializable entityId, String entityClassName, LockMode lockMode, EventSource source, Boolean readOnly) {
this( entityId, entityClassName, null, lockMode, false, source, readOnly );
}

public LoadEvent(Serializable entityId, String entityClassName, LockOptions lockOptions, EventSource source) {
this( entityId, entityClassName, null, lockOptions, false, source );
public LoadEvent(Serializable entityId, String entityClassName, LockOptions lockOptions, EventSource source, Boolean readOnly) {
this( entityId, entityClassName, null, lockOptions, false, source, readOnly );
}

public LoadEvent(Serializable entityId, String entityClassName, boolean isAssociationFetch, EventSource source) {
this( entityId, entityClassName, null, DEFAULT_LOCK_OPTIONS, isAssociationFetch, source );
public LoadEvent(Serializable entityId, String entityClassName, boolean isAssociationFetch, EventSource source, Boolean readOnly) {
this( entityId, entityClassName, null, DEFAULT_LOCK_OPTIONS, isAssociationFetch, source, readOnly );
}

public boolean isAssociationFetch() {
return isAssociationFetch;
}
Expand All @@ -73,10 +74,11 @@ private LoadEvent(
Object instanceToLoad,
LockMode lockMode,
boolean isAssociationFetch,
EventSource source) {
EventSource source,
Boolean readOnly) {
this( entityId, entityClassName, instanceToLoad,
lockMode == DEFAULT_LOCK_MODE ? DEFAULT_LOCK_OPTIONS : new LockOptions().setLockMode( lockMode ),
isAssociationFetch, source );
isAssociationFetch, source, readOnly );
}

private LoadEvent(
Expand All @@ -85,7 +87,8 @@ private LoadEvent(
Object instanceToLoad,
LockOptions lockOptions,
boolean isAssociationFetch,
EventSource source) {
EventSource source,
Boolean readOnly) {

super( source );

Expand All @@ -106,6 +109,7 @@ else if ( lockOptions.getLockMode() == null ) {
this.lockOptions = lockOptions;
this.isAssociationFetch = isAssociationFetch;
this.postLoadEvent = new PostLoadEvent( source );
this.readOnly = readOnly;
}

public Serializable getEntityId() {
Expand Down Expand Up @@ -190,4 +194,12 @@ public PostLoadEvent getPostLoadEvent() {
public void setPostLoadEvent(PostLoadEvent postLoadEvent) {
this.postLoadEvent = postLoadEvent;
}

public Boolean getReadOnly() {
return readOnly;
}

public void setReadOnly(Boolean readOnly) {
this.readOnly = readOnly;
}
}
Expand Up @@ -928,7 +928,7 @@ public void load(Object object, Serializable id) throws HibernateException {
LoadEvent event = loadEvent;
loadEvent = null;
if ( event == null ) {
event = new LoadEvent( id, object, this );
event = new LoadEvent( id, object, this, getReadOnlyFromLoadQueryInfluencers() );
}
else {
event.setEntityClassName( null );
Expand Down Expand Up @@ -1059,7 +1059,7 @@ public final Object internalLoad(
*/
private LoadEvent recycleEventInstance(final LoadEvent event, final Serializable id, final String entityName) {
if ( event == null ) {
return new LoadEvent( id, entityName, true, this );
return new LoadEvent( id, entityName, true, this, getReadOnlyFromLoadQueryInfluencers() );
}
else {
event.setEntityClassName( entityName );
Expand Down Expand Up @@ -2748,12 +2748,12 @@ protected T perform(Supplier<T> executor) {
@SuppressWarnings("unchecked")
protected T doGetReference(Serializable id) {
if ( this.lockOptions != null ) {
LoadEvent event = new LoadEvent( id, entityPersister.getEntityName(), lockOptions, SessionImpl.this );
LoadEvent event = new LoadEvent( id, entityPersister.getEntityName(), lockOptions, SessionImpl.this, getReadOnlyFromLoadQueryInfluencers() );
fireLoad( event, LoadEventListener.LOAD );
return (T) event.getResult();
}

LoadEvent event = new LoadEvent( id, entityPersister.getEntityName(), false, SessionImpl.this );
LoadEvent event = new LoadEvent( id, entityPersister.getEntityName(), false, SessionImpl.this, getReadOnlyFromLoadQueryInfluencers() );
boolean success = false;
try {
fireLoad( event, LoadEventListener.LOAD );
Expand Down Expand Up @@ -2784,12 +2784,12 @@ public Optional<T> loadOptional(Serializable id) {
@SuppressWarnings("unchecked")
protected final T doLoad(Serializable id) {
if ( this.lockOptions != null ) {
LoadEvent event = new LoadEvent( id, entityPersister.getEntityName(), lockOptions, SessionImpl.this );
LoadEvent event = new LoadEvent( id, entityPersister.getEntityName(), lockOptions, SessionImpl.this, getReadOnlyFromLoadQueryInfluencers() );
fireLoad( event, LoadEventListener.GET );
return (T) event.getResult();
}

LoadEvent event = new LoadEvent( id, entityPersister.getEntityName(), false, SessionImpl.this );
LoadEvent event = new LoadEvent( id, entityPersister.getEntityName(), false, SessionImpl.this, getReadOnlyFromLoadQueryInfluencers() );
boolean success = false;
try {
fireLoad( event, LoadEventListener.GET );
Expand Down Expand Up @@ -3311,7 +3311,8 @@ public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode

try {
getLoadQueryInfluencers().getEffectiveEntityGraph().applyConfiguredGraph( properties );

Boolean readOnly = properties == null ? null : (Boolean) properties.get( QueryHints.HINT_READONLY );
getLoadQueryInfluencers().setReadOnly( readOnly );
final IdentifierLoadAccess<T> loadAccess = byId( entityClass );
loadAccess.with( determineAppropriateLocalCacheMode( properties ) );

Expand Down Expand Up @@ -3366,6 +3367,7 @@ public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode
}
finally {
getLoadQueryInfluencers().getEffectiveEntityGraph().clear();
getLoadQueryInfluencers().setReadOnly( null );
}
}

Expand Down Expand Up @@ -3786,4 +3788,12 @@ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFound
( (FilterImpl) loadQueryInfluencers.getEnabledFilter( filterName ) ).afterDeserialize( getFactory() );
}
}

private Boolean getReadOnlyFromLoadQueryInfluencers() {
Boolean readOnly = null;
if ( loadQueryInfluencers != null ) {
readOnly = loadQueryInfluencers.getReadOnly();
}
return readOnly;
}
}
25 changes: 24 additions & 1 deletion hibernate-core/src/main/java/org/hibernate/loader/Loader.java
Expand Up @@ -2389,7 +2389,8 @@ protected final List loadEntity(
final String optionalEntityName,
final Serializable optionalIdentifier,
final EntityPersister persister,
LockOptions lockOptions) throws HibernateException {
final LockOptions lockOptions,
final Boolean readOnly) throws HibernateException {
if ( LOG.isDebugEnabled() ) {
LOG.debugf( "Loading entity: %s", MessageHelper.infoString( persister, id, identifierType, getFactory() ) );
}
Expand All @@ -2403,6 +2404,9 @@ protected final List loadEntity(
qp.setOptionalEntityName( optionalEntityName );
qp.setOptionalId( optionalIdentifier );
qp.setLockOptions( lockOptions );
if ( readOnly != null ) {
qp.setReadOnly( readOnly );
}
result = doQueryAndInitializeNonLazyCollections( session, qp, false );
}
catch (SQLException sqle) {
Expand Down Expand Up @@ -2477,6 +2481,22 @@ public final List loadEntityBatch(
final Serializable optionalId,
final EntityPersister persister,
LockOptions lockOptions) throws HibernateException {
return loadEntityBatch( session, ids, idType, optionalObject, optionalEntityName, optionalId, persister, lockOptions, null );
}

/**
* Called by wrappers that batch load entities
*/
public final List loadEntityBatch(
final SharedSessionContractImplementor session,
final Serializable[] ids,
final Type idType,
final Object optionalObject,
final String optionalEntityName,
final Serializable optionalId,
final EntityPersister persister,
final LockOptions lockOptions,
final Boolean readOnly) throws HibernateException {
if ( LOG.isDebugEnabled() ) {
LOG.debugf( "Batch loading entity: %s", MessageHelper.infoString( persister, ids, getFactory() ) );
}
Expand All @@ -2492,6 +2512,9 @@ public final List loadEntityBatch(
qp.setOptionalEntityName( optionalEntityName );
qp.setOptionalId( optionalId );
qp.setLockOptions( lockOptions );
if ( readOnly != null ) {
qp.setReadOnly( readOnly );
}
result = doQueryAndInitializeNonLazyCollections( session, qp, false );
}
catch (SQLException sqle) {
Expand Down
Expand Up @@ -8,8 +8,6 @@

import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collections;
import java.util.List;

import org.hibernate.HibernateException;
Expand Down Expand Up @@ -46,20 +44,32 @@ public AbstractEntityLoader(
@Override
public Object load(Serializable id, Object optionalObject, SharedSessionContractImplementor session) {
// this form is deprecated!
return load( id, optionalObject, session, LockOptions.NONE );
return load( id, optionalObject, session, LockOptions.NONE, null );
}

@Override
public Object load(Serializable id, Object optionalObject, SharedSessionContractImplementor session, Boolean readOnly) {
// this form is deprecated!
return load( id, optionalObject, session, LockOptions.NONE, readOnly );
}

@Override
public Object load(Serializable id, Object optionalObject, SharedSessionContractImplementor session, LockOptions lockOptions) {
return load( session, id, optionalObject, id, lockOptions );
return load( id, optionalObject, session, lockOptions, null );
}

@Override
public Object load(Serializable id, Object optionalObject, SharedSessionContractImplementor session, LockOptions lockOptions, Boolean readOnly) {
return load( session, id, optionalObject, id, lockOptions, readOnly );
}

protected Object load(
SharedSessionContractImplementor session,
Object id,
Object optionalObject,
Serializable optionalId,
LockOptions lockOptions) {
LockOptions lockOptions,
Boolean readOnly) {

List list = loadEntity(
session,
Expand All @@ -69,7 +79,8 @@ protected Object load(
entityName,
optionalId,
persister,
lockOptions
lockOptions,
readOnly
);

if ( list.size()==1 ) {
Expand Down
Expand Up @@ -11,6 +11,7 @@
import java.util.Arrays;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.LockOptions;
import org.hibernate.engine.internal.BatchFetchQueueHelper;
import org.hibernate.engine.spi.QueryParameters;
Expand Down Expand Up @@ -50,11 +51,27 @@ public Object load(Serializable id, Object optionalObject, SharedSessionContract
return load( id, optionalObject, session, LockOptions.NONE );
}

@Override
public Object load(
Serializable id,
Object optionalObject,
SharedSessionContractImplementor session,
LockOptions lockOptions,
Boolean readOnly) {
return load( id, optionalObject, session, lockOptions, readOnly );
}

@Override
public Object load(Serializable id, Object optionalObject, SharedSessionContractImplementor session, Boolean readOnly) {
return load( id, optionalObject, session, LockOptions.NONE, readOnly );
}

protected QueryParameters buildQueryParameters(
Serializable id,
Serializable[] ids,
Object optionalObject,
LockOptions lockOptions) {
LockOptions lockOptions,
Boolean readOnly) {
Type[] types = new Type[ids.length];
Arrays.fill( types, persister().getIdentifierType() );

Expand All @@ -65,6 +82,9 @@ protected QueryParameters buildQueryParameters(
qp.setOptionalEntityName( persister().getEntityName() );
qp.setOptionalId( id );
qp.setLockOptions( lockOptions );
if ( readOnly != null ) {
qp.setReadOnly( readOnly );
}
return qp;
}

Expand All @@ -88,12 +108,13 @@ protected Object doBatchLoad(
SharedSessionContractImplementor session,
Serializable[] ids,
Object optionalObject,
LockOptions lockOptions) {
LockOptions lockOptions,
Boolean readOnly) {
if ( log.isDebugEnabled() ) {
log.debugf( "Batch loading entity: %s", MessageHelper.infoString( persister, ids, session.getFactory() ) );
}

QueryParameters qp = buildQueryParameters( id, ids, optionalObject, lockOptions );
QueryParameters qp = buildQueryParameters( id, ids, optionalObject, lockOptions, readOnly );

try {
final List results = loaderToUse.doQueryAndInitializeNonLazyCollections( session, qp, false );
Expand Down

0 comments on commit 00e9db2

Please sign in to comment.