I'm trying to understand how a "get" method (findXByYAndZAnd...) on a Repository (org.springframework.data.repository.CrudRepository) fails with an ORA-00001 "unique constraint () violated".
Obviously the insert was generated from another (previous) statement, however, I do not understand what's the role of Spring AOP and the CrudMethodMetadataPostProcessor, why the transaction is committed in the middle of it. We do have
dbConfig:
...
hikari:
auto-commit: true
And
spring:
application:
name: xxx
cache:
type: caffeine
jpa:
database: oracle
properties:
hibernate:
jdbc:
batch_size: 200
# order_inserts: true
# order_updates: true
# show_sql: true
use_sql_comments: false
format_sql: false
But still... it should either do the transaction immediately, or at the end, isn't it?
ERROR 42664956 --- [task-10] c.e.my-app.service.error.DbLoggerService : Error saving messages : org.hibernate.exception.ConstraintViolationException: could not execute batch; nested exception is javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute batch
RootCause:
ORA-00001: unique constraint (SIDE.PK_RMESG) violated
Stack Trace:
org.springframework.orm.jpa.JpaSystemException: org.hibernate.exception.ConstraintViolationException: could not execute batch; nested exception is javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute batch
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:408) ~[spring-orm-5.2.9.RELEASE.jar!/:5.2.9.RELEASE]
at org.springframework.orm.jpa.DefaultJpaDialect.translateExceptionIfPossible(DefaultJpaDialect.java:128) ~[spring-orm-5.2.9.RELEASE.jar!/:5.2.9.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:528) ~[spring-orm-5.2.9.RELEASE.jar!/:5.2.9.RELEASE]
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61) ~[spring-tx-5.2.9.RELEASE.jar!/:5.2.9.RELEASE]
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242) ~[spring-tx-5.2.9.RELEASE.jar!/:5.2.9.RELEASE]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:154) ~[spring-tx-5.2.9.RELEASE.jar!/:5.2.9.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.9.RELEASE.jar!/:5.2.9.RELEASE]
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:149) ~[spring-data-jpa-2.3.4.RELEASE.jar!/:2.3.4.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.9.RELEASE.jar!/:5.2.9.RELEASE]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95) ~[spring-aop-5.2.9.RELEASE.jar!/:5.2.9.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.9.RELEASE.jar!/:5.2.9.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.2.9.RELEASE.jar!/:5.2.9.RELEASE]
at com.sun.proxy.$Proxy162.getInstanceByxAndYAndZ(Unknown Source) ~[na:na]
at com.my-org.my-app.my-component.service.impl.PartServiceImpl.process(PartServiceImpl.java:287) ~[loader-1.0.0-SNAPSHOT.jar!/:1.0.0-SNAPSHOT]
Thanks!
CodePudding user response:
I don't see any sign that a transaction was committed. Since you don't share any code we can only guess but what is probably going on is the following:
You made some changes to some managed entities.
This might be by calling save
with an entity, or by modifying an entity that you loaded in the same transaction.
These changes don't get flushed to the database immediately, but are delayed as long as possible.
You then perform or trigger some kind of query. This by default configuration of JPA triggers a flush of the changes and therefore the exception.
CrudMethodMetadataPostProcessor.CrudMethodMetadataPopulatingMethodInterceptor
doesn't seem to be relevant here. It just gathers some information about the method invoked and then proceeds to the actual implementation (or next aspect) of the method invoked. You can see the invoke
method here: https://github.com/spring-projects/spring-data-jpa/blob/b57eb85a230d3a05e45276052ef62b1249e5a0e6/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/CrudMethodMetadataPostProcessor.java#L128
As for AOP it is just a mechanic used for get things like CrudMethodMetadataPostProcessor
or transaction management and even the implementation of repository methods themselves to be executed.
Apart from being crucial for Spring Data itself (remember repositories are just interfaces without normal implementation) it is not really affecting the JPA behaviour described above.