• Mysql插入或者更新数据(MyBatis框架)


    目录

    1.场景说明

    2.DUPLICATE 和REPLACE比较

    3.批量插入或者更新(两种方式)

    方式一:mybatis-plus的saveOrUpdateBatch方法

    问题:如果操作类集成了基础类,比如封装了BaseEntity去集成,那么这样使用会出问题

    方式二:on duplicate key (推荐)

    4.注意

    5.常见问题 


    1.场景说明

    插入数据时,我们经常会遇到这样的情况:

    1、首先判断数据是否存在;

    2、如果不存在,则插入;

    3、如果存在,则更新

    需求:根据表中的部分字段去判断插入或者更新

    有一张表 hh_adx_monitor_summary

     ddl:

    1. CREATE TABLE `hh_adx_monitor_summary` (
    2. `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
    3. `code` varchar(6) DEFAULT NULL COMMENT '链路编码',
    4. `plan_id` varchar(32) DEFAULT NULL COMMENT '计划id',
    5. `cons` int(11) DEFAULT NULL COMMENT '消耗',
    6. `exp` int(11) DEFAULT NULL COMMENT '曝光数',
    7. `conv` int(11) DEFAULT NULL COMMENT '转化数',
    8. `click` int(11) DEFAULT NULL COMMENT '点击数',
    9. `dimension_time` varchar(32) DEFAULT NULL COMMENT '维度时间',
    10. `create_time` datetime DEFAULT NULL COMMENT '创建时间',
    11. `update_time` datetime DEFAULT NULL COMMENT '更新时间',
    12. PRIMARY KEY (`id`),
    13. UNIQUE KEY `idx_hh_adx_monitor_summary_cpd` (`code`,`plan_id`,`dimension_time`) USING BTREE
    14. ) ENGINE=InnoDB AUTO_INCREMENT=42 DEFAULT CHARSET=utf8 COMMENT='监测请求数据汇总';

    需要通过code,plan_id,dimension_time判断插入或者更新

    1. INSERT INTO hh_adx_monitor_summary ( CODE, plan_id, cons, exp, conv, click, dimension_time)
    2. VALUES
    3. ( '001001', '1', 6, 3, 0, 0, '20220823' )
    4. ON DUPLICATE KEY UPDATE
    5. CODE =VALUES ( CODE ),
    6. plan_id =VALUES ( plan_id ),
    7. cons =VALUES ( cons ),
    8. exp =VALUES ( exp ),
    9. conv =VALUES ( conv ),
    10. click =VALUES ( click ),
    11. dimension_time =VALUES ( dimension_time)

    此时会发现依然会重复插入数据,需要创建一个组合索引

     添加完索引再次尝试,code,plan_id,dimension_time相同的情况下只会更新不会新增

    2.DUPLICATE 和REPLACE比较

    replace into 跟 insert 功能类似,不同点在于:replace into 首先尝试插入数据到表中, 1. 如果发现表中已经有此行数据(根据主键或者唯一索引判断)则先删除此行数据,然后插入新的数据。 2. 否则,直接插入新数据。

    3.批量插入或者更新(两种方式)

    方式一:mybatis-plus的saveOrUpdateBatch方法

    使用saveOrUpdateBatch方法直接调用就可以了,分别在持久层实现Mapper接口,服务层接口继承 IService接口,实现类继承 ServiceImpl接口

    1.持久层代码示例

    说明:继承BaseMapper即可,泛型使用当前要操作类

    1. package com.hhmt.delivery.mapper;
    2. import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    3. import com.hhmt.delivery.pojo.entity.HhChainCustomerInfo;
    4. import org.apache.ibatis.annotations.Mapper;
    5. import org.apache.ibatis.annotations.Param;
    6. import java.util.Collection;
    7. import java.util.List;
    8. /**
    9. * 链路客户信息Mapper接口
    10. *
    11. * @author huachun
    12. * @date 2023-01-31
    13. */
    14. @Mapper
    15. public interface HhChainCustomerInfoMapper extends BaseMapper {
    16. /**
    17. * 使用mybatis-plus方式调用saveOrUpdateBatch不需要写这个接口
    18. boolean saveOrUpdateBatch(@Param("entities") Collection hhChainCustomerInfos);
    19. */
    20. }

    2.服务层接口示例

    说明:继承 IService即可,泛型使用当前要操作类

    1. package com.hhmt.delivery.service;
    2. import com.baomidou.mybatisplus.extension.service.IService;
    3. import com.hhmt.delivery.pojo.entity.HhChainCustomerInfo;
    4. import java.util.List;
    5. /**
    6. * 链路客户信息Service接口
    7. *
    8. * @author huachun
    9. * @date 2023-01-31
    10. */
    11. public interface IHhChainCustomerInfoService extends IService {
    12. }

    3.服务实现类示例

    说明:继承ServiceImpl即可,泛型使用持久层操作对象接口类和操作类

    1. package com.hhmt.delivery.service.impl;
    2. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    3. import com.hhmt.delivery.mapper.HhChainCustomerInfoMapper;
    4. import com.hhmt.delivery.pojo.entity.HhChainCustomerInfo;
    5. import org.springframework.stereotype.Service;
    6. import java.util.List;
    7. /**
    8. * 链路客户信息Service业务层处理
    9. *
    10. * @author huachun
    11. * @date 2023-01-31
    12. */
    13. @Service
    14. public class HhChainCustomerInfoServiceImpl extends ServiceImpl implements IHhChainCustomerInfoService {
    15. /*@Override
    16. public boolean saveOrUpdateBatch(Collection entityList) {
    17. return hhChainCustomerInfoMapper.saveOrUpdateBatch(entityList);
    18. }*/
    19. }

    4.服务层示例

    1. package com.hhmt.delivery.controller;
    2. import com.hhmt.delivery.core.controller.BaseController;
    3. import com.hhmt.delivery.core.domain.model.ResultVo;
    4. import com.hhmt.delivery.core.page.TableDataInfo;
    5. import com.hhmt.delivery.pojo.entity.HhChainCustomerInfo;
    6. import com.hhmt.delivery.pojo.model.query.HhChainCustomerInfoQuery;
    7. import com.hhmt.delivery.pojo.model.vo.HhChainCustomerInfoVo;
    8. import com.hhmt.delivery.service.IHhChainCustomerInfoService;
    9. import com.hhmt.delivery.valiadtion.Add;
    10. import com.hhmt.delivery.valiadtion.Update;
    11. import io.swagger.annotations.Api;
    12. import io.swagger.annotations.ApiOperation;
    13. import org.springframework.beans.factory.annotation.Autowired;
    14. import org.springframework.validation.annotation.Validated;
    15. import org.springframework.web.bind.annotation.DeleteMapping;
    16. import org.springframework.web.bind.annotation.GetMapping;
    17. import org.springframework.web.bind.annotation.PathVariable;
    18. import org.springframework.web.bind.annotation.PostMapping;
    19. import org.springframework.web.bind.annotation.PutMapping;
    20. import org.springframework.web.bind.annotation.RequestBody;
    21. import org.springframework.web.bind.annotation.RequestMapping;
    22. import org.springframework.web.bind.annotation.RestController;
    23. import java.util.List;
    24. /**
    25. * 链路客户信息Controller
    26. *
    27. * @author huachun
    28. * @date 2023-01-31
    29. */
    30. @Api(tags = "链路客户信息")
    31. @RestController
    32. @RequestMapping("/chain/HhChainCustomerInfo")
    33. public class HhChainCustomerInfoController extends BaseController {
    34. @Autowired
    35. private IHhChainCustomerInfoService hhChainCustomerInfoService;
    36. @ApiOperation("批量插入或更新客户信息")
    37. @PostMapping("/batch")
    38. public ResultVo addBatch(@Validated(value = Add.class) @RequestBody List hhChainCustomerInfos) {
    39. return toAjax(hhChainCustomerInfoService.saveOrUpdateBatch(hhChainCustomerInfos));
    40. }
    41. }

    此时调用发现结果是成功的,数据库数据也被更新了(省略过多的测试截图)

     这种方式在执行时候会通过id判断是否有内容,然后在做更新操作。从打印的sql日志可以看出

    总结:

            1.没有唯一键(id)回自动生成id后新增

            2.有id会查询后判断

            3.查询后数据有差异会调用update语句更新

    问题:如果操作类集成了基础类,比如封装了BaseEntity去集成,那么这样使用会出问题

    示例如下:

    1.BaseEntity类(一般是实体类的公共参数)

    1. package com.hhmt.delivery.core.domain.model;
    2. import com.fasterxml.jackson.annotation.JsonFormat;
    3. import com.fasterxml.jackson.annotation.JsonIgnore;
    4. import io.swagger.annotations.ApiModelProperty;
    5. import lombok.Data;
    6. import java.io.Serializable;
    7. import java.util.Date;
    8. import java.util.Map;
    9. /**
    10. * Entity基类
    11. *
    12. * @author huachun
    13. */
    14. @Data
    15. public class BaseEntity implements Serializable {
    16. private static final long serialVersionUID = 1L;
    17. /**
    18. * 搜索值
    19. */
    20. private String searchValue;
    21. /**
    22. * 创建者
    23. */
    24. private String createBy;
    25. /**
    26. * 创建时间
    27. */
    28. @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    29. @ApiModelProperty(value = "创建时间", example = "2022-09-01 13:24:09")
    30. private Date createTime;
    31. /**
    32. * 更新者
    33. */
    34. private String updateBy;
    35. /**
    36. * 更新时间
    37. */
    38. @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    39. @ApiModelProperty(value = "创建时间", example = "2022-09-01 13:24:09")
    40. private Date updateTime;
    41. /**
    42. * 备注
    43. */
    44. private String remark;
    45. /**
    46. * 请求参数
    47. */
    48. @JsonIgnore
    49. private Map params;
    50. }

    2.操作类HhChainCustomerInfo继承了BaseEntity

    1. package com.hhmt.delivery.pojo.entity;
    2. import com.hhmt.delivery.annotation.Excel;
    3. import com.hhmt.delivery.constant.VerificationTips;
    4. import com.hhmt.delivery.core.domain.model.BaseEntity;
    5. import com.hhmt.delivery.valiadtion.Update;
    6. import io.swagger.annotations.ApiModelProperty;
    7. import lombok.Data;
    8. import lombok.EqualsAndHashCode;
    9. import javax.validation.constraints.NotNull;
    10. /**
    11. * 链路客户信息对象 hh_chain_customer_info
    12. *
    13. * @author huachun
    14. * @date 2023-01-31
    15. */
    16. @EqualsAndHashCode(callSuper = true)
    17. @Data
    18. public class HhChainCustomerInfo extends BaseEntity {
    19. private static final long serialVersionUID = 1L;
    20. /**
    21. * 主键ID
    22. */
    23. @NotNull(groups = Update.class, message = VerificationTips.EMPTY_TIPS)
    24. @ApiModelProperty(value = "${comment}")
    25. private Long id;
    26. /**
    27. * 描述
    28. */
    29. @Excel(name = "描述")
    30. @ApiModelProperty(value = "描述")
    31. private String description;
    32. /**
    33. * 服务
    34. */
    35. @Excel(name = "服务")
    36. @ApiModelProperty(value = "服务")
    37. private Long serviceId;
    38. /**
    39. * 名称
    40. */
    41. @Excel(name = "名称")
    42. @ApiModelProperty(value = "名称")
    43. private String name;
    44. /**
    45. * 编码
    46. */
    47. @Excel(name = "编码")
    48. @ApiModelProperty(value = "编码")
    49. private String code;
    50. /**
    51. * 回传请求方式(1.GET 2.POST)
    52. */
    53. @Excel(name = "回传请求方式(1.GET 2.POST)")
    54. @ApiModelProperty(value = "回传请求方式(1.GET 2.POST)")
    55. private Integer reqMode;
    56. /**
    57. * 上报接口
    58. */
    59. @Excel(name = "上报接口")
    60. @ApiModelProperty(value = "上报接口")
    61. private String reqApi;
    62. /**
    63. * 签名策略
    64. */
    65. @Excel(name = "签名策略")
    66. @ApiModelProperty(value = "签名策略")
    67. private Integer signPolicy;
    68. }

    此时想要进行批量插入或者更新会出现以下问题:

    有请求id时候被认为是更新,更新会通过id查询判断,问题就出在这里。plus在进行查询时候通过操作类属性去查询,导致了集成的父类属性也进去了,然而在表里面是没有这些字段的,所以出现了上述问题。

    方式二:on duplicate key (推荐)

    说明:通过sql的方式实现批量的插入或更新,这种方式需要有唯一索引,通过唯一索引去判断是否冲突,有冲突就会更新,没有冲突就会插入数据。

    1. <insert id="saveOrUpdateBatch" keyProperty="id" useGeneratedKeys="true">
    2. insert into hh_chain_customer_info(id,description, create_time, update_time, service_id, name, code, req_mode,
    3. req_api, sign_policy)
    4. values
    5. <foreach collection="entities" item="entity" separator=",">
    6. (#{entity.id},#{entity.description}, #{entity.createTime}, #{entity.updateTime}, #{entity.serviceId},
    7. #{entity.name},
    8. #{entity.code}, #{entity.reqMode}, #{entity.reqApi}, #{entity.signPolicy})
    9. foreach>
    10. on duplicate key update
    11. description = values(description),
    12. create_time = values(create_time),
    13. update_time = values(update_time),
    14. service_id = values(service_id),
    15. name = values(name),
    16. code = values(code),
    17. req_mode = values(req_mode),
    18. req_api = values(req_api),
    19. sign_policy = values(sign_policy)
    20. insert>

    1.持久层代码示例

    1. package com.hhmt.delivery.mapper;
    2. import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    3. import com.hhmt.delivery.pojo.entity.HhChainCustomerParams;
    4. import org.apache.ibatis.annotations.Mapper;
    5. import org.apache.ibatis.annotations.Param;
    6. import java.util.Collection;
    7. import java.util.List;
    8. /**
    9. * 链路客户参数Mapper接口
    10. *
    11. * @author huachun
    12. * @date 2023-01-31
    13. */
    14. @Mapper
    15. public interface HhChainCustomerParamsMapper extends BaseMapper {
    16. boolean insertOrUpdateBatch(@Param("entities") Collection hhChainCustomerParams);
    17. }

    2.服务实现类

    1. package com.hhmt.delivery.service.impl;
    2. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    3. import com.hhmt.delivery.core.utils.DateUtils;
    4. import com.hhmt.delivery.mapper.HhChainCustomerParamsMapper;
    5. import com.hhmt.delivery.pojo.entity.HhChainCustomerParams;
    6. import com.hhmt.delivery.service.IHhChainCustomerParamsService;
    7. import org.springframework.beans.factory.annotation.Autowired;
    8. import org.springframework.stereotype.Service;
    9. import java.util.Collection;
    10. import java.util.List;
    11. /**
    12. * 链路客户参数Service业务层处理
    13. *
    14. * @author huachun
    15. * @date 2023-01-31
    16. */
    17. @Service
    18. public class HhChainCustomerParamsServiceImpl extends ServiceImpl implements IHhChainCustomerParamsService {
    19. @Autowired
    20. private HhChainCustomerParamsMapper hhChainCustomerParamsMapper;
    21. @Override
    22. public boolean saveOrUpdateBatch(Collection entityList) {
    23. return hhChainCustomerParamsMapper.insertOrUpdateBatch(entityList);
    24. }
    25. }

    此时sql日志:

    拦截的sql ==>: com.hhmt.delivery.mapper.HhChainCustomerInfoMapper.saveOrUpdateBatch:insert into hh_chain_customer_info(id,description, create_time, update_time, service_id, name, code, req_mode, req_api, sign_policy) values (1621028577047281666,, , , , '111111111111', , , , ) on duplicate key update description = values(description), create_time = values(create_time), update_time = values(update_time), service_id = values(service_id), name = values(name), code = values(code), req_mode = values(req_mode), req_api = values(req_api), sign_policy = values(sign_policy)
    sql耗时 ==>: 14 毫秒
    类型 ==> INSERT
    拦截的sql ==>: com.hhmt.delivery.mapper.HhChainCustomerInfoMapper.saveOrUpdateBatch:insert into hh_chain_customer_info(id,description, create_time, update_time, service_id, name, code, req_mode, req_api, sign_policy) values (1621028577047281666,, , , , 'dsfasdfadf', , , , ) on duplicate key update description = values(description), create_time = values(create_time), update_time = values(update_time), service_id = values(service_id), name = values(name), code = values(code), req_mode = values(req_mode), req_api = values(req_api), sign_policy = values(sign_policy)
    sql耗时 ==>: 0 毫秒
    类型 ==> INSERT
    拦截的sql ==>: com.hhmt.delivery.mapper.HhChainCustomerInfoMapper.saveOrUpdateBatch:insert into hh_chain_customer_info(id,description, create_time, update_time, service_id, name, code, req_mode, req_api, sign_policy) values (,, , , , 'dsfasdfadf', , , , ) on duplicate key update description = values(description), create_time = values(create_time), update_time = values(update_time), service_id = values(service_id), name = values(name), code = values(code), req_mode = values(req_mode), req_api = values(req_api), sign_policy = values(sign_policy)
    sql耗时 ==>: 0 毫秒

    个人感觉这样效率更改更方便,值得推荐

    4.注意

    on udplicate key update后的内容表示,主键存在时则执行更新操作,需要注意的是insert字段中需要含有唯一性字段(主键索引或唯一索引)

    原文参考 mysql插入或更新_w_t_y_y的博客-CSDN博客_mysql 插入更新

    5.常见问题 

    详细后续补充~

  • 相关阅读:
    java 企业工程管理系统软件源码+Spring Cloud + Spring Boot +二次开发+ MybatisPlus + Redis
    【机器学习】LSTM 讲解
    docker(二)容器的启动,停止,删除
    奇瑞金融:汽车金融行业架构设计
    QT之QListView的简介
    工作流Activiti 迁移 Camunda
    你知道什么是Oracle嘛
    国庆中秋特辑(五)MySQL如何性能调优?下篇
    [含论文+开题+任务书+中期检查+源码等]S2SH+mysql音乐网站[包运行成功]适合计算机毕业设计Java毕设程序设计
    《深入理解Spark RDD缓存机制》(第4天)
  • 原文地址:https://blog.csdn.net/hauchun/article/details/126488062