Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 重复条目异常:Spring Hibernate/JPA级联多对一保存_Java_Spring_Hibernate_Jpa - Fatal编程技术网

Java 重复条目异常:Spring Hibernate/JPA级联多对一保存

Java 重复条目异常:Spring Hibernate/JPA级联多对一保存,java,spring,hibernate,jpa,Java,Spring,Hibernate,Jpa,它是一个spring应用程序(无spring引导)。 我使用的数据库是MySQL。 我遇到的问题是在保存实体驱动程序时,该实体在Carrier和Location上都具有多对一关系 我想做的是,当我在驱动程序上保存时。驱动程序以及位置和载体被持久化到数据库中。我遇到的问题是当我试图拯救的时候。我得到了重复的密钥冲突 堆栈跟踪: org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions WARN: SQL Error: 1062,

它是一个spring应用程序(无spring引导)。 我使用的数据库是MySQL。 我遇到的问题是在保存实体
驱动程序
时,该实体在
Carrier
Location
上都具有多对一关系

我想做的是,当我在驱动程序上保存时。驱动程序以及位置和载体被持久化到数据库中。我遇到的问题是当我试图拯救的时候。我得到了重复的密钥冲突

堆栈跟踪:

org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
WARN: SQL Error: 1062, SQLState: 23000
Feb 18, 2019 1:25:42 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
ERROR: Duplicate entry '910327' for key 'UK_lheij6i9eldhfhyu9j1q5fjls'
Exception in thread "main" org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [UK_lheij6i9eldhfhyu9j1q5fjls]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:296)
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:253)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:527)
    at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
    at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:135)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
    at com.sun.proxy.$Proxy47.saveAll(Unknown Source)
    at greyhound.service.GreyhoundServiceImpl.process(GreyhoundServiceImpl.java:38)
    at greyhound.Main.main(Main.java:17)
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement
    at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:59)
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:178)
    at org.hibernate.dialect.identity.GetGeneratedKeysDelegate.executeAndExtract(GetGeneratedKeysDelegate.java:57)
    at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:42)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3073)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3666)
    at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:81)
    at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:645)
    at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:282)
    at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:263)
    at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:317)
    at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:332)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:289)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:196)
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:127)
    at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:192)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:135)
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:828)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:795)
    at org.hibernate.engine.spi.CascadingActions$7.cascade(CascadingActions.java:298)
    at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:490)
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:415)
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:216)
    at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:149)
    at org.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:428)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:266)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:196)
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:127)
    at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:192)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:135)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:62)
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:804)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:789)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:308)
    at com.sun.proxy.$Proxy44.persist(Unknown Source)
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:489)
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.saveAll(SimpleJpaRepository.java:521)
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.saveAll(SimpleJpaRepository.java:73)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:359)
    at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:644)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:608)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
    ... 11 more
Caused by: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '910327' for key 'UK_lheij6i9eldhfhyu9j1q5fjls'
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:117)
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
    at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
    at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:970)
    at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1109)
    at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1057)
    at com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1377)
    at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:1042)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:175)
    ... 69 more

Process finished with exit code 1
实体/模型类:(已删除getter/setter)

更新#2

有这样的驾驶执照吗

@Repository
public interface DriverRepository extends JpaRepository<Driver, Long> {

}
Github链接


我添加了github链接,以防有人愿意尝试。

您还需要使用板条箱
驱动程序填充
承运人
位置

  for(DriverAssignment driverAssignment : result.getDriverAssignments()) {
        Location location = new Location();
        Carrier carrier = new Carrier();
        Driver driver = new Driver();
        driver.setCarrier(carrier);
        driver.setLocation(location);

        // add this
        location.getDrivers().add(driver);
        carrier.getDrivers().add(driver);

        drivers.add(driver);
    }
由于您使用了双向映射(
@OneToMany
),因此需要执行此操作

更新

使用JPA级联配置,而不是休眠配置:

@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Carrier carrier;

@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Location location;
更新2

仔细查看您的项目后,您似乎缺少以下方面的事务设置:

