有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java JPARepository save:在插入约束冲突后继续保存

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

一般来说,我了解hibernate在做什么,但我知道如何恢复会话或启动新会话以继续保存下一个数据对象。请查看以下代码:

这里有人。爪哇

@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条目中的空id(发生异常后不要刷新会话)”

我怎样才能避免这种行为?如何清理会话或启动新会话

非常感谢 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);
    }
}

这在我的测试中效果很好。。。你觉得呢


共 (1) 个答案

  1. # 1 楼答案

    一笔交易

    原因是所有插入都发生在一个事务中。由于该事务是原子的,它要么完全成功,要么失败,两者之间没有任何区别

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

    public interface PeopleRespository {
    
        boolean existsByLastnameAndFirstname(String lastname, String firstname);
    }
    

    然后:

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

    每人一次交易

    另一种选择是为每个人启动一项新的交易。但我不确定它是否会更有效率,因为创建交易需要额外的成本