HHH-17073 Auto flush broken when using sequence generator ID
This commit is contained in:
parent
7a4523a470
commit
fe77bcfee9
|
@ -38,6 +38,7 @@ import org.hibernate.engine.jdbc.LobCreator;
|
||||||
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
|
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
|
||||||
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
||||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||||
|
import org.hibernate.event.spi.AutoFlushEvent;
|
||||||
import org.hibernate.event.spi.EventManager;
|
import org.hibernate.event.spi.EventManager;
|
||||||
import org.hibernate.event.spi.DeleteContext;
|
import org.hibernate.event.spi.DeleteContext;
|
||||||
import org.hibernate.event.spi.EventSource;
|
import org.hibernate.event.spi.EventSource;
|
||||||
|
@ -397,6 +398,17 @@ public class SessionDelegatorBaseImpl implements SessionImplementor {
|
||||||
return delegate.autoFlushIfRequired( querySpaces );
|
return delegate.autoFlushIfRequired( querySpaces );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean autoFlushIfRequired(Set<String> querySpaces, boolean skipPreFlush)
|
||||||
|
throws HibernateException {
|
||||||
|
return delegate.autoFlushIfRequired( querySpaces, skipPreFlush );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void autoPreFlush() {
|
||||||
|
delegate.autoPreFlush();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterOperation(boolean success) {
|
public void afterOperation(boolean success) {
|
||||||
delegate.afterOperation( success );
|
delegate.afterOperation( success );
|
||||||
|
|
|
@ -18,6 +18,7 @@ import org.hibernate.HibernateException;
|
||||||
import org.hibernate.Interceptor;
|
import org.hibernate.Interceptor;
|
||||||
import org.hibernate.StatelessSession;
|
import org.hibernate.StatelessSession;
|
||||||
import org.hibernate.boot.spi.SessionFactoryOptions;
|
import org.hibernate.boot.spi.SessionFactoryOptions;
|
||||||
|
import org.hibernate.event.spi.AutoFlushEvent;
|
||||||
import org.hibernate.event.spi.EventSource;
|
import org.hibernate.event.spi.EventSource;
|
||||||
import org.hibernate.graph.GraphSemantic;
|
import org.hibernate.graph.GraphSemantic;
|
||||||
import org.hibernate.query.Query;
|
import org.hibernate.query.Query;
|
||||||
|
@ -537,6 +538,14 @@ public interface SharedSessionContractImplementor
|
||||||
*/
|
*/
|
||||||
boolean autoFlushIfRequired(Set<String> querySpaces) throws HibernateException;
|
boolean autoFlushIfRequired(Set<String> querySpaces) throws HibernateException;
|
||||||
|
|
||||||
|
default boolean autoFlushIfRequired(Set<String> querySpaces, boolean skipPreFlush)
|
||||||
|
throws HibernateException {
|
||||||
|
return autoFlushIfRequired( querySpaces );
|
||||||
|
}
|
||||||
|
|
||||||
|
default void autoPreFlush(){
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Are we currently enforcing a {@linkplain GraphSemantic#FETCH fetch graph}?
|
* Are we currently enforcing a {@linkplain GraphSemantic#FETCH fetch graph}?
|
||||||
*
|
*
|
||||||
|
|
|
@ -26,6 +26,7 @@ import org.hibernate.engine.jdbc.LobCreator;
|
||||||
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
|
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
|
||||||
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
||||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||||
|
import org.hibernate.event.spi.AutoFlushEvent;
|
||||||
import org.hibernate.event.spi.EventManager;
|
import org.hibernate.event.spi.EventManager;
|
||||||
import org.hibernate.graph.RootGraph;
|
import org.hibernate.graph.RootGraph;
|
||||||
import org.hibernate.jdbc.ReturningWork;
|
import org.hibernate.jdbc.ReturningWork;
|
||||||
|
@ -558,6 +559,17 @@ public class SharedSessionDelegatorBaseImpl implements SharedSessionContractImpl
|
||||||
return delegate.autoFlushIfRequired( querySpaces );
|
return delegate.autoFlushIfRequired( querySpaces );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean autoFlushIfRequired(Set<String> querySpaces, boolean skipPreFlush)
|
||||||
|
throws HibernateException {
|
||||||
|
return delegate.autoFlushIfRequired( querySpaces, skipPreFlush );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void autoPreFlush() {
|
||||||
|
delegate.autoPreFlush();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterOperation(boolean success) {
|
public void afterOperation(boolean success) {
|
||||||
delegate.afterOperation( success );
|
delegate.afterOperation( success );
|
||||||
|
|
|
@ -74,6 +74,29 @@ public abstract class AbstractFlushingEventListener implements JpaBootstrapSensi
|
||||||
final EventSource session = event.getSession();
|
final EventSource session = event.getSession();
|
||||||
|
|
||||||
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
|
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
|
||||||
|
preFlush( session, persistenceContext );
|
||||||
|
|
||||||
|
flushEverythingToExecutions( event, persistenceContext, session );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void flushEverythingToExecutions(FlushEvent event, PersistenceContext persistenceContext, EventSource session) {
|
||||||
|
persistenceContext.setFlushing( true );
|
||||||
|
try {
|
||||||
|
int entityCount = flushEntities( event, persistenceContext );
|
||||||
|
int collectionCount = flushCollections( session, persistenceContext );
|
||||||
|
|
||||||
|
event.setNumberOfEntitiesProcessed( entityCount );
|
||||||
|
event.setNumberOfCollectionsProcessed( collectionCount );
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
persistenceContext.setFlushing( false);
|
||||||
|
}
|
||||||
|
|
||||||
|
//some statistics
|
||||||
|
logFlushResults( event );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void preFlush(EventSource session, PersistenceContext persistenceContext) {
|
||||||
session.getInterceptor().preFlush( persistenceContext.managedEntitiesIterator() );
|
session.getInterceptor().preFlush( persistenceContext.managedEntitiesIterator() );
|
||||||
|
|
||||||
prepareEntityFlushes( session, persistenceContext );
|
prepareEntityFlushes( session, persistenceContext );
|
||||||
|
@ -84,21 +107,6 @@ public abstract class AbstractFlushingEventListener implements JpaBootstrapSensi
|
||||||
// now, any collections that are initialized
|
// now, any collections that are initialized
|
||||||
// inside this block do not get updated - they
|
// inside this block do not get updated - they
|
||||||
// are ignored until the next flush
|
// are ignored until the next flush
|
||||||
|
|
||||||
persistenceContext.setFlushing( true );
|
|
||||||
try {
|
|
||||||
int entityCount = flushEntities( event, persistenceContext );
|
|
||||||
int collectionCount = flushCollections( session, persistenceContext );
|
|
||||||
|
|
||||||
event.setNumberOfEntitiesProcessed( entityCount );
|
|
||||||
event.setNumberOfCollectionsProcessed( collectionCount );
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
persistenceContext.setFlushing(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
//some statistics
|
|
||||||
logFlushResults( event );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void logFlushResults(FlushEvent event) {
|
protected void logFlushResults(FlushEvent event) {
|
||||||
|
|
|
@ -48,8 +48,13 @@ public class DefaultAutoFlushEventListener extends AbstractFlushingEventListener
|
||||||
// Need to get the number of collection removals before flushing to executions
|
// Need to get the number of collection removals before flushing to executions
|
||||||
// (because flushing to executions can add collection removal actions to the action queue).
|
// (because flushing to executions can add collection removal actions to the action queue).
|
||||||
final ActionQueue actionQueue = source.getActionQueue();
|
final ActionQueue actionQueue = source.getActionQueue();
|
||||||
|
final EventSource session = event.getSession();
|
||||||
|
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
|
||||||
|
if ( !event.isSkipPreFlush() ) {
|
||||||
|
preFlush( session, persistenceContext );
|
||||||
|
}
|
||||||
final int oldSize = actionQueue.numberOfCollectionRemovals();
|
final int oldSize = actionQueue.numberOfCollectionRemovals();
|
||||||
flushEverythingToExecutions( event );
|
flushEverythingToExecutions( event, persistenceContext, session );
|
||||||
if ( flushIsReallyNeeded( event, source ) ) {
|
if ( flushIsReallyNeeded( event, source ) ) {
|
||||||
LOG.trace( "Need to execute flush" );
|
LOG.trace( "Need to execute flush" );
|
||||||
event.setFlushRequired( true );
|
event.setFlushRequired( true );
|
||||||
|
@ -87,6 +92,13 @@ public class DefaultAutoFlushEventListener extends AbstractFlushingEventListener
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAutoPreFlush(EventSource source) {
|
||||||
|
if ( flushMightBeNeeded( source ) ) {
|
||||||
|
preFlush( source, source.getPersistenceContextInternal() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean flushIsReallyNeeded(AutoFlushEvent event, final EventSource source) {
|
private boolean flushIsReallyNeeded(AutoFlushEvent event, final EventSource source) {
|
||||||
return source.getHibernateFlushMode() == FlushMode.ALWAYS
|
return source.getHibernateFlushMode() == FlushMode.ALWAYS
|
||||||
|| source.getActionQueue().areTablesToBeUpdated( event.getQuerySpaces() );
|
|| source.getActionQueue().areTablesToBeUpdated( event.getQuerySpaces() );
|
||||||
|
|
|
@ -16,10 +16,16 @@ public class AutoFlushEvent extends FlushEvent {
|
||||||
|
|
||||||
private Set<String> querySpaces;
|
private Set<String> querySpaces;
|
||||||
private boolean flushRequired;
|
private boolean flushRequired;
|
||||||
|
private boolean skipPreFlush;
|
||||||
|
|
||||||
public AutoFlushEvent(Set<String> querySpaces, EventSource source) {
|
public AutoFlushEvent(Set<String> querySpaces, EventSource source) {
|
||||||
super(source);
|
this( querySpaces, false, source );
|
||||||
|
}
|
||||||
|
|
||||||
|
public AutoFlushEvent(Set<String> querySpaces, boolean skipPreFlush, EventSource source) {
|
||||||
|
super( source );
|
||||||
this.querySpaces = querySpaces;
|
this.querySpaces = querySpaces;
|
||||||
|
this.skipPreFlush = skipPreFlush;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<String> getQuerySpaces() {
|
public Set<String> getQuerySpaces() {
|
||||||
|
@ -37,4 +43,8 @@ public class AutoFlushEvent extends FlushEvent {
|
||||||
public void setFlushRequired(boolean dirty) {
|
public void setFlushRequired(boolean dirty) {
|
||||||
this.flushRequired = dirty;
|
this.flushRequired = dirty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isSkipPreFlush() {
|
||||||
|
return skipPreFlush;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
package org.hibernate.event.spi;
|
package org.hibernate.event.spi;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.SharedSessionContract;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the contract for handling of session auto-flush events.
|
* Defines the contract for handling of session auto-flush events.
|
||||||
|
@ -20,4 +21,7 @@ public interface AutoFlushEventListener {
|
||||||
* @param event The auto-flush event to be handled.
|
* @param event The auto-flush event to be handled.
|
||||||
*/
|
*/
|
||||||
void onAutoFlush(AutoFlushEvent event) throws HibernateException;
|
void onAutoFlush(AutoFlushEvent event) throws HibernateException;
|
||||||
|
|
||||||
|
default void onAutoPreFlush(EventSource source) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1359,17 +1359,36 @@ public class SessionImpl
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean autoFlushIfRequired(Set<String> querySpaces) throws HibernateException {
|
public boolean autoFlushIfRequired(Set<String> querySpaces) throws HibernateException {
|
||||||
|
return autoFlushIfRequired( querySpaces, false );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean autoFlushIfRequired(Set<String> querySpaces, boolean skipPreFlush)
|
||||||
|
throws HibernateException {
|
||||||
checkOpen();
|
checkOpen();
|
||||||
if ( !isTransactionInProgress() ) {
|
if ( !isTransactionInProgress() ) {
|
||||||
// do not auto-flush while outside a transaction
|
// do not auto-flush while outside a transaction
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
AutoFlushEvent event = new AutoFlushEvent( querySpaces, this );
|
AutoFlushEvent event = new AutoFlushEvent( querySpaces, skipPreFlush, this );
|
||||||
fastSessionServices.eventListenerGroup_AUTO_FLUSH
|
fastSessionServices.eventListenerGroup_AUTO_FLUSH
|
||||||
.fireEventOnEachListener( event, AutoFlushEventListener::onAutoFlush );
|
.fireEventOnEachListener( event, AutoFlushEventListener::onAutoFlush );
|
||||||
return event.isFlushRequired();
|
return event.isFlushRequired();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void autoPreFlush(){
|
||||||
|
checkOpen();
|
||||||
|
if ( !isTransactionInProgress() ) {
|
||||||
|
// do not auto-flush while outside a transaction
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fastSessionServices.eventListenerGroup_AUTO_FLUSH
|
||||||
|
.fireEventOnEachListener( this, AutoFlushEventListener::onAutoPreFlush );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isDirty() throws HibernateException {
|
public boolean isDirty() throws HibernateException {
|
||||||
checkOpen();
|
checkOpen();
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||||
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
||||||
import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper;
|
import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper;
|
||||||
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
|
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
|
||||||
|
import org.hibernate.event.spi.AutoFlushEvent;
|
||||||
import org.hibernate.generator.BeforeExecutionGenerator;
|
import org.hibernate.generator.BeforeExecutionGenerator;
|
||||||
import org.hibernate.generator.Generator;
|
import org.hibernate.generator.Generator;
|
||||||
import org.hibernate.generator.values.GeneratedValues;
|
import org.hibernate.generator.values.GeneratedValues;
|
||||||
|
|
|
@ -12,12 +12,14 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import jakarta.persistence.Tuple;
|
import jakarta.persistence.Tuple;
|
||||||
|
|
||||||
import org.hibernate.InstantiationException;
|
import org.hibernate.InstantiationException;
|
||||||
import org.hibernate.ScrollMode;
|
import org.hibernate.ScrollMode;
|
||||||
import org.hibernate.engine.spi.EntityHolder;
|
import org.hibernate.engine.spi.EntityHolder;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.engine.spi.SubselectFetch;
|
import org.hibernate.engine.spi.SubselectFetch;
|
||||||
|
import org.hibernate.event.spi.AutoFlushEvent;
|
||||||
import org.hibernate.internal.EmptyScrollableResults;
|
import org.hibernate.internal.EmptyScrollableResults;
|
||||||
import org.hibernate.metamodel.mapping.MappingModelExpressible;
|
import org.hibernate.metamodel.mapping.MappingModelExpressible;
|
||||||
import org.hibernate.query.Query;
|
import org.hibernate.query.Query;
|
||||||
|
@ -105,7 +107,7 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
|
||||||
JdbcParametersList.empty(),
|
JdbcParametersList.empty(),
|
||||||
jdbcParameterBindings
|
jdbcParameterBindings
|
||||||
);
|
);
|
||||||
|
session.autoFlushIfRequired( jdbcSelect.getAffectedTableNames(), true );
|
||||||
return session.getFactory().getJdbcServices().getJdbcSelectExecutor().executeQuery(
|
return session.getFactory().getJdbcServices().getJdbcSelectExecutor().executeQuery(
|
||||||
jdbcSelect,
|
jdbcSelect,
|
||||||
jdbcParameterBindings,
|
jdbcParameterBindings,
|
||||||
|
@ -133,8 +135,7 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
|
||||||
JdbcParametersList.empty(),
|
JdbcParametersList.empty(),
|
||||||
jdbcParameterBindings
|
jdbcParameterBindings
|
||||||
);
|
);
|
||||||
|
session.autoFlushIfRequired( jdbcSelect.getAffectedTableNames(), true );
|
||||||
session.autoFlushIfRequired( jdbcSelect.getAffectedTableNames() );
|
|
||||||
return session.getFactory().getJdbcServices().getJdbcSelectExecutor().list(
|
return session.getFactory().getJdbcServices().getJdbcSelectExecutor().list(
|
||||||
jdbcSelect,
|
jdbcSelect,
|
||||||
jdbcParameterBindings,
|
jdbcParameterBindings,
|
||||||
|
@ -162,7 +163,7 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
|
||||||
final JdbcSelectExecutor jdbcSelectExecutor = session.getFactory()
|
final JdbcSelectExecutor jdbcSelectExecutor = session.getFactory()
|
||||||
.getJdbcServices()
|
.getJdbcServices()
|
||||||
.getJdbcSelectExecutor();
|
.getJdbcSelectExecutor();
|
||||||
session.autoFlushIfRequired( jdbcSelect.getAffectedTableNames() );
|
session.autoFlushIfRequired( jdbcSelect.getAffectedTableNames(), true );
|
||||||
return jdbcSelectExecutor.scroll(
|
return jdbcSelectExecutor.scroll(
|
||||||
jdbcSelect,
|
jdbcSelect,
|
||||||
scrollMode,
|
scrollMode,
|
||||||
|
@ -204,7 +205,7 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
|
||||||
return selections.size() == 1 ? selections.get( 0 ) : null;
|
return selections.size() == 1 ? selections.get( 0 ) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Map<Class<?>,Class<?>> WRAPPERS
|
private static final Map<Class<?>, Class<?>> WRAPPERS
|
||||||
= Map.of(
|
= Map.of(
|
||||||
boolean.class, Boolean.class,
|
boolean.class, Boolean.class,
|
||||||
int.class, Integer.class,
|
int.class, Integer.class,
|
||||||
|
@ -318,6 +319,8 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
|
||||||
CacheableSqmInterpretation localCopy = cacheableSqmInterpretation;
|
CacheableSqmInterpretation localCopy = cacheableSqmInterpretation;
|
||||||
JdbcParameterBindings jdbcParameterBindings = null;
|
JdbcParameterBindings jdbcParameterBindings = null;
|
||||||
|
|
||||||
|
executionContext.getSession().autoPreFlush();
|
||||||
|
|
||||||
if ( localCopy == null ) {
|
if ( localCopy == null ) {
|
||||||
synchronized ( this ) {
|
synchronized ( this ) {
|
||||||
localCopy = cacheableSqmInterpretation;
|
localCopy = cacheableSqmInterpretation;
|
||||||
|
|
Loading…
Reference in New Issue