문제는 거의 모든 것을 말합니다. JPARepository를 사용하여 엔티티를 어떻게 업데이트합니까?
JPARepository에는 실제로 저장 또는 작성 중인지 알려주지 않는 저장 메소드 만 있습니다. 예를 들어, 나는 세 개의 필드가 데이터베이스 사용자에게 간단한 개체를 삽입 : firstname
, lastname
및 age
:
@Entity
public class User {
private String firstname;
private String lastname;
//Setters and getters for age omitted, but they are the same as with firstname and lastname.
private int age;
@Column
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
@Column
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
private long userId;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
public long getUserId(){
return this.userId;
}
public void setUserId(long userId){
this.userId = userId;
}
}
그런 다음 간단히 호출 save()
하면 데이터베이스에 실제로 삽입됩니다.
User user1 = new User();
user1.setFirstname("john"); user1.setLastname("dew");
user1.setAge(16);
userService.saveUser(user1);// This call is actually using the JPARepository: userRepository.save(user);
여태까지는 그런대로 잘됐다. 이제이 사용자를 업데이트하고 싶습니다. 나이를 바꾸십시오. 이 목적을 위해 QueryDSL 또는 NamedQuery와 같은 쿼리를 사용할 수 있습니다. 그러나 spring-data-jpa와 JPARepository를 사용하고 싶다는 것을 고려할 때 삽입 대신 업데이트를 원한다고 어떻게 알 수 있습니까?
특히, 동일한 사용자 이름과 이름을 가진 사용자가 실제로 동일하고 기존 엔티티가 업데이트되어야한다고 spring-data-jpa에 알리려면 어떻게해야합니까? equals를 재정의해도이 문제는 해결되지 않았습니다.
답변
엔터티의 ID는 기본 키로 정의됩니다. 이후 firstname
및 lastname
기본 키의 일부하지, 당신은 치료에 JPA를 말할 수 없다 User
같은과의 firstname
s와 lastname
서로 다른 경우 동일로의 userId
들.
따라서 and 로 User
식별 된 정보 를 업데이트 하려면 쿼리 로 식별 한 다음 찾은 객체의 해당 필드를 변경해야합니다. 이러한 변경 사항은 트랜잭션이 끝날 때 데이터베이스에 자동으로 플러시되므로 변경 사항을 명시 적으로 저장하기 위해 아무 것도 할 필요가 없습니다.firstname
lastname
User
편집하다:
아마도 JPA의 전체 의미에 대해 자세히 설명해야 할 것입니다. 퍼시스턴스 API 디자인에는 두 가지 주요 접근 방식이 있습니다.
-
삽입 / 업데이트 접근법 . 데이터베이스를 수정해야하는 경우 지속성 API 메소드를 명시 적으로 호출
insert
해야합니다. 오브젝트를 삽입하거나 오브젝트의update
새 상태를 데이터베이스에 저장하기 위해 호출 합니다. -
작업 단위 접근 . 이 경우 지속성 라이브러리로 관리 되는 오브젝트 세트가 있습니다. 이러한 오브젝트에 대한 모든 변경 사항은 작업 단위 (UOW) 종료시 (즉, 일반적인 경우 현재 트랜잭션 종료시) 데이터베이스에 자동으로 플러시됩니다. 데이터베이스에 새 레코드를 삽입해야하는 경우 해당 오브젝트를 관리 합니다. 관리 대상 객체는 기본 키로 식별되므로 사전 정의 된 기본 키가 managed 인 객체를 만들면 동일한 id의 데이터베이스 레코드와 연결되고이 객체의 상태가 해당 레코드에 자동으로 전파됩니다.
JPA는 후자의 접근법을 따릅니다. save()
Spring Data JPA는 merge()
일반 JPA로 지원되므로 위에서 설명한대로 엔티티를 관리 합니다. save()
사전 정의 된 id를 가진 객체 를 호출 하면 새로운 데이터베이스를 삽입하지 않고 해당 데이터베이스 레코드를 업데이트하고 save()
라는 이유를 설명합니다 create()
.
답변
@axtavt로 대답에 초점을 맞추고 있기 때문에 JPA
하지spring-data-jpa
쿼리를 통해 엔터티를 업데이트하면 저장이 효율적이지 않습니다. 두 개의 쿼리가 필요하기 때문에 다른 테이블을 조인하고 컬렉션이있는 컬렉션을로드 할 수 있기 때문에 쿼리가 매우 비쌀 수 있습니다. fetchType=FetchType.EAGER
Spring-data-jpa
업데이트 작업을 지원합니다.
Repository 인터페이스에서 메소드를 정의하고 @Query
and로 주석을 달아야합니다 @Modifying
.
@Modifying
@Query("update User u set u.firstname = ?1, u.lastname = ?2 where u.id = ?3")
void setUserInfoById(String firstname, String lastname, Integer userId);
@Query
사용자 지정 쿼리를 정의 @Modifying
하기위한 것이며이 spring-data-jpa
쿼리가 업데이트 작업이며 필요 executeUpdate()
하지 않음 을 알리기위한 것 executeQuery()
입니다.
다른 반환 유형을 지정할 수 있습니다
int
.-업데이트되는 레코드 수.
boolean
-업데이트중인 레코드가 있으면 true입니다. 그렇지 않으면 false입니다.
참고 : 트랜잭션 에서이 코드를 실행하십시오 .
답변
save () JPAfunction과 함께이 함수를 간단히 사용할 수 있지만, 매개 변수로 전송 된 오브젝트는 데이터베이스에 기존 ID를 포함해야합니다. 그렇지 않으면 ID가없는 오브젝트를 보낼 때 save ()가 행을 직접 추가하기 때문에 작동하지 않습니다. 기존 ID를 가진 개체를 보내면 데이터베이스에서 이미 찾은 열이 변경됩니다.
public void updateUser(Userinfos u) {
User userFromDb = userRepository.findById(u.getid());
// crush the variables of the object found
userFromDb.setFirstname("john");
userFromDb.setLastname("dew");
userFromDb.setAge(16);
userRepository.save(userFromDb);
}
답변
다른 사람들이 이미 언급했듯이 save()
자체에는 작성 및 업데이트 작업이 모두 포함되어 있습니다.
난 그냥 save()
방법 뒤에 무엇에 대한 보충을 추가하고 싶습니다 .
먼저의 확장 / 구현 계층을 보자 CrudRepository<T,ID>
.
좋아,에서 save()
구현을 확인하자 SimpleJpaRepository<T, ID>
.
@Transactional
public <S extends T> S save(S entity) {
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
보시다시피 ID가 존재하는지 여부를 먼저 확인합니다. 엔터티가 이미 존재 merge(entity)
하는 경우 방법으로 만 업데이트가 발생 하고 그렇지 않으면 방법으로 새 레코드가 삽입됩니다 persist(entity)
.
답변
spring-data-jpa 사용하면 save()
@DtechNet과 동일한 문제가 발생했습니다. 모든 사람들 save()
이 업데이트 대신 새로운 객체를 만들고 있음을 의미합니다 . 이를 해결하기 위해 version
엔터티 및 관련 테이블에 필드를 추가해야했습니다 .
답변
이것이 내가 문제를 해결 한 방법입니다.
User inbound = ...
User existing = userRepository.findByFirstname(inbound.getFirstname());
if(existing != null) inbound.setId(existing.getId());
userRepository.save(inbound);
답변
스프링 데이터 save()
방법은 새 항목 추가와 기존 항목 업데이트를 모두 수행하는 데 도움이됩니다.
그냥 전화하고 save()
인생을 즐기십시오 :))