JPA存储库保存:插入违反约束后,继续保存

问题描述 投票:1回答:1

我正在使用JPA存储库将简单的数据对象保存到数据库中。为了避免重复,我在多个字段上创建了唯一约束。如果现在应该保存根据唯一字段/约束的重复项,则要捕获异常,请记录该对象,然后应用程序应继续并保存下一个对象。但是在这里,我总是会收到此异常:“ org.hibernate.AssertionFailure:de.test.PeopleDBO条目中的null ID(发生异常后不要刷新Session)”。

通常,我了解休眠状态,但是我如何还原会话或开始新的会话以继续保存下一个数据对象。请看下面的代码:

PeopleDBO.java

@Entity
@Data
@Table(
        name = "PEOPLE", 
        uniqueConstraints = {@UniqueConstraint(columnNames = {"firstname", "lastname"}})
public class PeopleDBO {

    public PeopleDBO(String firstname, String lastname) {
        this.firstname = firstname;
        this.lastname = lastname;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String firstname;

    private String lastname;

}

测试:

public void should_save_people_and_ignore_constraint_violation(){
    final List<PeopleDBO> peopleList = Arrays.asList(
        new PeopleDBO("Georg","Smith"),
        new PeopleDBO("Georg","Smith"),
        new PeopleDBO("Paul","Smith")
    );

    peopleList.forEach(p -> {
        try {
            peopleRepository.save(p);
        } catch (DataIntegrityViolationException e) {
            log.error("Could not save due to constraint violation: {}",p);
        }
    }

    Assertions.assertThat(peopleRepository.count()).isEqualTo(2);
}

问题是,保存第二人后,唯一约束就被违反了。错误日志发生,并且在下一次调用peopleRepository.save()时,抛出了上述异常:

“” org.hibernate.AssertionFailure:de.test.PeopleDBO条目中的null id(在发生异常后不要刷新Session)“

我如何避免这种行为?如何清理会话或开始新会话?

非常感谢d。

---------编辑/新想法------我只是尝试了一些事情,发现可以实现PeopleRepositoryImpl,如下所示:

@Service
public class PeopleRepositoryImpl {

    final private PeopleRepository peopleRepository;

    public PeopleRepositoryImpl(PeopleRepository peopleRepository) {
        this.peopleRepository = peopleRepository;
    }

    @Transactional
    public PeopleDBO save(PeopleDBO people){
        return peopleRepository.save(people);
    }
}

在我的测试中,这工作得很好。 ...您怎么看?

java hibernate jpa spring-data-jpa unique-constraint
1个回答
1
投票

单笔交易

原因是所有插入都发生在一个事务中。由于此事务是atomic,因此它要么全部成功,要么失败,因此两者之间没有任何关系。

最干净的解决方案是在尝试插入人员之前检查是否存在人员:

public interface PeopleRespository {

    boolean existsByLastnameAndFirstname(String lastname, String firstname);
}

然后:

if (!peopleRepository.existsByLastnameAndFirstname(p.getLastname, p.getFirstname)) {
    peopleRepository.save(p);
}

每人一笔交易

的确是为每个人启动新交易。但是我不确定这样做会更有效,因为创建交易会产生额外的费用。

© www.soinside.com 2019 - 2024. All rights reserved.