충돌 업데이트 시 삽입 일부 필드를 사용하여 Postgres가 있는 Spring Data/Hibernate 저장 엔티티
JpaRepository.save 메서드를 사용하여 저장하고 Postgres의 Sequence generator를 사용하여 ID를 자동으로 생성하는 Spring 도메인 개체가 있습니다.
@SequenceGenerator(initialValue = 1, name = "device_metric_gen", sequenceName = "device_metric_seq")
public class DeviceMetric extends BaseTimeModel {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "device_metric_gen")
@Column(nullable = false, updatable = false)
private Long id;
///// extra fields
내 사용 사례는 다음 작업을 수행해야 합니다.upsert
의 통이아 save
작업(ID가 있는 경우 업데이트할 것으로 알고 있음).세 개의 열 조합(복합 고유)이 있거나 새 행을 작성하는 경우 기존 행을 업데이트하려고 합니다.이는 다음과 유사합니다.
INSERT INTO customers (name, email)
VALUES
(
'Microsoft',
'hotline@microsoft.com'
)
ON CONFLICT (name)
DO
UPDATE
SET email = EXCLUDED.email || ';' || customers.email;
Spring-data에서 동일한 것을 달성하는 한 가지 방법은 다음과 같습니다.
- 다음과 같은 사용자 지정 저장 작업을 서비스 계층에 작성합니다.
- 행이 있는 경우 세 개의 열에 대한 a를 구합니까?
- 현재 개체에 동일한 ID를 설정하고 리포지토리를 수행합니다.저장
- 행이 없으면 일반 리포지토리를 수행합니다. 저장
위 접근법의 문제는 다음과 같습니다.insert
제는이 .select
그리고 나서.save
두의 데이터베이스 호출을 , 두 개 데 이 터 수 하 는 동 호 일 포 한 은 있 출 니 습 의 다 수 달 될 성 해 그 스 레 에 트 스 반 면 의 행 베 호 이 스 을 출 ▁post ▁which ▁calls g ▁whereas ▁can ▁be▁by 두 니 습 ▁makes ▁achieved ▁database 있 ▁sameinsert on conflict
기능을 제공합니다.Spring Data에서 이를 구현하는 방법에 대한 조언이 있습니까?
한 가지 방법은 네이티브 쿼리를 작성하는 것입니다.insert into values (all fields here)
해당 객체는 25개 정도의 필드를 가지고 있기 때문에 저는 동일한 것을 달성할 수 있는 다른 더 나은 방법을 찾고 있습니다.
@JBizet이 언급했듯이, 당신은 데이터를 읽고 발견되면 업데이트하고 그렇지 않으면 삽입하는 것으로 당신의 질문에 답했습니다.스프링 데이터를 사용하여 이를 수행할 수 있는 방법은 다음과 같습니다.Optional
.
를 합니다.findByField1AndField2AndField3
의 신의방에 .DeviceMetricRepository
.
public interface DeviceMetricRepository extends JpaRepository<DeviceMetric, UUID> {
Optional<DeviceMetric> findByField1AndField2AndField3(String field1, String field2, String field3);
}
서비스 메서드에서 리포지토리를 사용합니다.
@RequiredArgsConstructor
public class DeviceMetricService {
private final DeviceMetricRepository repo;
DeviceMetric save(String email, String phoneNumber) {
DeviceMetric deviceMetric = repo.findByField1AndField2AndField3("field1", "field", "field3")
.orElse(new DeviceMetric()); // create new object in a way that makes sense for you
deviceMetric.setEmail(email);
deviceMetric.setPhoneNumber(phoneNumber);
return repo.save(deviceMetric);
}
}
관찰 가능성에 대한 조언:이는 시스템의 높은 처리량 사용 사례라고 언급했습니다.어떤 접근 방식을 취하든 이 저장 주위에 타이머를 설치하는 것을 고려합니다.이렇게 하면 객관적인 방식으로 수행한 모든 조정에 대해 초기 성능을 측정할 수 있습니다.이 실험을 살펴보고 필요에 따라 다른 솔루션으로 전환할 준비를 하십시오.이 세 개의 열을 항상 함께 읽는 경우 인덱스가 있는지 확인합니다.이러한 기능을 사용하면 업데이트/삽입 여부를 확인할 수 있습니다.
명명된 쿼리를 사용하여 후보 키를 기준으로 행을 가져오는 것이 좋습니다.행이 있으면 해당 행을 업데이트하고, 그렇지 않으면 새 행을 만듭니다.이 두 작업은 모두 저장 방법을 사용하여 수행할 수 있습니다.
@NamedQuery(name="getCustomerByNameAndEmail", query="select a from Customers a where a.name = :name and a.email = :email");
또한 도면요소에 대한 @UniqueColumns() 주석을 사용하여 이러한 열이 함께 그룹화될 때 항상 고유성을 유지하도록 할 수 있습니다.
Optional<Customers> customer = customerRepo.getCustomersByNameAndEmail(name, email);
저장소에 위의 방법을 구현합니다.쿼리를 호출하고 이름과 전자 메일을 매개 변수로 전달합니다.행이 없으면 Optional.empty()를 반환해야 합니다.
Customers c;
if (customer.isPresent()) {
c = customer.get();
c.setEmail("newemail@gmail.com");
c.setPhone("9420420420");
customerRepo.save(c);
} else {
c = new Customer(0, "name", "email", "5451515478");
customerRepo.save(c);
}
ID를 0으로 전달하면 JPA가 시퀀스 생성기에 따라 생성된 ID로 새 행을 삽입합니다.
숫자를 ID로 사용하는 것은 권장하지 않지만, 가능하면 기본 키에 임의로 생성된 UUID를 사용하면 고유성을 보장하고 시퀀스 생성기에서 발생할 수 있는 예기치 않은 동작을 방지할 수 있습니다.
스프링 JPA를 사용하면 깨끗한 자바 코드로 이를 구현하는 것이 매우 간단합니다.Spring Data JPA 방법 사용T getOne(ID id)
DB 자체를 쿼리하는 것이 아니라 DB 객체(프록시)에 대한 참조를 사용하는 것입니다.따라서 엔티티를 업데이트/저장할 때 일회성 작업을 수행합니다.
객체를 수정할 수 있도록 Spring에서 제공하는@Transactional
주석 - 메서드가 트랜잭션을 시작하고 메서드 자체가 런타임을 종료할 때만 종료함을 선언하는 메서드 수준 주석입니다.
다음을 수행해야 합니다.
- jpa 트랜잭션 시작
- getOne을 통해 DB 참조 가져오기
- DB 참조 수정
- 그것을 데이터베이스에 저장합니다.
- 거래를 종료합니다.
실제 코드를 잘 볼 수 없기 때문에 가능한 한 많이 추상화할 것입니다.
@Transactional
public void saveOrUpdate(DeviceMetric metric) {
DeviceMetric deviceMetric = metricRepository.getOne(metric.getId());
//modify it
deviceMetric.setName("Hello World!");
metricRepository.save(metric);
}
까다로운 부분은 getOne을 DB의 SELECT로 생각하지 않는 것입니다.'저장' 메서드가 있을 때까지 데이터베이스가 호출되지 않습니다.
언급URL : https://stackoverflow.com/questions/58352334/spring-data-hibernate-save-entity-with-postgres-using-insert-on-conflict-updat
'it-source' 카테고리의 다른 글
스크립트 하나에 여러 트리거를 생성하는 방법이 있습니까? (0) | 2023.07.15 |
---|---|
문자열에서 모든 공백을 제거하는 방법은 무엇입니까? (0) | 2023.07.15 |
한 워크북의 시트에서 다른 워크북으로 VBA 코드를 복사하시겠습니까? (0) | 2023.07.15 |
iOS 시뮬레이터 내에서 앱스토어에 액세스할 수 있습니까? (0) | 2023.07.15 |
MongoDB는 $exists 연산자로 필드의 존재를 확인할 때 인덱스를 사용할 수 있습니까? (0) | 2023.07.15 |