多线程事务回滚

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(

最近开发,有地方需要用到多线程,每个线程里面处理多个方法,过程中遇到了一个问题,我们使用平时的@Transactional注解,就是当前一个方法执行完成(比如插入操作),后一个方法是不会事务回滚的。当时觉得很不可思议,后来经过半天时间,终于挖出原因,并成功解决。
我这里先说明原因:多线程底层连接数据库的时候,时使用的线程变量(TheadLocal),所以,开多少线程理论上就会建立多少个连接,每个线程有自己的连接,事务肯定不是同一个了。
解决办法:我强制手动把每个线程的事务状态放到一个同步集合里面。然后如果有单个异常,循环回滚每个线程。
代码如下:

1、注入

     @Autowired
     private PlatformTransactionManager transactionManager;

2、多线程操作

@Override
    public String importBatch(String url,String taskId) {
        if (StringUtils.isEmpty(taskId)){
            return "请选择外呼任务";
        }

        Task task = taskService.selectById(taskId);
        if (task == null){
            return "外呼任务不存在,Id为:"+taskId;
        }

        String filePath = tmpFilePath + url;
        List customers = ExcelTemplateExportUtil.importExcel(filePath, 0, 1, Customer.class);
        if (CollectionUtils.isEmpty(customers)){
            return "Excel数据不能为空";
        }

        int totalCustomerCnt = customers.size();
        if (totalCustomerCnt > 5000){
            return "最多支持5000条,请分批导入";
        }

        //过滤掉空属性
        List phones = new ArrayList<>();
        List customersNotNull = new ArrayList<>();
        String corpCode = ExecutionContext.getCorpCode();
        String userId = ExecutionContext.getUserId();
        for (Customer customer : customers) {
            String phone = customer.getPhone();
            if (StringUtils.isEmpty(customer.getName()) || StringUtils.isEmpty(phone)){
                continue;
            }

            customersNotNull.add(customer);
            phones.add(phone);
        }

        String result = "";
        int notNullSize = customersNotNull.size();
        int size = customers.size();
        if (notNullSize < size){
            result += "存在客户名称或手机号码为空:"+(size - notNullSize)+"条记录";
        }

        //过滤手机号重复的
        List validCustomers = new ArrayList<>();
        List repeatCustomers = this.selectList(new EntityWrapper().eq("corp_code", corpCode).in("phone", phones));
        if (CollectionUtils.isNotEmpty(repeatCustomers)){
            result += "
存在手机号码重复:"+(repeatCustomers.size())+"条记录"; List repeatPhones = new ArrayList<>(repeatCustomers.size()); for (Customer repeatCustomer : repeatCustomers) { repeatPhones.add(repeatCustomer.getPhone()); } for (Customer customer : customersNotNull) { if (repeatPhones.contains(customer.getPhone())){ continue; } validCustomers.add(customer); } }else { validCustomers = customersNotNull; } for (Customer validCustomer : validCustomers) { validCustomer.setCustomerType(UkConstant.CUSTOMER_TYPE_INDIVIDUALITY); validCustomer.setChannelType(UkConstant.CHANNEL_TYPE_CALL_OUT); validCustomer.setCalloutTaskStatus(0); validCustomer.setCalloutDistributeStatus(0); validCustomer.setCalloutTaskId(taskId); validCustomer.setCorpCode(corpCode); validCustomer.setCreater(userId); } if (CollectionUtils.isEmpty(validCustomers)){ return "成功导入:"+ 0 +"条记录
"+result; } List> customersList = new ArrayList<>(); int total = validCustomers.size(); int threads = 5; int oneSize = total/5 +1; int start = 0; int end = 0; for (int i = 0; i transactionStatuses = Collections.synchronizedList(new ArrayList()); CountDownLatch latch= new CountDownLatch(threads); for (int i = 0; i < threads; i++) { int finalI = i; ThreadPoolUtils.fixedThreadPool.execute(new Runnable() { @Override public void run() { DefaultTransactionDefinition def = new DefaultTransactionDefinition(); def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); // 事物隔离级别,开启新事务,这样会比较安全些。 TransactionStatus status = transactionManager.getTransaction(def); // 获得事务状态 transactionStatuses.add(status); try{ //执行业务逻辑 插入或更新操作 improtInsertBath(corpCode,userId,customersList.get(finalI)); }catch(Exception e){ e.printStackTrace(); //异常 回滚所有事务 for (TransactionStatus transactionStatus:transactionStatuses) { transactionStatus.setRollbackOnly(); } } latch.countDown(); } }); } try { latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } //更新外呼任务客户总数 customerCnt、未分配客户数 notDistributeCnt、未拨打数 not_call_cnt task.setCustomerCnt(task.getCustomerCnt()+total); task.setNotDistributeCnt(task.getNotDistributeCnt()+total); task.setNotCallCnt(task.getNotCallCnt()+total); taskService.updateById(task); return "成功导入:"+ total +"条记录
"+result; }

 

3、整体类

package com.ps.uzkefu.apps.crm.service.impl;

import com.baomidou.mybatisplus.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.ps.uzkefu.apps.callout.entity.Task;
import com.ps.uzkefu.apps.callout.service.TaskService;
import com.ps.uzkefu.apps.crm.entity.Customer;
import com.ps.uzkefu.apps.crm.entity.CustomerRecord;
import com.ps.uzkefu.apps.crm.mapper.CustomerDao;
import com.ps.uzkefu.apps.crm.service.CustomerRecordService;
import com.ps.uzkefu.apps.crm.service.CustomerService;
import com.ps.uzkefu.apps.oms.account.entity.DefinedField;
import com.ps.uzkefu.apps.oms.account.entity.DefinedFieldOption;
import com.ps.uzkefu.apps.oms.account.entity.DefinedFieldValue;
import com.ps.uzkefu.apps.oms.account.service.DefinedFieldOptionService;
import com.ps.uzkefu.apps.oms.account.service.DefinedFieldService;
import com.ps.uzkefu.apps.oms.account.service.DefinedFieldValueService;
import com.ps.uzkefu.apps.oms.account.service.UserService;
import com.ps.uzkefu.base.BaseServiceImpl;
import com.ps.uzkefu.common.ExecutionContext;
import com.ps.uzkefu.common.UkConstant;
import com.ps.uzkefu.util.DateUtil;
import com.ps.uzkefu.util.ExcelTemplateExportUtil;
import com.ps.uzkefu.util.ThreadPoolUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.executor.BatchExecutorException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.sql.BatchUpdateException;
import java.util.*;
import java.util.concurrent.CountDownLatch;

/**
 * 

* 客户 服务实现类 *

* * @author WuZhiWei * @since 2018-07-06 */ @Transactional(rollbackFor = {Exception.class}) @Service public class CustomerServiceImpl extends BaseServiceImpl implements CustomerService { @Autowired private DefinedFieldValueService definedFieldValueService; @Autowired private DefinedFieldService definedFieldService; @Autowired private DefinedFieldOptionService definedFieldOptionService; @Autowired private CustomerRecordService customerRecordService; @Autowired private UserService userService; @Autowired private TaskService taskService; @Autowired private CustomerDao customerDao; @Autowired private PlatformTransactionManager transactionManager; @Value("${tmp.file.path}") private String tmpFilePath; @Override public String saveOrUpdate(Customer customer) { String id = customer.getId(); String phone = customer.getPhone(); String corpCode = ExecutionContext.getCorpCode(); customer.setCorpCode(corpCode); if (StringUtils.isEmpty(id)){ Customer selectOne = this.selectOne(new EntityWrapper(). eq("corp_code", corpCode).eq("phone", phone)); if (selectOne != null){ return "联系号码已存在"; } } Customer selectOne = this.selectOne(new EntityWrapper(). eq("corp_code", corpCode).eq("phone", phone) .where("id !={0}",id)); if (selectOne != null){ return "联系号码已存在"; } if (StringUtils.isEmpty(customer.getCorpName())){ customer.setCustomerType(UkConstant.CUSTOMER_TYPE_INDIVIDUALITY); }else { customer.setCustomerType(UkConstant.CUSTOMER_TYPE_CORP); } if (StringUtils.isEmpty(customer.getUserId())){ customer.setUserId(ExecutionContext.getUserId()); } //自定义属性 List definedFieldValues = customer.getDefinedFieldValues(); //变更记录 String updateRecord = getUpdateRecord(customer, id, corpCode, definedFieldValues); customer.setAssignDate(new Date()); this.insertOrUpdate(customer); if (StringUtils.isEmpty(id)){ id = customer.getId(); } if (StringUtils.isNotEmpty(updateRecord)){ CustomerRecord customerRecord = new CustomerRecord(UkConstant.RECORD_TYPE_UPDATE,updateRecord,null,null,null,id); customerRecordService.insert(customerRecord); } //自定义保存或更新处理 if (CollectionUtils.isNotEmpty(definedFieldValues)){ for (DefinedFieldValue fieldValue : definedFieldValues) { fieldValue.setResourceId(id); } definedFieldValueService.delete(new EntityWrapper().eq("resource_id",id)); definedFieldValueService.insertBatch(definedFieldValues); } return ""; } private String getUpdateRecord(Customer customer, String id, String corpCode, List definedFieldValues) { String recordContent = ""; if (StringUtils.isNotEmpty(id)){ Customer customerDb = this.selectById(id); Map uidNameMap = userService.getAllUidNameMap(); recordContent = dealUpdate("客户姓名",customer.getName(),customerDb.getName(),recordContent); recordContent = dealUpdate("公司名称",customer.getCorpName(),customerDb.getCorpName(),recordContent); recordContent =dealUpdate("联系号码",customer.getPhone(),customerDb.getPhone(),recordContent); recordContent =dealUpdate("联系邮箱",customer.getEmail(),customerDb.getEmail(),recordContent); recordContent =dealUpdate("微信",customer.getWx(),customerDb.getWx(),recordContent); recordContent =dealUpdate("QQ",customer.getQq(),customerDb.getQq(),recordContent); recordContent =dealUpdate("所在省",customer.getProvince(),customerDb.getProvince(),recordContent); recordContent =dealUpdate("所在市",customer.getCity(),customerDb.getCity(),recordContent); recordContent =dealUpdate("描述",customer.getDescription(),customerDb.getDescription(),recordContent); recordContent =dealUpdate("所属员工",uidNameMap.get(customer.getUserId()),uidNameMap.get(customerDb.getUserId()),recordContent); if (CollectionUtils.isNotEmpty(definedFieldValues)){ Map fieldIdValueMap = new HashMap<>(); for (DefinedFieldValue fieldValue : definedFieldValues) { fieldIdValueMap.put(fieldValue.getFieldId(),fieldValue.getFieldValue()); } Map fieldIdValueMapDb = new HashMap<>(); List definedFieldValuesDb = definedFieldValueService.selectList(new EntityWrapper(). eq("corp_code", corpCode).eq("resource_id", id)); if (CollectionUtils.isNotEmpty(definedFieldValuesDb)){ for (DefinedFieldValue fieldValue : definedFieldValuesDb) { fieldIdValueMapDb.put(fieldValue.getFieldId(),fieldValue.getFieldValue()); } } List definedFields = definedFieldService.selectList(new EntityWrapper(). eq("corp_code", corpCode).eq("biz_type", UkConstant.DEFINED_BIZ_TYPE_CRM)); List fieldOptions = definedFieldOptionService.selectList(new EntityWrapper().eq("corp_code", corpCode)); Map optionIdNameMap; if (CollectionUtils.isEmpty(fieldOptions)){ optionIdNameMap = MapUtils.EMPTY_MAP; }else { optionIdNameMap = new HashMap<>(fieldOptions.size()); } for (DefinedFieldOption option : fieldOptions) { optionIdNameMap.put(option.getId(),option.getOptionName()); } if (CollectionUtils.isNotEmpty(definedFields)){ for (DefinedField field : definedFields) { String fieldName = field.getFieldName(); String fieldType = field.getFieldType(); String fieldId = field.getId(); String pre = fieldIdValueMapDb.get(fieldId); if (pre == null){ pre = ""; } String now = fieldIdValueMap.get(fieldId); if (now == null){ now = ""; } if (UkConstant.DEFINED_FIELD_TYPE_SELECT.equals(fieldType) || UkConstant.DEFINED_FIELD_TYPE_RADIO.equals(fieldType) || UkConstant.DEFINED_FIELD_TYPE_CHECKBOX.equals(fieldType)){ pre = optionIdNameMap.get(pre); now = optionIdNameMap.get(now); } recordContent = dealUpdate(fieldName,now,pre,recordContent); } } } }else { recordContent = "创建了客户"; } return recordContent; } private String dealUpdate(String label,String now,String pre,String result){ String preStr = pre; if (StringUtils.isEmpty(pre)){ pre = ""; preStr = "<空>"; } String nowStr = now; if (StringUtils.isEmpty(now)){ now = ""; nowStr = "<空>"; } if (now.equals(pre)){ return result; } result += label + ":" + preStr + "-->" + nowStr+"
"; return result; } @Override public String importBatch(String url,String taskId) { if (StringUtils.isEmpty(taskId)){ return "请选择外呼任务"; } Task task = taskService.selectById(taskId); if (task == null){ return "外呼任务不存在,Id为:"+taskId; } String filePath = tmpFilePath + url; List customers = ExcelTemplateExportUtil.importExcel(filePath, 0, 1, Customer.class); if (CollectionUtils.isEmpty(customers)){ return "Excel数据不能为空"; } int totalCustomerCnt = customers.size(); if (totalCustomerCnt > 5000){ return "最多支持5000条,请分批导入"; } //过滤掉空属性 List phones = new ArrayList<>(); List customersNotNull = new ArrayList<>(); String corpCode = ExecutionContext.getCorpCode(); String userId = ExecutionContext.getUserId(); for (Customer customer : customers) { String phone = customer.getPhone(); if (StringUtils.isEmpty(customer.getName()) || StringUtils.isEmpty(phone)){ continue; } customersNotNull.add(customer); phones.add(phone); } String result = ""; int notNullSize = customersNotNull.size(); int size = customers.size(); if (notNullSize < size){ result += "存在客户名称或手机号码为空:"+(size - notNullSize)+"条记录"; } //过滤手机号重复的 List validCustomers = new ArrayList<>(); List repeatCustomers = this.selectList(new EntityWrapper().eq("corp_code", corpCode).in("phone", phones)); if (CollectionUtils.isNotEmpty(repeatCustomers)){ result += "
存在手机号码重复:"+(repeatCustomers.size())+"条记录"; List repeatPhones = new ArrayList<>(repeatCustomers.size()); for (Customer repeatCustomer : repeatCustomers) { repeatPhones.add(repeatCustomer.getPhone()); } for (Customer customer : customersNotNull) { if (repeatPhones.contains(customer.getPhone())){ continue; } validCustomers.add(customer); } }else { validCustomers = customersNotNull; } for (Customer validCustomer : validCustomers) { validCustomer.setCustomerType(UkConstant.CUSTOMER_TYPE_INDIVIDUALITY); validCustomer.setChannelType(UkConstant.CHANNEL_TYPE_CALL_OUT); validCustomer.setCalloutTaskStatus(0); validCustomer.setCalloutDistributeStatus(0); validCustomer.setCalloutTaskId(taskId); validCustomer.setCorpCode(corpCode); validCustomer.setCreater(userId); } if (CollectionUtils.isEmpty(validCustomers)){ return "成功导入:"+ 0 +"条记录
"+result; } List> customersList = new ArrayList<>(); int total = validCustomers.size(); int threads = 5; int oneSize = total/5 +1; int start = 0; int end = 0; for (int i = 0; i transactionStatuses = Collections.synchronizedList(new ArrayList()); CountDownLatch latch= new CountDownLatch(threads); for (int i = 0; i < threads; i++) { int finalI = i; ThreadPoolUtils.fixedThreadPool.execute(new Runnable() { @Override public void run() { DefaultTransactionDefinition def = new DefaultTransactionDefinition(); def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); // 事物隔离级别,开启新事务,这样会比较安全些。 TransactionStatus status = transactionManager.getTransaction(def); // 获得事务状态 transactionStatuses.add(status); try{ improtInsertBath(corpCode,userId,customersList.get(finalI)); }catch(Exception e){ e.printStackTrace(); for (TransactionStatus transactionStatus:transactionStatuses) { transactionStatus.setRollbackOnly(); } } latch.countDown(); } }); } try { latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } //更新外呼任务客户总数 customerCnt、未分配客户数 notDistributeCnt、未拨打数 not_call_cnt task.setCustomerCnt(task.getCustomerCnt()+total); task.setNotDistributeCnt(task.getNotDistributeCnt()+total); task.setNotCallCnt(task.getNotCallCnt()+total); taskService.updateById(task); return "成功导入:"+ total +"条记录
"+result; } @Override public Page callOutTask(Page page, Customer customer) { if (StringUtils.isNotBlank(customer.getAssignTimeStart())){ String start = customer.getAssignTimeStart().substring(0,10)+" 00:00:00"; String end = customer.getAssignTimeStart().substring(13)+" 23:59:59"; customer.setAssignTimeStart(start); customer.setAssignTimeEnd(end); }else { customer.setAssignTimeEnd(DateUtil.getConvertDateFormat("yyyy-MM-dd HH:mm:ss",new Date())); } if (StringUtils.isNotBlank(customer.getCalloutTimeStart())){ String start = customer.getCalloutTimeStart().substring(0,10)+" 00:00:00"; String end = customer.getCalloutTimeStart().substring(13)+" 23:59:59"; customer.setCalloutTimeStart(start); customer.setCalloutTimeEnd(end); } List ids = new ArrayList<>(); if (StringUtils.isNotBlank(customer.getHasLabel())){ String[] ss = customer.getHasLabel().substring(1).split("\\,"); for (String id:ss) { ids.add(id); } customer.setLabelIds(ids); } customer.setCorpCode(ExecutionContext.getCorpCode()); return page.setRecords(this.baseMapper.callOutTask(page, customer)); } @Override public Map getCallOutTaskStatistics(String userId,List taskIds) { List customers = customerDao.getCallOutTaskStatistics(ExecutionContext.getCorpCode(), userId, taskIds); if (CollectionUtils.isEmpty(customers)){ return MapUtils.EMPTY_MAP; } Map taskIdStatusCntMap = new HashMap<>(customers.size()); for (Customer customer : customers) { taskIdStatusCntMap.put(customer.getCalloutTaskId()+"-"+customer.getCalloutTaskStatus(),customer.getCalloutTaskStatusCnt()); } return taskIdStatusCntMap; } @Override public Page findPageForProcess(Page page, Customer customer) { List records = customerDao.findPageForProcess(page, customer); return page.setRecords(records); } @Transactional(rollbackFor = {MybatisPlusException.class}) @Override public void improtInsertBath(String corpCode,String userId,List list){ insertBatch(list);//TODO 检查validCustomers,一个线程1K条数据导入 //处理客户轨迹记录 int validCustomerSize = list.size(); List customerRecords = new ArrayList<>(validCustomerSize); for (Customer validCustomer : list) { CustomerRecord customerRecord = new CustomerRecord(UkConstant.RECORD_TYPE_UPDATE,"导入了客户",null,null,null,validCustomer.getId()); customerRecord.setCreater(userId); customerRecord.setCorpCode(corpCode); customerRecords.add(customerRecord); } boolean result = customerRecordService.insertBatch(customerRecords); } }

以上在测试环境,数据插入ok,上生产

数据无法插入数据库,可能原因 事务未提交 手动提交

 

代码如下

package com.ps.uzkefu.apps.crm.service.impl;

import com.baomidou.mybatisplus.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.ps.uzkefu.apps.callout.entity.Task;
import com.ps.uzkefu.apps.callout.service.TaskService;
import com.ps.uzkefu.apps.crm.entity.Customer;
import com.ps.uzkefu.apps.crm.entity.CustomerRecord;
import com.ps.uzkefu.apps.crm.mapper.CustomerDao;
import com.ps.uzkefu.apps.crm.service.CustomerRecordService;
import com.ps.uzkefu.apps.crm.service.CustomerService;
import com.ps.uzkefu.apps.oms.account.entity.DefinedField;
import com.ps.uzkefu.apps.oms.account.entity.DefinedFieldOption;
import com.ps.uzkefu.apps.oms.account.entity.DefinedFieldValue;
import com.ps.uzkefu.apps.oms.account.service.DefinedFieldOptionService;
import com.ps.uzkefu.apps.oms.account.service.DefinedFieldService;
import com.ps.uzkefu.apps.oms.account.service.DefinedFieldValueService;
import com.ps.uzkefu.apps.oms.account.service.UserService;
import com.ps.uzkefu.base.BaseServiceImpl;
import com.ps.uzkefu.common.ExecutionContext;
import com.ps.uzkefu.common.UkConstant;
import com.ps.uzkefu.util.DateUtil;
import com.ps.uzkefu.util.ExcelTemplateExportUtil;
import com.ps.uzkefu.util.ThreadPoolUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.executor.BatchExecutorException;
import org.apache.ibatis.transaction.Transaction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.sql.BatchUpdateException;
import java.util.*;
import java.util.concurrent.CountDownLatch;

/**
 * 

* 客户 服务实现类 *

* * @author WuZhiWei * @since 2018-07-06 */ @Transactional(rollbackFor = {Exception.class}) @Service public class CustomerServiceImpl extends BaseServiceImpl implements CustomerService { @Autowired private DefinedFieldValueService definedFieldValueService; @Autowired private DefinedFieldService definedFieldService; @Autowired private DefinedFieldOptionService definedFieldOptionService; @Autowired private CustomerRecordService customerRecordService; @Autowired private UserService userService; @Autowired private TaskService taskService; @Autowired private CustomerDao customerDao; @Autowired private PlatformTransactionManager transactionManager; @Value("${tmp.file.path}") private String tmpFilePath; @Override public String saveOrUpdate(Customer customer) { String id = customer.getId(); String phone = customer.getPhone(); String corpCode = ExecutionContext.getCorpCode(); customer.setCorpCode(corpCode); if (StringUtils.isEmpty(id)){ Customer selectOne = this.selectOne(new EntityWrapper(). eq("corp_code", corpCode).eq("phone", phone)); if (selectOne != null){ return "联系号码已存在"; } } Customer selectOne = this.selectOne(new EntityWrapper(). eq("corp_code", corpCode).eq("phone", phone) .where("id !={0}",id)); if (selectOne != null){ return "联系号码已存在"; } if (StringUtils.isEmpty(customer.getCorpName())){ customer.setCustomerType(UkConstant.CUSTOMER_TYPE_INDIVIDUALITY); }else { customer.setCustomerType(UkConstant.CUSTOMER_TYPE_CORP); } if (StringUtils.isEmpty(customer.getUserId())){ customer.setUserId(ExecutionContext.getUserId()); } //自定义属性 List definedFieldValues = customer.getDefinedFieldValues(); //变更记录 String updateRecord = getUpdateRecord(customer, id, corpCode, definedFieldValues); customer.setAssignDate(new Date()); this.insertOrUpdate(customer); if (StringUtils.isEmpty(id)){ id = customer.getId(); } if (StringUtils.isNotEmpty(updateRecord)){ CustomerRecord customerRecord = new CustomerRecord(UkConstant.RECORD_TYPE_UPDATE,updateRecord,null,null,null,id); customerRecordService.insert(customerRecord); } //自定义保存或更新处理 if (CollectionUtils.isNotEmpty(definedFieldValues)){ for (DefinedFieldValue fieldValue : definedFieldValues) { fieldValue.setResourceId(id); } definedFieldValueService.delete(new EntityWrapper().eq("resource_id",id)); definedFieldValueService.insertBatch(definedFieldValues); } return ""; } private String getUpdateRecord(Customer customer, String id, String corpCode, List definedFieldValues) { String recordContent = ""; if (StringUtils.isNotEmpty(id)){ Customer customerDb = this.selectById(id); Map uidNameMap = userService.getAllUidNameMap(); recordContent = dealUpdate("客户姓名",customer.getName(),customerDb.getName(),recordContent); recordContent = dealUpdate("公司名称",customer.getCorpName(),customerDb.getCorpName(),recordContent); if (StringUtils.isNotEmpty(customer.getPhone())){ recordContent =dealUpdate("联系号码",customer.getPhone(),customerDb.getPhone(),recordContent); } recordContent =dealUpdate("联系邮箱",customer.getEmail(),customerDb.getEmail(),recordContent); recordContent =dealUpdate("微信",customer.getWx(),customerDb.getWx(),recordContent); recordContent =dealUpdate("QQ",customer.getQq(),customerDb.getQq(),recordContent); recordContent =dealUpdate("所在省",customer.getProvince(),customerDb.getProvince(),recordContent); recordContent =dealUpdate("所在市",customer.getCity(),customerDb.getCity(),recordContent); recordContent =dealUpdate("描述",customer.getDescription(),customerDb.getDescription(),recordContent); recordContent =dealUpdate("所属员工",uidNameMap.get(customer.getUserId()),uidNameMap.get(customerDb.getUserId()),recordContent); if (CollectionUtils.isNotEmpty(definedFieldValues)){ Map fieldIdValueMap = new HashMap<>(); for (DefinedFieldValue fieldValue : definedFieldValues) { fieldIdValueMap.put(fieldValue.getFieldId(),fieldValue.getFieldValue()); } Map fieldIdValueMapDb = new HashMap<>(); List definedFieldValuesDb = definedFieldValueService.selectList(new EntityWrapper(). eq("corp_code", corpCode).eq("resource_id", id)); if (CollectionUtils.isNotEmpty(definedFieldValuesDb)){ for (DefinedFieldValue fieldValue : definedFieldValuesDb) { fieldIdValueMapDb.put(fieldValue.getFieldId(),fieldValue.getFieldValue()); } } List definedFields = definedFieldService.selectList(new EntityWrapper(). eq("corp_code", corpCode).eq("biz_type", UkConstant.DEFINED_BIZ_TYPE_CRM)); List fieldOptions = definedFieldOptionService.selectList(new EntityWrapper().eq("corp_code", corpCode)); Map optionIdNameMap; if (CollectionUtils.isEmpty(fieldOptions)){ optionIdNameMap = MapUtils.EMPTY_MAP; }else { optionIdNameMap = new HashMap<>(fieldOptions.size()); } for (DefinedFieldOption option : fieldOptions) { optionIdNameMap.put(option.getId(),option.getOptionName()); } if (CollectionUtils.isNotEmpty(definedFields)){ for (DefinedField field : definedFields) { String fieldName = field.getFieldName(); String fieldType = field.getFieldType(); String fieldId = field.getId(); String pre = fieldIdValueMapDb.get(fieldId); if (pre == null){ pre = ""; } String now = fieldIdValueMap.get(fieldId); if (now == null){ now = ""; } if (UkConstant.DEFINED_FIELD_TYPE_SELECT.equals(fieldType) || UkConstant.DEFINED_FIELD_TYPE_RADIO.equals(fieldType) || UkConstant.DEFINED_FIELD_TYPE_CHECKBOX.equals(fieldType)){ pre = optionIdNameMap.get(pre); now = optionIdNameMap.get(now); } recordContent = dealUpdate(fieldName,now,pre,recordContent); } } } }else { recordContent = "创建了客户"; } return recordContent; } private String dealUpdate(String label,String now,String pre,String result){ String preStr = pre; if (StringUtils.isEmpty(pre)){ pre = ""; preStr = "<空>"; } String nowStr = now; if (StringUtils.isEmpty(now)){ now = ""; nowStr = "<空>"; } if (now.equals(pre)){ return result; } result += label + ":" + preStr + "-->" + nowStr+"
"; return result; } @Override public String importBatch(String url,String taskId) { if (StringUtils.isEmpty(taskId)){ return "请选择外呼任务"; } Task task = taskService.selectById(taskId); if (task == null){ return "外呼任务不存在,Id为:"+taskId; } String filePath = tmpFilePath + url; List customers = ExcelTemplateExportUtil.importExcel(filePath, 0, 1, Customer.class); if (CollectionUtils.isEmpty(customers)){ return "Excel数据不能为空"; } int totalCustomerCnt = customers.size(); if (totalCustomerCnt > 5000){ return "最多支持5000条,请分批导入"; } //过滤掉空属性 List phones = new ArrayList<>(); List customersNotNull = new ArrayList<>(); String corpCode = ExecutionContext.getCorpCode(); String userId = ExecutionContext.getUserId(); for (Customer customer : customers) { String phone = customer.getPhone(); if (StringUtils.isEmpty(customer.getName()) || StringUtils.isEmpty(phone)){ continue; } customersNotNull.add(customer); phones.add(phone); } String result = ""; int notNullSize = customersNotNull.size(); int size = customers.size(); if (notNullSize < size){ result += "存在客户名称或手机号码为空:"+(size - notNullSize)+"条记录"; } //过滤手机号重复的 List validCustomers = new ArrayList<>(); List repeatCustomers = this.selectList(new EntityWrapper().eq("corp_code", corpCode).in("phone", phones)); if (CollectionUtils.isNotEmpty(repeatCustomers)){ result += "
存在手机号码重复:"+(repeatCustomers.size())+"条记录"; List repeatPhones = new ArrayList<>(repeatCustomers.size()); for (Customer repeatCustomer : repeatCustomers) { repeatPhones.add(repeatCustomer.getPhone()); } for (Customer customer : customersNotNull) { if (repeatPhones.contains(customer.getPhone())){ continue; } validCustomers.add(customer); } }else { validCustomers = customersNotNull; } for (Customer validCustomer : validCustomers) { validCustomer.setCustomerType(UkConstant.CUSTOMER_TYPE_INDIVIDUALITY); validCustomer.setChannelType(UkConstant.CHANNEL_TYPE_CALL_OUT); validCustomer.setCalloutTaskStatus(0); validCustomer.setCalloutDistributeStatus(0); validCustomer.setCalloutTaskId(taskId); validCustomer.setCorpCode(corpCode); validCustomer.setCreater(userId); } if (CollectionUtils.isEmpty(validCustomers)){ return "成功导入:"+ 0 +"条记录
"+result; } List> customersList = new ArrayList<>(); int total = validCustomers.size(); int threads = 1; if (total >=1000){ threads = 5; } int oneSize = total/threads +1; int start = 0; int end = 0; for (int i = 0; i transactionStatuses = Collections.synchronizedList(new ArrayList()); CountDownLatch latch= new CountDownLatch(threads); Map totalMap = new HashMap(); for (int i = 0; i < threads; i++) { int finalI = i; ThreadPoolUtils.fixedThreadPool.execute(new Runnable() { @Override public void run() { DefaultTransactionDefinition def = new DefaultTransactionDefinition(); def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); // 事物隔离级别,开启新事务,这样会比较安全些。 TransactionStatus status = transactionManager.getTransaction(def); // 获得事务状态 transactionStatuses.add(status); try{ improtInsertBath(corpCode,userId,customersList.get(finalI)); totalMap.put("total"+finalI,customersList.get(finalI).size()); //提交事务 transactionManager.commit(status); }catch(Exception e){ e.printStackTrace(); //回滚 事务 这样做一个线程出问题 只能回滚出问题的线程 transactionManager.rollback(status); } latch.countDown(); } }); } try { // for (TransactionStatus transactionStatus:transactionStatuses) { // transactionManager.commit(transactionStatus); // } latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } int countTotal = 0; for (Integer count: totalMap.values()) { countTotal = countTotal+count; } //更新外呼任务客户总数 customerCnt、未分配客户数 notDistributeCnt、未拨打数 not_call_cnt task.setCustomerCnt(task.getCustomerCnt()+countTotal); task.setNotDistributeCnt(task.getNotDistributeCnt()+countTotal); task.setNotCallCnt(task.getNotCallCnt()+countTotal); taskService.updateById(task); return "成功导入:"+ countTotal +"条记录
"+result; } @Override public Page callOutTask(Page page, Customer customer) { if (StringUtils.isNotBlank(customer.getAssignTimeStart())){ String start = customer.getAssignTimeStart().substring(0,10)+" 00:00:00"; String end = customer.getAssignTimeStart().substring(13)+" 23:59:59"; customer.setAssignTimeStart(start); customer.setAssignTimeEnd(end); }else { customer.setAssignTimeEnd(DateUtil.getConvertDateFormat("yyyy-MM-dd HH:mm:ss",new Date())); } if (StringUtils.isNotBlank(customer.getCalloutTimeStart())){ String start = customer.getCalloutTimeStart().substring(0,10)+" 00:00:00"; String end = customer.getCalloutTimeStart().substring(13)+" 23:59:59"; customer.setCalloutTimeStart(start); customer.setCalloutTimeEnd(end); } List ids = new ArrayList<>(); if (StringUtils.isNotBlank(customer.getHasLabel())){ String[] ss = customer.getHasLabel().substring(1).split("\\,"); for (String id:ss) { ids.add(id); } customer.setLabelIds(ids); } customer.setCorpCode(ExecutionContext.getCorpCode()); return page.setRecords(this.baseMapper.callOutTask(page, customer)); } @Override public Map getCallOutTaskStatistics(String userId,List taskIds) { List customers = customerDao.getCallOutTaskStatistics(ExecutionContext.getCorpCode(), userId, taskIds); if (CollectionUtils.isEmpty(customers)){ return MapUtils.EMPTY_MAP; } Map taskIdStatusCntMap = new HashMap<>(customers.size()); for (Customer customer : customers) { taskIdStatusCntMap.put(customer.getCalloutTaskId()+"-"+customer.getCalloutTaskStatus(),customer.getCalloutTaskStatusCnt()); } return taskIdStatusCntMap; } @Override public Page findPageForProcess(Page page, Customer customer) { List records = customerDao.findPageForProcess(page, customer); return page.setRecords(records); } @Transactional(rollbackFor = {MybatisPlusException.class}) @Override public void improtInsertBath(String corpCode,String userId,List list){ insertBatch(list);//TODO 检查validCustomers,一个线程1K条数据导入 //处理客户轨迹记录 int validCustomerSize = list.size(); List customerRecords = new ArrayList<>(validCustomerSize); for (Customer validCustomer : list) { CustomerRecord customerRecord = new CustomerRecord(UkConstant.RECORD_TYPE_UPDATE,"导入了客户",null,null,null,validCustomer.getId()); customerRecord.setCreater(userId); customerRecord.setCorpCode(corpCode); customerRecords.add(customerRecord); } boolean result = customerRecordService.insertBatch(customerRecords); } }

 

你可能感兴趣的:(Java和Jvm,Java多线程)