>source

봄 부팅 2.4.0 , DB는 MySql입니다. 8 .

REST를 사용하여 원격에서 15 초마다 데이터를 가져 와서 MySql DB에 저장합니다. saveAll() .

주어진 모든 엔티티에 대해 save () 메소드를 호출합니다..

모든 데이터에는 세트 ID가 있습니다.
그리고 DB에 그러한 ID가 없으면삽입.
이러한 ID가 이미 DB에 제시되어 있다면업데이트 됨.

다음은 콘솔에서 가져온 것입니다.

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

가져오고 저장하는 방법은 다음과 같습니다.

@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 초마다.

실재:

@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

및 저장소 :

public interface EntityRepository extends JpaRepository<IotEntity, Integer> {
}

다음은 JSON 형식의 iot 엔티티에 대한 내용입니다.

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는 확실히 설정되었습니다.

또한 프로젝트에 대해 일괄 처리가 활성화됩니다. 저축에 영향을 미치지 않아야합니다.

기존 항목을 업데이트하는 대신 새 항목을 삽입하려는 이유를 이해할 수 없습니까?
왜 이전 엔티티와 새 엔티티의 차이를 구별 할 수 없습니까?

<시간 />

최신 정보:

엔티티에 대한 지속성 구현 :

@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 다음과 같이 :

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;

실패하지 않을 것입니다. 그러나 자체적으로 ID 값을 업데이트합니다.

예를 들어, id = 15 :

[ {
  "id" : 15,
  "carParkRef" : 15,
  "name" : "UF Haus 1/2",

다음과 같이 저장해야합니다.

사실 그것은 id = 2 대신 :

그리고 그것은 올바르지 않습니다.

<시간 />

저장 서비스에 추가하려고했습니다.

private final EntityManager entityManager;
...
List.of(carParks).forEach(entityManager::merge);

동일한 예외 (Persistable 구현 여부에 관계없이)와 함께 실패합니다. 값을 삽입하려고합니다. insert into ... Duplicate entry '15' for key '... .PRIMARY'

스 니펫 application.yml :

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 파일 내용.

이 문제를 해결하는 방법은 무엇입니까?


  • 답변 # 1

    문제는 아마도 @Id 로 표시되지 않음 @GeneratedValue , SpringData는 모든 분리 된 (일시적인) 엔티티가 save()/saveAll() 있어야한다 EntityManager.persist() 그들에게 호출되었습니다.

    만들어보십시오 IotEntity 도구 Persistable 및 반환 false ...에서 isNew() . 이것은 SpringData에게 항상 EntityManager.merge() 대신 원하는 효과를 가져야합니다 (예 : 존재하지 않는 엔티티 삽입 및 기존 엔티티 업데이트).

  • 답변 # 2

    이 행동의 근원을 찾은 것 같습니다.

    기본 앱 런처는 다음과 같습니다.

    @AllArgsConstructor
    @SpringBootApplication
    public class Application implements CommandLineRunner {
        private final DataService dataService;
        private final QrReaderServer qrReaderServer;
        private final MonitoringService monitoringService;
        @Override
        public void run(String... args) {
            dataService.fetchAndStoreData();
            monitoringService.launchMonitoring();
            qrReaderServer.launchServer();
        }
    
    

    세 단계 모두 엄격한 실행 순서가 있습니다. 그리고 첫 번째는 필요한 경우 데이터를 로컬로 업데이트하기 위해 반복해야합니다. 저장된 데이터로만 작동하는 다른 두 대의 서버.

    첫 번째 방법은 다음과 같습니다.

    @Scheduled(fixedDelay = 15_000)
    public void fetchAndStoreData() {
        log.debug("START_DATA_FETCH");
        carParkService.fetchAndStoreData();
        entityService.fetchAndStoreData();
        assignmentService.fetchAndStoreData();
        permissionService.fetchAndStoreData();
        capacityService.fetchAndStoreData();
        log.debug("END_DATA_FETCH");
    }
    
    

    또한이 실행도 예정되어 있습니다.

    앱이 시작될 때이 가져 오기를 두 번 실행하려고했습니다.

    2020-12-14 14:00:46.208 DEBUG 16656 --- [pool-3-thread-1] c.s.s.s.data.impl.DataServiceImpl        : START_DATA_FETCH
    2020-12-14 14:00:46.208 DEBUG 16656 --- [  restartedMain] c.s.s.s.data.impl.DataServiceImpl        : START_DATA_FETCH
    
    

    2 개의 스레드가 동일한 캐치에서 실행되고 병렬로 저장됩니다. insert 데이터. (테이블은 시작할 때마다 다시 생성됩니다).

    이후의 모든 가져 오기는 괜찮습니다. @Sceduled 실.

    만약 코멘트 @Sceduled -예외없이 잘 작동합니다.

    <시간 />

    해결책:

    서비스 클래스에 추가 부울 속성을 추가했습니다.

    @Getter
    private static final AtomicBoolean ifDataFetched = new AtomicBoolean(false);
    @Override
    @Scheduled(fixedDelay = 15_000)
    @Order(value = Ordered.HIGHEST_PRECEDENCE)
    public void fetchAndStoreData() {
        log.debug("START_DATA_FETCH");
        ...
        log.debug("END_DATA_FETCH");
        ifDataFetched.compareAndExchange(false, true);
    }
    
    

    그리고 응용 프로그램이 시작된 후 값을 제어하십시오.

    @Override
    public void run(String... args) {
        waitRemoteDataStoring();
        monitoringService.launchMonitoring();
        qrReaderServer.launchServer();
    }
    private void waitRemoteDataStoring() {
        do {
            try {
                Thread.sleep(1_000);
                counter += 1;
                log.debug("wait for data fetch one more second ...");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        } while (!DataServiceImpl.getIfDataFetched().get() || counter > DATA_FETCH_LIMIT);
        log.debug("Data is fetched and stored, launch the services now");
    }
    
    

  • 이전 python - 외부 CSS (Django)에서 배경 이미지로드 문제
  • 다음 angular - 컴포넌트 내부의 데이터가 렌더링되지 않는 이유는 무엇입니까?