当前位置: 首页 > 知识库问答 >
问题:

SqlExceptionHelper-使用Spring数据JPA为唯一键复制条目

东方新霁
2023-03-14

情况如下:

  1. 我有3张表——Dummy、A和B——其中A和B有一对多的关系,Dummy是独立的

上面从#4到#7的顺序就像是虚拟桌子的魅力。但未能对A和B执行。例外情况是:

ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper - Duplicate entry <The name here> for key 'name_UNIQUE'
Exception in thread "main" org.springframework.orm.jpa.JpaSystemException: org.hibernate.exception.ConstraintViolationException: could not execute statement; nested exception is javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:321)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:403)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:58)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)

我正在更新的字段不是唯一的。这些实体具有完全相同的结构,到处都有一些额外的列。

以下是虚拟实体的代码:

    DummyEntity dummyEntity = dummyService.findDummyEntity(16L);
    System.out.println(">>> Name is: " + dummyEntity.getName() + " with ID: " + dummyEntity.getId());
    dummyEntity.setName("New Name");
    dummyEntity.setRank(3333333);
    dummyService.updateDummyEntity(dummyEntity);

对其余实体A和B重复完全相同的步骤。

那么我做错了什么?任何指点都将不胜感激。

@是的,我仔细检查过了。以下是我在这里提出问题后观察到的情况。表A和表B(麻烦的表)有以下问题:

  • 当我请求存储库服务为表a和表B返回给定ID的实例时,它会正确地返回它们
  • 当使用setXXX()对该实例进行更改,并调用updateEntity()或saveEntity()时(如上面使用演示实体代码所示),save/update会在表中插入一个新实体,其属性值与旧实体的属性值完全相同,但随着新变化的加入(通过移除表A和表B上的唯一键约束可以观察到这一点)
  • 稍后,当我使用JPA/Java代码中的ID查询这些新创建的实体,并执行完全相同的步骤(更改某些属性并在存储库上调用save/update)时,这些新创建的实体(db表中的行)会以完全预期的方式得到更新
  • 因此,原始实体(行)似乎以某种方式被“锁定”,并阻止了更新。因此,JPA save/update调用只是尝试创建一个新的调用;由于新实体仍然具有相同的属性值集,任何唯一的键约束都会开始抱怨(当然)
  • 我对现有的表进行了一些测试(ETL被导入数据库),发现这种行为是一致的:如果实体不是由JPA创建的,那么JPA可以正常读取数据,但无法更新它们;如果实体是由JPA创建的,那么JPA可以读取并更新它们

不过(目前)还不确定这是怎么发生的。以下是表A和表B的模式:

CREATE TABLE IF NOT EXISTS `mydbschema`.`table-B` (
  `id` INT NOT NULL AUTO_INCREMENT COMMENT 'This is PK',
  `name` VARCHAR(100) NULL,
  `city` VARCHAR(50) NOT NULL,
  `state` VARCHAR(30) NOT NULL,
  `zip` VARCHAR(5) NOT NULL,
  `country` VARCHAR(50) NOT NULL,
  `overall_rank` INT NULL,
  `inserted` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `insert_src_ver_id` INT NULL,
  `updated` TIMESTAMP NULL ON UPDATE CURRENT_TIMESTAMP,
  `update_src_ver_id` INT NULL,
  `version` INT NULL,
  PRIMARY KEY (`id`),
  UNIQUE INDEX `name_UNIQUE` (`name` ASC))
ENGINE = InnoDB;

另一个:

