我已经Javers配置在我的Java Sping Boot (3.0.4
)应用程序与Postgresql(13.8
),因为几个月,它工作正常。
我的配置详细信息:build.gradle
依赖关系:
...
implementation "org.springframework.boot:spring-boot-starter-data-jpa:3.0.4"
implementation "org.javers:javers-spring-boot-starter-sql:7.0.0-RC3"
...
字符串application.properties
Javers配置:
javers.sqlSchema=schema_a
logging.level.org.javers.core.Javers=ERROR
型
正在我的存储库上使用的注解:
@Repository
@JaversSpringDataAuditable
public interface IMyExampleRepository extends IMyBaseRepository<MyExample, UUID> {}
@NoRepositoryBean
public interface IMyBaseRepository<Entity, ID> extends JpaRepository<Entity, ID>, JpaSpecificationExecutor<Entity> {
}
型
然后,我开始在另一个应用程序模块中使用相同的共享DB,并在新示例中部署了相同的Javers配置。该配置在非prod环境中工作正常。但在我的prod环境中,我最近开始收到JaversException关于重复键约束违反的异常。
这里有一个样本问题:
Exception Cause = JaversException SQL_EXCEPTION: ERROR: duplicate key value violates unique constraint "jv_global_id_pk"
Detail: Key (global_id_pk)=(571901) already exists.
while executing sql: INSERT INTO schema_a.jv_global_id ( type_name, local_id, global_id_pk ) VALUES ( ?,?,? )
StackTrace Array begin
JaversException SQL_EXCEPTION: ERROR: duplicate key value violates unique constraint "jv_global_id_pk"
Detail: Key (global_id_pk)=(571901) already exists.
while executing sql: INSERT INTO schema_a.jv_global_id ( type_name, local_id, global_id_pk ) VALUES ( ?,?,? )
at org.javers.repository.sql.session.PreparedStatementExecutor.wrapExceptionAndCall(PreparedStatementExecutor.java:120)
at org.javers.repository.sql.session.PreparedStatementExecutor.runVoidSql(PreparedStatementExecutor.java:110)
at org.javers.repository.sql.session.PreparedStatementExecutor.execute(PreparedStatementExecutor.java:39)
at org.javers.repository.sql.session.Session.execute(Session.java:106)
at org.javers.repository.sql.session.Session.executeInsertAndGetSequence(Session.java:53)
at org.javers.repository.sql.session.InsertBuilder.executeAndGetSequence(InsertBuilder.java:54)
at org.javers.repository.sql.repositories.GlobalIdRepository.insert(GlobalIdRepository.java:118)
at org.javers.repository.sql.repositories.GlobalIdRepository.getOrInsertId(GlobalIdRepository.java:35)
at org.javers.repository.sql.repositories.CdoSnapshotRepository.save(CdoSnapshotRepository.java:25)
at org.javers.repository.sql.JaversSqlRepository.persist(JaversSqlRepository.java:87)
at org.javers.repository.api.JaversExtendedRepository.persist(JaversExtendedRepository.java:154)
at org.javers.core.JaversCore.persist(JaversCore.java:109)
at org.javers.core.JaversCore.commit(JaversCore.java:90)
at org.javers.spring.transactions.JaversTransactionalDecorator.commit(JaversTransactionalDecorator.java:68)
at org.javers.spring.jpa.JaversTransactionalJpaDecorator.commit(JaversTransactionalJpaDecorator.java:50)
at jdk.internal.reflect.GeneratedMethodAccessor133.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:390)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:702)
at org.javers.spring.jpa.JaversTransactionalJpaDecorator$$SpringCGLIB$$0.commit(<generated>)
at org.javers.spring.auditable.aspect.JaversCommitAdvice.commitObject(JaversCommitAdvice.java:93)
at java.base/java.util.Arrays$ArrayList.forEach(Arrays.java:4204)
at java.base/java.util.Collections$UnmodifiableCollection.forEach(Collections.java:1092)
型
如何解决这个问题?如果我做错了什么,请提出建议。
最初,我在jv_commit_pk
Key上遇到了这样的重复键约束违规问题:
Caused by: org.javers.common.exception.JaversException: SQL_EXCEPTION: ERROR: duplicate key value violates unique constraint "jv_commit_pk"
Detail: Key (commit_pk)=(1086610) already exists.
型
为了解决这个问题,我在另一个架构schema_b
中为我的新应用程序模块创建了新的Javers表,以临时解决这个问题。然后,我在任何一个应用程序模块上都没有再得到jv_commit_pk
Key的问题。但是,我在第一个模块上收到了关于“javers_global_id_pk”Key的问题,我不得不创建一个备份并删除Javers表,以创建新的表来永久解决这个问题。
但是我想要一个更好的解决方案,因为我当前的多模块Java Sping Boot 应用程序将有多个示例,我不希望我的API由于Javers DB问题而失败。
1条答案
按热度按时间mfpqipee1#
要全面解决这个问题,必须考虑Javers库的配置。Javers提供了几种生成提交ID的算法,可以使用
CommitIdGenerator
类指定。*同步序列
*随机
*自定义
有关详细信息,请参阅
org.javers.core.CommitIdGenerator
. here下的文档在Javers中也有关于生成pk-id的类似问题,讨论也可以从here中找到
另一个重要的考虑因素是,使用相同的表为不同的应用程序存储Javers数据可能不是一个理想的解决方案。建议为每个存储自己业务数据的不同实体维护单独的Javers专用表。
幸运的是,Javers提供了自定义表名的配置选项,允许您根据特定需求定制解决方案。