Sprinboot Data JPA更新出现错误 Duplicate entry ‘xxxx-xxx‘ for key ‘customer_menu_id‘ 问题排查解决

1.描述

完整的错误日志:

 WARN o.h.e.j.s.SqlExceptionHelper:145: SQL Error: 1062, SQLState: 23000
2022-03-01_15:28:49 [http-nio-8080-exec-1] ERROR o.h.e.j.s.SqlExceptionHelper:147: Duplicate entry '75302-16969' for key 'customer_menu_id'
2022-03-01_15:28:49 [http-nio-8080-exec-1] ERROR c.d.a.c.f.RestResponseEntityExceptionHandler:81: could not execute statement; SQL [n/a]; constraint [customer_menu_id]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [customer_menu_id]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
 Duplicate entry '75302-16969' for key 'customer_menu_id'
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)

其实抛出这种日志异常的问题就是,表中有重复的数据,无法添加新的数据。

2.出现场景

出现这种场景的原因是,我做了一个更新操作,是先把之前的数据删除,然后在添加新的数据进去,由于代码中使用了事务注解

导致,在提交的时候,数据并没有删除完整,然后添加的时候就出现了数据重复的错误。

请看实例代码:

    //由于方法需要删除,所有加了事务注解
    @Transactional(rollbackFor = Exception.class)
    public TAuthRole updateRole(TAuthRole tAuthRole) {
      //查询需要删除的数据,然后全部删除掉
        this.tAuthRole2PermissionRepository.delete(this.tAuthRole2PermissionRepository.findByRoleId(
                tAuthRole.getRoleId()));

        String type = getRoleType(policy.getStatements());
        tAuthRoleRepository.updateType(tAuthRole.getRoleId(), type);
        //更新添加新的数据进去
        TAuthRole authRole = tAuthRoleRepository.save(tAuthRole);
        return authRole;
    }

代码逻辑很简单,先删除然后在添加数据进去,但是这里问题就是,事务在这一个方法中,先删除的数据没有提交,所以导致有外键关联的数据出现重复报错。

3.源码分析解决

由于事务的原因,我们在删除的时候,事务并没有提交,而是在这个方法执行完后在去提交,这就导致,添加的时候,数据还存在,所以我们能不能在,delete这个方法的时候,删除就立即提交呢,这样子,后面添加的时候,就不会出现这个重复的问题了。延着这个思路,我们来看看有没有方法能解决,或者我们看看jpa有没有方法帮我们解决。

delete接口方法:

void delete(ID var1);

void delete(T var1);

void delete(Iterable<? extends T> var1);

实现:由于这里是批量删除,我们直接看批量删除的实现代码

代码在 SimpleJpaRepository 类中:

    @Transactional
    public void delete(Iterable<? extends T> entities) {
        Assert.notNull(entities, "The given Iterable of entities not be null!");
        Iterator var2 = entities.iterator();

        while(var2.hasNext()) {
            T entity = var2.next();
            this.delete(entity);
        }

    }

可以看到,实现很简单,就是一个迭代删除,没有任何的处理

deleteInBatch:方法实现:

    @Transactional
    public void deleteInBatch(Iterable<T> entities) {
        Assert.notNull(entities, "The given Iterable of entities not be null!");
        if (entities.iterator().hasNext()) {
            QueryUtils.applyAndBind(QueryUtils.getQueryString("delete from %s x", this.entityInformation.getEntityName()), entities, this.em).executeUpdate();
        }
    }

可以看出来这个方法最大的区别就在于executeUpdate 删除就提交,这个就很满足我们上面的那个思路了。

解决方法:

把delete 方法改为 deleteInBatch 即可解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值