복붙노트

[SPRING] 스프링 JPA 저장소 : 저장시 업데이트 방지

SPRING

스프링 JPA 저장소 : 저장시 업데이트 방지

내 사용자 DB 테이블은 다음과 같습니다.

CREATE TABLE user (
    username VARCHAR(32) PRIMARY KEY,
    first_name VARCHAR(256) NOT NULL,
    last_name VARCHAR(256) NOT NULL,
    password VARCHAR(32) NOT NULL,
    enabled BOOL
) ENGINE = InnoDB;

이것은 내 엔티티의 필드 정의입니다.

@Entity
public class User implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @Column(nullable = false)
    private String username;

    @Column(nullable = false)
    private String firstName;

    @Column(nullable = false)
    private String lastName;

    @Column(nullable = false)
    private String password;

필드 username은 내 테이블 / 엔티티의 키이며 그 값을 설정하는 것은 나에게 달려있다. 다른 사용자를 생성해야 할 때 서비스에서 이렇게합니다.

public User insertUserImpl(String username, String firstName, String lastName) {
    Assert.hasText(username);
    Assert.hasText(firstName);
    Assert.hasText(lastName);

    String password = UUID.randomUUID().toString().substring(0, 4); // temp
    User user = new User(username, password);
    user.setFirstName(firstName);
    user.setLastName(lastName);
    user.setEnabled(false);
    this.userRepository.save(user);
    // FIXME - assegnare un ruolo
    return user;
}

어쨌든 사용자 이름이 이미 사용 된 경우 저장소는 지정된 식별자가 null이 아니기 때문에 업데이트 만 수행합니다. 이것은 내가 원하는 행동이 아니며, 중복 된 항목 예외와 같은 것을 던져야합니다. 그것을 막을 수있는 방법이 있습니까? 혼자서해야합니까? 예 :

User user = this.userRepository.findOne(username);
if(user != null) {
    throw new RuntimeException("Username already taken"); // FIXME - eccezione applicativa
}

해결법

  1. ==============================

    1.기본 설정을 사용하고 CrudRepository # save () 또는 JpaRepository # save ()를 사용하는 경우 EntityManager에 위임하여 새 엔티티 인 경우에는 persistists ()를 사용하고, 그렇지 않으면 merge ()를 사용합니다.

    기본 설정을 사용하고 CrudRepository # save () 또는 JpaRepository # save ()를 사용하는 경우 EntityManager에 위임하여 새 엔티티 인 경우에는 persistists ()를 사용하고, 그렇지 않으면 merge ()를 사용합니다.

    기본 설정을 사용할 때, 새로운 메소드 또는 아닌 메소드를 사용하여 엔티티 상태를 감지하는 전략은 다음과 같습니다.

    출처

    따라서 ID로 사용자 이름을 사용하면서 null이 아니기 때문에 저장소 호출이 persist () 대신 EntityManager.merge ()로 위임됩니다. 따라서 가능한 솔루션은 두 가지입니다.

    어떠한 이유로 엔티티를 수정하지 않으려는 경우 플러시 모드 구성을 수정하는 동작을 변경할 수도 있습니다. 기본적으로 스프링 데이터 jpa에서 최대 절전 모드는 자동으로 설정됩니다. 당신이하고 싶은 것은 그것을 COMMIT으로 바꾸고 그것을 변경하는 속성은 org.hibernate.flushMode이다. @Configuration 클래스의 EntityManagerFactoryBean을 재정 의하여이 구성을 수정할 수 있습니다.

    EntityManager의 설정을 엉망으로 만들고 싶지 않으면 JpaRepository # flush () 또는 JpaRepository # saveAndFlush () 메소드를 사용하여 보류중인 변경 사항을 데이터베이스에 적용 할 수 있습니다.

  2. ==============================

    2.대신에     this.userRepository.save (user) , 너 시도 할 수있어     this.userRepository.saveAndFlush (user)

    대신에     this.userRepository.save (user) , 너 시도 할 수있어     this.userRepository.saveAndFlush (user)

    내 생각 엔 JPA 문서에 따라 엔티티를 분리하고 전달 된 객체가 분리 된 엔티티 일 때 엔티티 메소드에 의해 EntityExistsException이 throw됩니다. 또는 지속성 컨텍스트가 플러시되거나 트랜잭션이 커밋 될 때 다른 모든 PersistenceException.

  3. ==============================

    3.userRepository가 CrudRepository를 확장하면 existsById (ID primaryKey)를 사용하여이를 테스트 할 수 있습니다.

    userRepository가 CrudRepository를 확장하면 existsById (ID primaryKey)를 사용하여이를 테스트 할 수 있습니다.

    if(userRepository.existsById(username)){
        //Throw your Exception
    } else {
        this.userRepository.save(user);
    }
    

    https://docs.spring.io/spring-data/jpa/docs/current/reference/html/을 참조하십시오.

  4. from https://stackoverflow.com/questions/35817584/spring-jpa-repository-prevent-update-on-save by cc-by-sa and MIT license