首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么saveAll()总是插入而不是更新数据?

为什么saveAll()总是插入而不是更新数据?
EN

Stack Overflow用户
提问于 2020-12-05 21:42:54
回答 4查看 8.8K关注 0票数 4

Spring Boot 2.4.0,DB是MySql 8

每15秒从REST远程获取数据,然后用saveAll()将其存储到saveAll() DB中。

调用所有给定实体的save()方法。

所有数据都设置了ID。

我希望如果DB没有这样的id -它将是插入的

如果这样的ID已经显示在DB -它将是更新的

这里是从控制台剪下来的:

代码语言:javascript
运行
复制
Hibernate: 
    insert 
    into
        iot_entity
        (controller_ref, description, device_id, device_ref, entity_type_ref, hw_address, hw_serial, image_ref, inventory_nr, ip6address1, ip6address2, ip_address1, ip_address2, latlng, location, mac_address, name, params, status, tenant, type, id) 
    values
        (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
...
2020-12-05 23:18:28.269 ERROR 15752 --- [  restartedMain] o.h.e.jdbc.batch.internal.BatchingBatch  : HHH000315: Exception executing batch [java.sql.BatchUpdateException: Duplicate entry '1' for key 'iot_entity.PRIMARY'], SQL: insert into iot_entity (controller_ref, description, device_id, device_ref, entity_type_ref, hw_address, hw_serial, image_ref, inventory_nr, ip6address1, ip6address2, ip_address1, ip_address2, latlng, location, mac_address, name, params, status, tenant, type, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2020-12-05 23:18:28.269  WARN 15752 --- [  restartedMain] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 1062, SQLState: 23000
2020-12-05 23:18:28.269 ERROR 15752 --- [  restartedMain] o.h.engine.jdbc.spi.SqlExceptionHelper   : Duplicate entry '1' for key 'iot_entity.PRIMARY'
2020-12-05 23:18:28.269 DEBUG 15752 --- [  restartedMain] o.s.orm.jpa.JpaTransactionManager        : Initiating transaction rollback after commit exception

org.springframework.dao.DataIntegrityViolationException: could not execute batch; SQL [insert into iot_entity (controller_ref, description, device_id, device_ref, entity_type_ref, hw_address, hw_serial, image_ref, inventory_nr, ip6address1, ip6address2, ip_address1, ip_address2, latlng, location, mac_address, name, params, status, tenant, type, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)]; constraint [iot_entity.PRIMARY]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute batch

下面是如何获取和保存如下所示的内容:

代码语言:javascript
运行
复制
@Override
@SneakyThrows
@Scheduled(fixedDelay = 15_000)
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void fetchAndStoreData() {
    IotEntity[] entities = restTemplate.getForObject(properties.getIotEntitiesUrl(), IotEntity[].class);

    log.debug("ENTITIES:\n{}", mapper.writerWithDefaultPrettyPrinter().writeValueAsString(entities));

    if (entities != null && entities.length > 0) {
        entityRepository.saveAll(List.of(entities));
    } else {
        log.warn("NO entities data FETCHED !!!");
    }
}

此方法每15秒运行一次。

实体:

代码语言:javascript
运行
复制
@Data
@Entity
@NoArgsConstructor
@EqualsAndHashCode(of = {"id"})
@ToString(of = {"id", "deviceId", "entityTypeRef", "ipAddress1"})
public class IotEntity implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    private Integer id;
    // other fields

和保管所:

代码语言:javascript
运行
复制
public interface EntityRepository extends JpaRepository<IotEntity, Integer> {
}

以下是JSON格式的物联网实体的代码片段:

代码语言:javascript
运行
复制
2020-12-05 23:18:44.261 DEBUG 15752 --- [pool-3-thread-1] EntityService : ENTITIES:
[ {
  "id" : 1,
  "controllerRef" : null,
  "name" : "Local Controller Unterföhring",
  "description" : "",
  "deviceId" : "",
  ...

所以ID绝对是设置好了。

此外,还为项目启用批处理。它不应该对储蓄产生任何影响。

我不明白为什么它试图插入一个新的实体而不是更新现有的实体?

为什么它不能区分新旧实体?

更新:

实体可持续执行:

代码语言:javascript
运行
复制
@Data
@Entity
@NoArgsConstructor
@EqualsAndHashCode(of = {"id"})
@ToString(of = {"id", "deviceId", "entityTypeRef", "ipAddress1"})
public class IotEntity implements Serializable, Persistable<Integer> {
    private static final long serialVersionUID = 1L;

    @Id
    private Integer id;

    @Override
    public boolean isNew() {
        return false;
    }

    @Override
    public Integer getId() {
        return this.id;
    }

但是,同样的异常-- Duplicate entry '1' for key 'iot_entity.PRIMARY' --会失败。

如果我将添加@GeneratedValue,如下所示:

代码语言:javascript
运行
复制
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;

不会失败的。但是,它将自动更新ID值。

例如,它使用id = 15获取

代码语言:javascript
运行
复制
[ {
  "id" : 15,
  "carParkRef" : 15,
  "name" : "UF Haus 1/2",

并应按以下方式保存:

实际上,它使用的是id = 2

这是不正确的。

试图添加到存储服务:

代码语言:javascript
运行
复制
private final EntityManager entityManager;
...
List.of(carParks).forEach(entityManager::merge);

在相同的异常下失败(不管是否实现Persistable)。它尝试插入值- insert into ... Duplicate entry '15' for key '... .PRIMARY'

来自application.yml的片段

代码语言:javascript
运行
复制
spring:
  # ===============================
  # = DATA SOURCE
  # ===============================
  datasource:
    url: jdbc:mysql://localhost:3306/demo_db
    username: root
    password: root
    initialization-mode: always

  # ===============================
  # = JPA / HIBERNATE
  # ===============================
  jpa:
    show-sql: true
    generate-ddl: true
    hibernate:
      ddl-auto: update
    properties:
      hibernate:
        format_sql: true
        generate_statistics: true

在这里你可以看到pom文件内容

如何解决这个问题?

EN

Stack Overflow用户

发布于 2021-08-02 04:29:47

请您试一下@GeneratedValue(strategy = GenerationType.AUTO),这对我有用吗?

票数 0
EN
查看全部 4 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65162298

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档