[java] spring-data-jpa를 사용하여 엔티티를 어떻게 업데이트합니까?

문제는 거의 모든 것을 말합니다. JPARepository를 사용하여 엔티티를 어떻게 업데이트합니까?

JPARepository에는 실제로 저장 또는 작성 중인지 알려주지 않는 저장 메소드 만 있습니다. 예를 들어, 나는 세 개의 필드가 데이터베이스 사용자에게 간단한 개체를 삽입 : firstname, lastnameage:

 @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는 기본 키로 정의됩니다. 이후 firstnamelastname기본 키의 일부하지, 당신은 치료에 JPA를 말할 수 없다 User같은과의 firstnames와 lastname서로 다른 경우 동일로의 userId들.

따라서 and 로 User식별 된 정보 를 업데이트 하려면 쿼리 로 식별 한 다음 찾은 객체의 해당 필드를 변경해야합니다. 이러한 변경 사항은 트랜잭션이 끝날 때 데이터베이스에 자동으로 플러시되므로 변경 사항을 명시 적으로 저장하기 위해 아무 것도 할 필요가 없습니다.firstnamelastnameUser

편집하다:

아마도 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 인터페이스에서 메소드를 정의하고 @Queryand로 주석을 달아야합니다 @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()인생을 즐기십시오 :))