CREATE TABLE IF NOT EXISTS `mydbschema`.`table-A` (
  `id` INT NOT NULL AUTO_INCREMENT COMMENT 'This is PK',
  `full_name` VARCHAR(200) NULL,
  `gender` VARCHAR(1) NULL,
  `year_of_birth` VARCHAR(4) NULL,
  `title_code` VARCHAR(6) NULL,
  `business_role` VARCHAR(30) NULL,
  `graduation_year` VARCHAR(4) NULL,
  `residency` VARCHAR(500) NULL,
  `table-B_id` INT NULL,
  `npi_num` VARCHAR(10) NULL,
  `upin` VARCHAR(20) NULL,
  `dea_num` VARCHAR(20) NULL,
  `dea_expire_date` VARCHAR(10) NULL,
  `year_started_practicing` VARCHAR(4) NULL,
  `high_prescriber` VARCHAR(1) NULL,
  `board_action` VARCHAR(1) NULL,
  `mdi_qscore` INT NOT NULL DEFAULT 0,
  `mdi_cscore` INT NOT NULL DEFAULT 0,
  `aco_id` INT NULL,
  `npp` INT NULL,
  `medicaid_id` VARCHAR(50) NULL,
  `medicaid_state` VARCHAR(2) NULL,
  `medicare_id` VARCHAR(50) NULL,
  `medicare_state` VARCHAR(2) NULL,
  `medicare_provider_flag` VARCHAR(1) NULL,
  `inserted` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `insert_src_ver_id` INT NULL,
  `updated` TIMESTAMP NULL ON UPDATE CURRENT_TIMESTAMP,
  `update_src_ver_id` INT NULL,
  `version` INT NULL,
  PRIMARY KEY (`id`),
  UNIQUE INDEX `hdsphy_id_UNIQUE` (`id` ASC),
  UNIQUE INDEX `npi_num_UNIQUE` (`npi_num` ASC),
  UNIQUE INDEX `dea_num_UNIQUE` (`dea_num` ASC),
  CONSTRAINT `fk_table-A_table-B`
    FOREIGN KEY (`table-B_id`)
    REFERENCES `mydbschema`.`table-B` (`id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION,
ENGINE = InnoDB;

以下是完整的堆栈跟踪:

2013-09-30 10:20:49,705 [main] ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper - Duplicate entry '1568673648' for key 'npi_num_UNIQUE'
Exception in thread "main" org.springframework.orm.jpa.JpaSystemException: org.hibernate.exception.ConstraintViolationException: could not execute statement; nested exception is javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:321)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:403)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:58)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:163)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.data.jpa.repository.support.LockModeRepositoryPostProcessor$LockModePopulatingMethodIntercceptor.invoke(LockModeRepositoryPostProcessor.java:84)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:91)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at com.sun.proxy.$Proxy60.save(Unknown Source)
at com.mdinsider.platform.domain.PhysicianServiceImpl_Roo_Service.ajc$interMethod$com_mdinsider_platform_domain_PhysicianServiceImpl_Roo_Service$com_mdinsider_platform_domain_PhysicianServiceImpl$updatePhysician(PhysicianServiceImpl_Roo_Service.aj:48)
at com.mdinsider.platform.domain.PhysicianServiceImpl.updatePhysician(PhysicianServiceImpl.java:1)
at com.mdinsider.platform.domain.PhysicianService_Roo_Service.ajc$interMethodDispatch1$com_mdinsider_platform_domain_PhysicianService_Roo_Service$com_mdinsider_platform_domain_PhysicianService$updatePhysician(PhysicianService_Roo_Service.aj)
at com.mdinsider.platform.mediblip.engine.TestDBSave.saveMDIQualityScore(TestDBSave.java:94)
at com.mdinsider.platform.mediblip.engine.TestDBSave.main(TestDBSave.java:142)
Caused by: javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1387)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1310)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1316)
at org.hibernate.ejb.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:898)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:241)
at com.sun.proxy.$Proxy31.merge(Unknown Source)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:345)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:334)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:319)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155)
... 12 more
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement
at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:74)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:125)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:110)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:136)
at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:96)
at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:58)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2975)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3487)
at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:81)
at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:377)
at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:214)
at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:194)
at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:178)
at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:321)
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:286)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:192)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:125)
at org.hibernate.ejb.event.EJB3MergeEventListener.saveWithGeneratedId(EJB3MergeEventListener.java:71)
at org.hibernate.event.internal.DefaultMergeEventListener.saveTransientEntity(DefaultMergeEventListener.java:236)
at org.hibernate.event.internal.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:216)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:154)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:76)
at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:914)
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:898)
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:902)
at org.hibernate.ejb.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:889)
... 31 more
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '1568673648' for key 'npi_num_UNIQUE'
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
at com.mysql.jdbc.Util.getInstance(Util.java:386)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1039)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3609)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3541)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2002)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2163)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2624)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2127)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2427)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2345)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2330)
at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105)
at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:133)

共有1个答案

顾正初
2023-03-14

好了,问题解决了。在尝试了各种隔离问题的方法之后,我发现手动或通过ETL添加的任何行都会被选择性地处理为该异常。Spring数据JPA/Java代码添加的任何行都可以正常工作。

因此,问题在于手动插入行。然后我意识到,对于手动插入的行,版本字段的值为空。当我将值设置为0时,JPA可以接受手动插入的行。

另一种选择是表中根本没有版本字段。

希望这能帮助遇到同样问题的人。

 类似资料:
  • 我有以下问题,我有一个已经存在的表,有三个字段field1,field2,field3。Field1实际上是另一个表的外键(@OneToOne)。所有字段2和字段3都可以为空,所以我不能为所有三个字段设置主键。在数据库中,field1 field2 field3有一个唯一约束。 我用JPA/Hibernate尝试了几种解决方案,但没有找到一个好的。如果不定义@Id,JPA当然无法工作。在@Embe

  • 问题内容: 如何定义一个字段,例如使用JPA批注进行索引。我们需要一个非唯一的键,因为每天在该字段上有数百万个查询,而没有键的话,它有点慢。 我已经看到了特定于hibernate的注释,但是由于我们仍在确定hibernate和数据核之间的关系,因此我试图避免使用特定于供应商的解决方案。 更新: 从JPA 2.1开始,您可以执行此操作。请参阅:此位置不允许使用注释@Index 问题答案: 使用JPA

  • 在现有答案中搜索没有给出有效结果。这就是我找不到原因的错误。我有一个实体类< code>MeteoRecord和< code>DayDegree,定义如下: 所有实体都扩展< code>AbstractEntity类: 保存新的如下所示: 它会引发错误: “气象仓库”只是扩展了“”JPA存储库: 我激活了更多日志以查看SQL查询,但没有看到创建新的其他查询,也没有在其他地方插入记录: 我错过了什么

  • 本文向大家介绍MySQL查询重复数据(删除重复数据保留id最小的一条为唯一数据),包括了MySQL查询重复数据(删除重复数据保留id最小的一条为唯一数据)的使用技巧和注意事项,需要的朋友参考一下 开发背景: 最近在做一个批量数据导入到MySQL数据库的功能,从批量导入就可以知道,这样的数据在插入数据库之前是不会进行重复判断的,因此只有在全部数据导入进去以后在执行一条语句进行删除,保证数据唯一性。

  • 有人知道如何使用Spring数据JPA获得一个列吗?我在我的Spring Boot项目中创建了一个存储库,如下所示,但总是得到

  • 问题内容: 我如何在MySQL中应用distinct关键字,以便仅检查一个列字段是否唯一,同时仍从表中返回其他列? 问题答案: 为了能够做到这一点,mysql必须知道如何处理其他列。您GROUP BY列应该是唯一的,并使用一个函数来告诉它如何处理其他列(所谓的 汇总函数 )。和是常见的例子: