SQL state [S000169]; error code [1206]; Microsoft 分布式事务处理协调器(MS DTC)已取消此分布式事务

项目中有个流程最后提交审批的时候由于后台处理比较复杂,事务处理没有优化,导致数据库中对同一张表即update又select,产生了几个死锁,但是死锁过一会就自动消失了。报错如下:

2018-08-07 08:58:08.302 [http-nio-9999-exec-6] ERROR o.a.e.i.interceptor.CommandContext - Error while closing command context
org.springframework.jdbc.UncategorizedSQLException: PreparedStatementCallback; uncategorized SQLException for SQL [ select distinct t.name,e.employeeId,c.date from  AttendanceHolidayType t left join AttendanceCalendar c on t.attendanceHolidayTypeId=c.attendanceHolidayTypeId left join AttendanceEmpRank e on e.corporationId = c.corporationId where cast(e.employeeId as varchar(36)) = ? and  convert(varchar(10),c.[Date] , 120) = ? ]; SQL state [S000169]; error code [1206]; Microsoft 分布式事务处理协调器(MS DTC)已取消此分布式事务。; nested exception is com.microsoft.sqlserver.jdbc.SQLServerException: Microsoft 分布式事务处理协调器(MS DTC)已取消此分布式事务。
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:84)
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:649)
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:684)
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:716)
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:726)
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:776)

原本测试时候是没有问题的,后来上线测试,由于用户量多了一些,导致事物处理的时候产生了错误。所以假如你的也有类似的错误,你可以查看一下你的后台代码逻辑是否会产生事务锁。

下面是我的代码,由于公司保密原因,代码有删减,但大概意思还是有的。

for (ProcHrRankChangeDtDto procHrRankChangeDtDto : procHrRankChangeDtList) {
            List<AttendanceRankChange> rankChangeList = new ArrayList<AttendanceRankChange>();
            ProcHrRankChangeDtDto dt = new ProcHrRankChangeDtDto();
            BeanUtils.copyProperties(procHrRankChangeDtDto, dt);
            List<Date> dateList = DateUtil.findDateListByTwoDate(bTime, eTime);
            for (int i=0;i<dateList.size();i++) {
                Date date = dateList.get(i);
                String rankTypeId = dt.getRankType();
                //查询语句
                String employeeId = map.get(dt.getEmpJobNumber()).getEmployeeId();
                if("true".equals(dt.getJumpHoliday())||"Y".equals(dt.getJumpHoliday())) {
                    List<AttendanceRankDto> nameList = attendanceRankService.getNameByCalendarHolidayEmpRank(employeeId, date);
                    if(nameList.size()>0 && BpmConsts.HR_DEFAULTHOLIDAYTYPE_NAME_004.equals(nameList.get(0).getName())) {
                        rankTypeId = dt.getHolidayRankType();
                        holidayTypeId = BpmConsts.HR_DEFAULTHOLIDAYTYPE_004;
                    }
                }
                if("true".equals(dt.getJumpFestival())||"Y".equals(dt.getJumpFestival())) {
                    List<AttendanceRankDto> nameList = attendanceRankService.getNameByCalendarHolidayEmpRank(employeeId, date);
                    if(nameList.size()>0 && BpmConsts.HR_DEFAULTHOLIDAYTYPE_NAME_003.equals(nameList.get(0).getName())) {
                        rankTypeId = dt.getFestivalRankType();
                        holidayTypeId = BpmConsts.HR_DEFAULTHOLIDAYTYPE_003;
                    }
                }
                Date lastModifiedDate = new Date();
                String lastModifiedBy = map.get(AppUtil.getUserInfoContext().getEmployeeNo()).getEmployeeId();
                //修改语句
                attendanceEmpRankService.updateEmpRankByDao(rankTypeId, holidayTypeId,lastModifiedDate,lastModifiedBy, employeeId, date);
                rankChange.setEmployeeId(employeeId);
                //查询
                String oldATRankId = null;
                AttendanceEmpRankDto empRankDto = attendanceEmpRankService.findEmpRankByEmployeeAndDate(employeeId, date);
                if(empRankDto!=null) {
                    oldATRankId = empRankDto.getAttendanceRankId();
                }
                rankChangeList.add(rankChange);
            }
            //新增
            attendanceRankChangeService.saveAttendanceRankChangeList(rankChangeList);
        }