@Transactional
public void process() {
在该方法中,您正在执行许多存储库操作,这很好,因为所有SimpleParepository方法都是事务性的

我认为问题在于,并非所有这些操作都在同一事务和有效持久性上下文下运行。(每个操作都在自己的小事务中运行,之后所有实体都从持久性上下文中分离出来)


注意:您可能需要稍微调整一下配置,以启用@Transactional annotation设置。

解决此问题的一种方法是加载所有位置和载体,以便使用findById()将它们绑定到您的会话。使用这些获得的对象在新的驱动程序对象上进行设置。这应该可以解决问题

for(DriverAssignment driverAssignment : result.getDriverAssignments()) {
  Location location;
  if (driverAssignment.getHomeLocation() != null) {
    location = locationRepo.findById(driverAssignment.getHomeLocation());
  } else {
    location = new Location();
  }
  location.setLocationName(driverAssignment.getHomeLocation3());
  Carrier carrier;
  if (driverAssignment.getCarrierId() != null) {
    carrier = carrierRepo.findById(driverAssignment.getCarrierId());
  } else {
    carrier = new Carrier();
  }
  Driver driver;
  if (driverAssignment.getDriverId() != null) {
    driver = driverRepo.findById(driverAssignment.getCarrierId());
  } else {
    driver = new Driver();
  }
  driver.setDriverId(driverAssignment.getDriverId());
  driver.setFirstName(driverAssignment.getFirstName());
  driver.setLastName(driverAssignment.getLastName());
  driver.setMiddleInitial(driverAssignment.getMiddleInitial());
  driver.setCarrier(carrier);
  driver.setLocation(location);
  drivers.add(driver);
}

它看起来像这样。这只是一个简单的例子,因为我不知道实际的上下文。

在插入两侧的条目时,会导致重复问题。 解决方法是将一面标记为“mappedby”,另一面标记为“mappedby”

因此,在
Carrier
类中使用:

@OneToMany(mappedBy="carrier")
@JoinColumn(name = "carrier_id", referencedColumnName = "id")
private List<Driver> drivers = new ArrayList<Driver>();
@OneToMany(mappedBy="location")
@JoinColumn(name = "location_id", referencedColumnName = "location_id")
private List<Driver> drivers = new ArrayList<Driver>();

我们需要将标识符作为引用的列名传递。映射位置实体,如下所示

@OneToMany
@JoinColumn(name = "location_id", referencedColumnName = "id")
private List<Driver> drivers = new ArrayList<Driver>();
@OneToMany
@JoinColumn(name=“location\u id”,referencedColumnName=“id”)
私有列表驱动程序=新的ArrayList();

由于
位置
运营商
都有版本控制,并且您没有在创建的实例中设置版本,Hibernate可能只是认为它们是新的,并尝试插入它们(否则,如果它们需要更新,Hibernate无论如何都不知道要比较哪个版本,因为更新的实例中缺少该版本)

首先,您需要:

  • 从db中获取现有的
    位置
    运营商
    实例,如果它们不是新实例,则更新它们(通过检查id是否已设置,您就知道这一点)
  • 或者正确地传播和设置版本属性以及id和业务属性
其次,对于当前的实体映射,您还有两个选择(以及允许Hibernate正确保存整个图形的既定目标):

  • 如果您不使用事务,那么对于以上两种情况,您必须求助于
    entityManager.merge(driver)
    ,以便正确插入或更新所有内容
  • 否则,仅当您选择上面的第一个选项并读取现有的
    位置
    运营商
    实例,并在同一事务中调用
    存储库.saveAll(drivers)
    ,它才会起作用,因为驱动程序实例将被持久化,
    持久化
    操作将级联到仍然连接的位置和载体实例

根据项目中使用的架构选择和约定,还有(许多)其他可能性,也就是说,我不会将所有的
many
端级联到
one
端(一个示例不希望出现的结果是删除),并且在大多数情况下,我总是明确地分别保存
one
端,但这取决于你。

我准备了工作解决方案:。 我“稍微”修改了你的项目——使用Spring Boot、Lombok和H2数据库,只是为了演示和简化它

因此,如果我没有弄错的话,任务是转换“作业””(来自灰狗网站):

到三个实体:
驱动程序
位置
,以及
承运人
,具有以下关系:

Location -1---*- Driver -*---1- Carrier
i、 e.
驾驶员
位置
承运人
有“多对一”关系

此任务的主要问题是,在保存
驱动程序
实体时,我们需要使用已保存的位置
载体
实体,或者使用新实体。因此,要解决这个问题,我们必须:

  • 为这些实体准备3个存储库
  • 对于每个“分配”查找相关的
    位置
    承运人
  • 如果未找到
    位置
    承运人
    ,则创建新的承运人
  • 创建一个新的
    驾驶员
    ,并设置找到的
    位置
    承运人
    或已创建的新驾驶员
  • 持久化
    驱动程序
    (和级联持久化
    位置
    载波
    (如果未找到)
  • 方法
    GreyhoundService.process()
    的最终代码:

    @Transactional
    公共程序(){
    client.getAssignments()
    .stream()
    .forEach(a->{
    调试(“[d]赋值:{}”,a);
    驱动程序=新驱动程序();
    驱动程序设置ID(a.ge
    
    @OneToMany(mappedBy="carrier")
    @JoinColumn(name = "carrier_id", referencedColumnName = "id")
    private List<Driver> drivers = new ArrayList<Driver>();
    
    @OneToMany(mappedBy="location")
    @JoinColumn(name = "location_id", referencedColumnName = "location_id")
    private List<Driver> drivers = new ArrayList<Driver>();
    
    @OneToMany
    @JoinColumn(name = "location_id", referencedColumnName = "id")
    private List<Driver> drivers = new ArrayList<Driver>();
    
    {
        "results": [
            {
                "oper_nbr": 1,
                "carrier_cd": "GLX ",
                "last_name": "JOHN",
                "first_name": "SMITH",
                "middle_init": null,
                "home_loc_6": 12345,
                "home_loc_3": "NLX",
                "oper_class": "T"
            },
            {
                "oper_nbr": 2,
                "carrier_cd": "GLX ",
                "last_name": "JOHN",
                "first_name": "DOE",
                "middle_init": null,
                "home_loc_6": 67890,
                "home_loc_3": "NLX",
                "oper_class": "T"
            }
        ]
    }
    
    Location -1---*- Driver -*---1- Carrier