Environment: Spring boot 3.1.x, Hibernate 6.2.x
Our JPA repository implementations are like this:
@Transactional
public interface MyEntityRepository extends JpaRepository<MyEntity, String> {
List<MyEntity> findAllByIntegrationId(String integrationId);
}
The entity class:
@Entity
@Table(name = "......")
public class MyEntity {
private String integrationId;
......
public String getIntegrationId() {
return integrationId;
}
public void setIntegrationId(String integrationId) {
this.integrationId = integrationId;
}
}
or
@Repository
public interface MyTaskRepository extends JpaRepository<MyTask, String> {
MyTask findFirstByIntegrationIdOrderByStartedDesc(String integrationId);
}
- There is no issue when calling such JPA repository method in single thread.
- There is no issue when calling such method in multiple threads if the method has already been executed before.
- But it fails for such call in multiple threads, if: such JPA repository call has never been called before; and multiple threads executing the call at the same time.
- So far we observed the failure in hibernate versions '6.2.6.Final' and '6.2.7.Final'.
- It does not fail in these hibernate versions: '6.2.2.Final' and '6.2.8.Final'.
Does anyone know a hibernate JPA 6.2.x issue like this which was fixed in '6.2.8.Final'? We want get confirmation that it's truly fixed in the latest hibernate JPA, not just accidentally hidden and might show up later.
- Here is the exception stacktrace:
java.util.ConcurrentModificationException: null
- at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1013)
- at java.base/java.util.ArrayList$Itr.next(ArrayList.java:967)
- at org.hibernate.sql.ast.spi.AbstractSqlAstTranslator.visitAnsiCaseSearchedExpression(AbstractSqlAstTranslator.java:6433)
- at org.hibernate.sql.ast.spi.AbstractSqlAstTranslator.visitCaseSearchedExpression(AbstractSqlAstTranslator.java:6424)
- at org.hibernate.sql.ast.spi.AbstractSqlAstTranslator.visitCaseSearchedExpression(AbstractSqlAstTranslator.java:6416)
- at org.hibernate.sql.ast.tree.expression.CaseSearchedExpression.accept(CaseSearchedExpression.java:99)
- at org.hibernate.metamodel.mapping.internal.CaseStatementDiscriminatorMappingImpl$CaseStatementDiscriminatorExpression.renderToSql(CaseStatementDiscriminatorMappingImpl.java:278)
- at org.hibernate.sql.ast.spi.AbstractSqlAstTranslator.visitSelfRenderingExpression(AbstractSqlAstTranslator.java:6657)
- at org.hibernate.sql.ast.tree.expression.SelfRenderingExpression.accept(SelfRenderingExpression.java:20)
- at org.hibernate.dialect.PostgreSQLSqlAstTranslator.renderExpressionAsClauseItem(PostgreSQLSqlAstTranslator.java:64)
- at org.hibernate.sql.ast.spi.AbstractSqlAstTranslator.renderSelectExpression(AbstractSqlAstTranslator.java:5020)
- at org.hibernate.sql.ast.spi.AbstractSqlAstTranslator.visitSqlSelectExpression(AbstractSqlAstTranslator.java:5015)
- at org.hibernate.sql.ast.spi.AbstractSqlAstTranslator.visitSqlSelection(AbstractSqlAstTranslator.java:4997)
- at org.hibernate.sql.ast.spi.AbstractSqlAstTranslator.visitSqlSelections(AbstractSqlAstTranslator.java:4662)
- at org.hibernate.sql.ast.spi.AbstractSqlAstTranslator.visitSelectClause(AbstractSqlAstTranslator.java:4563)
- at org.hibernate.sql.ast.spi.AbstractSqlAstTranslator.visitQuerySpec(AbstractSqlAstTranslator.java:3031)
- at org.hibernate.dialect.PostgreSQLSqlAstTranslator.visitQuerySpec(PostgreSQLSqlAstTranslator.java:186)
- at org.hibernate.sql.ast.tree.select.QuerySpec.accept(QuerySpec.java:119)
- at org.hibernate.sql.ast.spi.AbstractSqlAstTranslator.visitSelectStatement(AbstractSqlAstTranslator.java:986)
- at org.hibernate.sql.ast.spi.AbstractSqlAstTranslator.translateSelect(AbstractSqlAstTranslator.java:849)
- at org.hibernate.sql.ast.spi.AbstractSqlAstTranslator.translate(AbstractSqlAstTranslator.java:799)
- at org.hibernate.loader.ast.internal.CollectionLoaderSingleKey.load(CollectionLoaderSingleKey.java:106)
- at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:680)
- at org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:75)
- at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:127)
- at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:1702)
- at org.hibernate.collection.spi.AbstractPersistentCollection.lambda$initialize$3(AbstractPersistentCollection.java:617)
- at org.hibernate.collection.spi.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:265)
- at org.hibernate.collection.spi.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:615)
- at org.hibernate.collection.spi.AbstractPersistentCollection.forceInitialization(AbstractPersistentCollection.java:813)
- at org.hibernate.engine.internal.StatefulPersistenceContext.initializeNonLazyCollections(StatefulPersistenceContext.java:985)
- at org.hibernate.engine.internal.StatefulPersistenceContext.initializeNonLazyCollections(StatefulPersistenceContext.java:971)
- at org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:227)
- at org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:33)
- at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.doExecuteQuery(JdbcSelectExecutorStandardImpl.java:361)
- at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.executeQuery(JdbcSelectExecutorStandardImpl.java:168)
- at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.list(JdbcSelectExecutorStandardImpl.java:93)
- at org.hibernate.sql.exec.spi.JdbcSelectExecutor.list(JdbcSelectExecutor.java:31)
- at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.lambda$new$0(ConcreteSqmSelectQueryPlan.java:110)
- at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.withCacheableSqmInterpretation(ConcreteSqmSelectQueryPlan.java:303)
- at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.performList(ConcreteSqmSelectQueryPlan.java:244)
- at org.hibernate.query.sqm.internal.QuerySqmImpl.doList(QuerySqmImpl.java:518)
- at org.hibernate.query.spi.AbstractSelectionQuery.list(AbstractSelectionQuery.java:367)
- at org.hibernate.query.Query.getResultList(Query.java:119)
- at org.springframework.data.jpa.repository.query.JpaQueryExecution$CollectionExecution.doExecute(JpaQueryExecution.java:129)
- at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:92)
- at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:148)
- at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:136)
- at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:136)
- at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:120)
- at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:164)
- at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:143)
- at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
- at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:72)
- at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
- at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123)
- at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:391)
- at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
- at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
- at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)
- at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
- at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:135)
- at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
- at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
- at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
- at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:244)
- at jdk.proxy2/jdk.proxy2.$Proxy205.findAllByIntegrationId(Unknown Source)
Summery: Call JPA repository method concurrently the first time and fail.