代码版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  <T, KEY> int insertOnDuplicateKeyUpdate(List<T> dataList, Function<T, KEY> getUniqueKey,
            Function<List<T>, Integer> doInsert, Function<List<T>, List<T>> queryExists,
            BiFunction<List<T>, List<T>, 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<T> existsList = queryExists.apply(dataList);
            Set<KEY> existsKeys = existsList.stream().map(getUniqueKey).collect(Collectors.toSet());
            List<T> insertList = dataList.stream().filter(x -> !existsKeys.contains(getUniqueKey.apply(x))).collect(Collectors.toList());
            List<T> 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;
        }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容