我的代码是在foreach里面嵌套一个foreach语句,在里层的foreach有sql多表查询,又有update语句。这时候程序执行就比较慢了。由于表中数据量比较大,用map存放的方式也不是太理想,我把最里层的查询语句去掉,在第一层循环用map存放对象。
然后把循环里面的update全部用list保存对象,在循环结束后用JPA执行update集合。

修改后的代码

for (ProcHrRankChangeDtDto procHrRankChangeDtDto : procHrRankChangeDtList) {
            ProcHrRankChangeDtDto dt = new ProcHrRankChangeDtDto();
            BeanUtils.copyProperties(procHrRankChangeDtDto, dt);
            List<Date> dateList = DateUtil.findDateListByTwoDate(bTime, eTime);
        String employeeId0 = map.get(dt.getEmpJobNumber()).getEmployeeId();
        Map<String,AttendanceRankDto> mapp = new HashMap<String,AttendanceRankDto>();
        if("true".equals(dt.getJumpHoliday()) || "Y".equals(dt.getJumpHoliday()) || "true".equals(dt.getJumpFestival()) || "Y".equals(dt.getJumpFestival())) {
            List<AttendanceRankDto> nameList0 = attendanceRankService.getNameByCalendarHolidayEmpRank(employeeId0, null);
            for (AttendanceRankDto attendanceRankDto : nameList0) {
                mapp.put(DateUtil.getDate(attendanceRankDto.getDate()), attendanceRankDto);
            }
        }

        for (int i=0;i<dateList.size();i++) {
            Date date = dateList.get(i);
            if(mapp.size()>0 && mapp.get(DateUtil.getDate(date))!=null) {
                if("true".equals(dt.getJumpHoliday())||"Y".equals(dt.getJumpHoliday())) {
                    if(BpmConsts.HR_DEFAULTHOLIDAYTYPE_NAME_004.equals(mapp.get(DateUtil.getDate(date)).getName())) {
                        rankTypeId = dt.getHolidayRankType();
                        holidayTypeId = BpmConsts.HR_DEFAULTHOLIDAYTYPE_004;
                    }
                }
                if("true".equals(dt.getJumpFestival())||"Y".equals(dt.getJumpFestival())) {
                    if(BpmConsts.HR_DEFAULTHOLIDAYTYPE_NAME_003.equals(mapp.get(DateUtil.getDate(date)).getName())) {   
                        rankTypeId = dt.getFestivalRankType();
                        holidayTypeId = BpmConsts.HR_DEFAULTHOLIDAYTYPE_003;
                    }
                }
            }
            AttendanceEmpRank entity = attce.findOne(employeeId, date);
            AttEmpRankDto empDto = new AttEmpRankDto();
            empDto.setDate(date);
            dtoList.add(empDto);
            eList.add(entity);
            rankChange.setOldATRankId(oldATRankId);
            rankChangeList.add(rankChange);
        }
    }
    for (AttendanceEmpRank entity : eList) {
        for (AttendanceEmpRankDto dto : dtoList) {
            if(dto.getEmployeeId().equals(entity.getEmployeeId()) && DateUtil.getDate(dto.getDate()).equals(DateUtil.getDate(entity.getDate()))) {
                entity.setAttendanceRankId(dto.getAttendanceRankId());
                break;
            }
        }
    }
    atte.updateList(eList);
    ae.saveList(rankChangeList);

综合起来,我要表达的意思就是在代码里能减少查询语句就尽量减少,可以一下子全查出来存放到集合里面。对于同张表,尽量不要查询修改混合来操作。
使用jpa时,每当执行set()方法时,jpa就会执行update语句。

假如还不行,那就可能是别人说的什么服务器一类的问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值