2016-03-05 63 views
3

user DB表看起來像這樣:春天JPA倉庫:防止更新上保存

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 
} 
+0

如果它正在更新值而不是進行新的插入,這意味着它認爲它是同一個對象,但是具有更新的值,您是否在重複使用該對象以進行多次插入?你使用什麼沖水模式? – saljuama

+0

我不是在重複使用同一個對象,我編輯了文本,以便您可以看到完整的方法。我如何檢查我的沖洗模式?我認爲這是Spring Boot的默認設置,我沒有對它做任何設置。 – Antonio

回答

8

當使用默認配置,並使用CrudRepository#save()JpaRepository#save()將委託給EntityManager爲使用persists(),如果它是一個新的實體,或者merge()如果事實並非如此。

策略隨後檢測所述實體狀態,新的或沒有,使用此時,相應的方法中,使用缺省配置時如下:

  • 缺省情況下,執行屬性-ID檢查,如果是null,那麼它是一個新的實體,否則不是。
  • 如果實體執行Persistable,則檢測將委託給實體實施的isNew()方法。
  • 有第三個選項,實施EntityInformation,但需要進一步的自定義。

你的情況source

因此,當你正在使用的用戶名作爲ID,它不爲空,則庫通話結束委派EntityManager.merge(),而不是persist()。因此,有兩種可能的解決方案:

  • 使用diferent ID屬性,將其設置爲null,並使用任何自動生成方法,或
  • 建立用戶實現Persistable並使用isNew()方法,以確定它是否是一個新的實體或沒有。

如果由於某種原因,你不想修改你的實體,您也可以改變行爲調節沖水模式配置。默認情況下,在彈簧數據jpa中,休眠模式被設置爲AUTO。你想要做的是將其更改爲COMMIT,並將其更改爲org.hibernate.flushMode。您可以通過覆蓋@Configuration類中的EntityManagerFactoryBean來修改此配置。


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

0

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

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