在Spring JPA中强制执行主键约束

时间:2017-11-30 09:30:39

标签: hibernate jpa spring-data spring-data-jpa derby

我使用的是由嵌入式内存数据库支持的Spring JPA,特别是Apache Derby。

简单地说,我有一个像这样的实体类:

@Entity
public class Person {

    @Id
    @NotNull
    @Column(unique = true, updatable = false, name = "PERSON_ID")
    private Long personId;

    @NotNull
    @Size(min = 1)
    private String name;

    public Person() {
    } 
    //continue....

在@Service组件中我有一个这样的方法:

@Autowired
private PersonRepository personRepository;

@Override
public void addPerson(Person person)  {
        personRepository.save(movie);
}

其中存储库定义如下:

public interface PersonRepository extends CrudRepository<Person, Long> { }

问题如下:未按照我的预期强制执行主键约束。

更具体地说,如果我有两个具有相同键的Person对象:

Person person1 = new Person(1L, "Johan");
Person person2 = new Person(1L, "Tom");

我按顺序调用add方法:

serviceObject.addPerson(person1);
serviceObject.addPerson(person2);

将会发生 personRepository.save(movie)方法将两次具有相同ID的Person保存,从而覆盖以前的记录。最后只有一个人拥有该ID,其名称为“Tom”。我使用 findOne 方法检索记录,如下所示:

public Person getPersonById(long personId) {
    Person person = personRepository.findOne(personId);

但是我原本期望第二次尝试因为一些PrimaryKey Constraint Violation而失败,名称没有从“Johan”更改为“Tom”。

问题

  • 为什么会这样?
  • 我知道我可以在数据库级别强制执行此规则。这是实现它的唯一途径吗?在我的情况下,使用Apache Derby,我可以实现这一目标吗?或者如何在JPA级别强制执行通常的主键约束,以便拒绝具有重复键的记录而不是覆盖之前的记录?

P.S。:我有兴趣手动插入主键,因此 @GeneratedValue 或任何其他原则上无法传递两次相同键的机制都不是一种选择。

2 个答案:

答案 0 :(得分:2)

如果你看一下save方法的实现,

@Transactional
public <S extends T> S save(S entity) {

    if (entityInformation.isNew(entity)) {
        em.persist(entity);
        return entity;
    } else {
        return em.merge(entity);
    }
}

如果记录已经存在,它正在尝试合并。在您的情况下,将主键生成保留为spring并在代码中使用生成的id。

答案 1 :(得分:1)

在spring数据jpa中,当使用非自动生成的id保存无管理实体时,jpa将查找id,如果数据库中存在id,则会将save视为update,因此您只需更新记录< / p>