簡體   English   中英

Spring JPA存儲庫:阻止保存更新

[英]Spring JPA repository: prevent update on save

我的user數據庫表如下所示:

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;
}

無論如何,如果已經使用了用戶名,則存儲庫只會進行更新,因為指定的標識符不為空。 這不是我想要的行為,我需要它拋出類似重復的條目異常。 有什么辦法可以預防嗎? 我必須自己做嗎? 例如:

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

當使用默認配置,並使用CrudRepository#save()JpaRepository#save() ,它將委托給EntityManager ,如果它是新實體則使用CrudRepository#save() persists()如果不是則使用merge()

在使用默認配置時,遵循以下策略來檢測實體狀態(新的或不是新的)以使用適當的方法如下:

  • 默認情況下,執行Property-ID檢查,如果為null ,則它是新實體,否則不是。
  • 如果實體實現Persistable則檢測將委托給實體實現的isNew()方法。
  • 有第三個選項,實現EntityInformation ,但需要進一步的自定義。

資源

因此,在您的情況下,當您使用用戶名作為ID ,並且它不為空時,Repository調用最終委托給EntityManager.merge()而不是persist() 所以有兩種可能的解決方案:

  • 使用不同的ID屬性,將其設置為null,並使用任何自動生成方法,或
  • make User實現Persistable並使用isNew()方法確定它是否是新實體。

如果由於某種原因,您不想修改實體,還可以更改修改刷新模式配置的行為。 默認情況下,在spring數據jpa中,hibernate flush模式設置為AUTO。 你想要做的是將它更改為COMMIT,並且要更改它的屬性是org.hibernate.flushMode 您可以通過覆蓋@Configuration類中的EntityManagerFactoryBean來修改此配置。


如果您不想弄亂EntityManager的配置,可以使用JpaRepository#flush()JpaRepository#saveAndFlush()方法將掛起的更改提交到數據庫。

而不是this.userRepository.save(用戶),你可以嘗試this.userRepository.saveAndFlush(用戶)

我最好的猜測是,它將使您的實體分離,並且根據JPA文檔,它聲明當傳入的對象是分離的實體時,persist方法拋出EntityExistsException。 或者在刷新持久性上下文或提交事務時的任何其他PersistenceException。

如果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/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM