2016-03-05 36 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。