Spring Data Jpa Javers的重复键值违反了global_id_pk Key上的唯一约束Exception

wztqucjr  于 4个月前  发布在  Spring
关注(0)|答案(1)|浏览(83)

我已经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问题而失败。

mfpqipee

mfpqipee1#

要全面解决这个问题,必须考虑Javers库的配置。Javers提供了几种生成提交ID的算法,可以使用CommitIdGenerator类指定。

*同步序列
*随机
*自定义

有关详细信息,请参阅org.javers.core.CommitIdGenerator. here下的文档

  • 使用SYNCHRONIZED_SEQUENCE策略时,SQL Repository中的Commit_pk是使用数据库序列生成的,这种方式可以保证多示例多线程应用的安全性,但需要注意的是,该策略涉及到分配一组PK值(例如,100个PK值)。这可能在高强度系统中潜在地造成问题。因此,在分布式环境中,强烈建议您考虑使用RANDOM策略来生成ID。*

在Javers中也有关于生成pk-id的类似问题,讨论也可以从here中找到
另一个重要的考虑因素是,使用相同的表为不同的应用程序存储Javers数据可能不是一个理想的解决方案。建议为每个存储自己业务数据的不同实体维护单独的Javers专用表。
幸运的是,Javers提供了自定义表名的配置选项,允许您根据特定需求定制解决方案。

相关问题