代码版insertOnDuplicateKeyUpdate

并发插入数据导致数据库唯一键冲突报DuplicateKeyException,可以使用replace into,insert on duplicate key update来解决,但是会有mysql锁的问题,用代码来解决

public abstract class DbUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger(DbUtils.class);

    public static   int insertOnDuplicateKeyUpdate(List dataList, Function getUniqueKey,
            Function, Integer> doInsert, Function, List> queryExists,
            BiFunction, List, Integer> doUpdate, int tryCount) {

        Object savePoint = null;
        try {
            savePoint = TransactionSynchronizationManager.isActualTransactionActive() ? TransactionAspectSupport.currentTransactionStatus().createSavepoint() : null;

            Integer result = doInsert.apply(dataList);
            return result;
        }
        catch (DuplicateKeyException onDuplicate) {
            if (tryCount == 0) {
                throw onDuplicate;
            }
            if (savePoint != null) {
                TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);
            }

            List existsList = queryExists.apply(dataList);
            Set existsKeys = existsList.stream().map(getUniqueKey).collect(Collectors.toSet());
            List insertList = dataList.stream().filter(x -> !existsKeys.contains(getUniqueKey.apply(x))).collect(Collectors.toList());
            List updateList = dataList.stream().filter(x -> existsKeys.contains(getUniqueKey.apply(x))).collect(Collectors.toList());

            int updateResult = doUpdate.apply(existsList, updateList);
            int insertResult = CollectionUtils.isNotEmpty(insertList) ? insertOnDuplicateKeyUpdate(insertList, getUniqueKey, doInsert, queryExists, doUpdate, tryCount - 1) : 0;
            LOGGER.info("onDuplicateKey insert size {} result {}, update size {} result {} {}",
                    insertList.size(), insertResult, updateList.size(), updateResult, savePoint == null? "": "transactional");

            return insertResult + updateResult;
        }
    }
}

你可能感兴趣的:(代码版insertOnDuplicateKeyUpdate)