스프링 부트 데이터 JPA - 업데이트 쿼리 수정 - 지속성 컨텍스트 새로 고침
Spring Boot 1.3.0을 사용하고 있습니다.M4 및 MySQL 데이터베이스.
수정 쿼리를 사용할 때 문제가 발생하는데, 쿼리가 실행된 후 EntityManager에 오래된 엔티티가 포함되어 있습니다.
원본 JPA 저장소:
public interface EmailRepository extends JpaRepository<Email, Long> {
@Transactional
@Modifying
@Query("update Email e set e.active = false where e.active = true and e.expire <= NOW()")
Integer deactivateByExpired();
}
DB에 Email [id=1, active=true, expirate=2015/01/01]이(가) 있다고 가정합니다.
실행 후:
emailRepository.save(email);
emailRepository.deactivateByExpired();
System.out.println(emailRepository.findOne(1L).isActive()); // prints true!! it should print false
문제를 해결하기 위한 첫 번째 접근법: 명확성 추가자동 = 참
public interface EmailRepository extends JpaRepository<Email, Long> {
@Transactional
@Modifying(clearAutomatically = true)
@Query("update Email e set e.active = false where e.active = true and e.expire <= NOW()")
Integer deactivateByExpired();
}
이 접근방식은 오래된 값을 갖지 않도록 지속성 컨텍스트를 클리어하지만 Entity Manager에서 아직 보류 중인 플러시되지 않은 모든 변경을 폐기합니다.메서드만 사용하고 다른 엔티티에 대한 변경은 손실되지 않습니다.
문제 해결을 위한 두 번째 접근법: 저장소용 맞춤 구현
public interface EmailRepository extends JpaRepository<Email, Long>, EmailRepositoryCustom {
}
public interface EmailRepositoryCustom {
Integer deactivateByExpired();
}
public class EmailRepositoryImpl implements EmailRepositoryCustom {
@PersistenceContext
private EntityManager entityManager;
@Transactional
@Override
public Integer deactivateByExpired() {
String hsql = "update Email e set e.active = false where e.active = true and e.expire <= NOW()";
Query query = entityManager.createQuery(hsql);
entityManager.flush();
Integer result = query.executeUpdate();
entityManager.clear();
return result;
}
}
이 접근방식은 다음과 같이 동작합니다.@Modifying(clearAutomatically = true)
단, 업데이트를 실행하기 전에 Entity Manager가 강제로 모든 변경을 DB로 플래시한 후 지속성 컨텍스트를 클리어합니다.이렇게 하면 오래된 엔티티가 없고 모든 변경 내용이 DB에 저장됩니다.
오래된 엔티티의 문제나 매뉴얼을 DB에 플래시하지 않고 JPA에서 업데이트 스테이트먼트를 실행할 수 있는 더 좋은 방법이 있는지 알고 싶습니다.2차 캐시를 비활성화 시킬까요?Spring Boot에서는 어떻게 할 수 있나요?
2018년 갱신
Spring Data JPA가 제 PR을 승인했습니다.flushAutomatically
에 선택권을 주다.@Modifying()
지금이다.
@Modifying(flushAutomatically = true, clearAutomatically = true)
당신이 이미 Github에 대한 픽스를 작성하고 풀 요청을 시작했기 때문에 이것이 당신의 질문에 대한 직접적인 답변이 아니라는 것을 알고 있습니다.감사합니다!
하지만 JPA의 길을 설명하겠습니다.따라서 특정 기준과 일치하는 모든 엔티티를 변경하고 각 엔티티의 값을 업데이트하려고 합니다.통상적인 접근방식은 필요한 엔티티를 모두 로드하는 것입니다.
@Query("SELECT * FROM Email e where e.active = true and e.expire <= NOW()")
List<Email> findExpired();
그런 다음 이 값을 반복하고 업데이트합니다.
for (Email email : findExpired()) {
email.setActive(false);
}
이제 휴지 상태가 모든 변경 사항을 알고 있으며 트랜잭션이 완료되거나 사용자가 호출하면 데이터베이스에 씁니다.EntityManager.flush()
수동으로 조작할 수 있습니다.모든 엔티티를 메모리에 로드하기 때문에 대량의 데이터 엔트리가 있는 경우 이 방법이 제대로 작동하지 않는다는 것을 알고 있습니다.그러나 이것은 휴지 상태의 엔티티 캐시, 2차 수준의 캐시 및 데이터베이스를 동기화하는 최선의 방법입니다.
이 답변은 '@수정' 주석은 무용지물입니까?아니요! 변경된 엔티티가 로컬 캐시(예: 쓰기 전용 응용 프로그램)에 없는지 확인하는 경우 이 접근 방식이 적합합니다.
은 리리 and and, and신 and and and and and and and and and 는 필요 없습니다.@Transactional
이치노
v2의 : "v2"의 경우:active
은 과 column직 column column column column column column column column column column column column column column column column column column column column 와 직접적인 관계가 있는 것처럼 보입니다.expire
왜 '삭제'를 active
expire
든질 ??
klaus-groenback의 설명대로 EntityManager를 주입하고 새로 고침 방법을 사용할 수 있습니다.
@Inject
EntityManager entityManager;
...
emailRepository.save(email);
emailRepository.deactivateByExpired();
Email email2 = emailRepository.findOne(1L);
entityManager.refresh(email2);
System.out.println(email2.isActive()); // prints false
언급URL : https://stackoverflow.com/questions/32258857/spring-boot-data-jpa-modifying-update-query-refresh-persistence-context
'programing' 카테고리의 다른 글
서버 마이그레이션 후 이미지 파일 이름으로 인코딩되는 특수 문자 (0) | 2023.02.26 |
---|---|
해시 조인(Oracle RDBMS)과 머지 조인(Merge Join)의 차이점은 무엇입니까? (0) | 2023.02.26 |
브라우저 새로 고침 후 angularjs 코드 변경이 표시되지 않음 (0) | 2023.02.26 |
Wordpress 구독(라벨(코셀)) (0) | 2023.02.26 |
Wordpress REST API(wp-api) 404 오류: WordPress REST API에 액세스할 수 없습니다. (0) | 2023.02.26 |