Mybatis 使用总结

一. mybatis的PageHelper分页插件使用

Mybatis使用插件Mybatis-PageHelper进行翻页(SpringMVC+Spring+Mybatis-PageHelper)_pagehelper翻页_Orient_的博客-优快云博客

https://www.cnblogs.com/QingXiaxu/p/8247164.html

mybatis的PageHelper分页插件使用 - 简书

https://www.cnblogs.com/cjsblog/p/9372258.html

二.mybatisPlus 的 pagination插件使用

Service 代码:

 @Override
    public List<XfComplainModel> listComplain(XfComplainParam param, XfUser user) {
        Page<XfComplainModel> complainModelPage = new Page<XfComplainModel>(param.getCurrent(), param.getSize() == 0 ? 10 : param.getSize());
        complainModelPage.setSearchCount(false);
        transferOrderType(param);
        List<XfComplainModel> list = baseMapper.listComplain(complainModelPage, param);
        list.forEach(xfComplainModel -> {
            fillComplainListTag(xfComplainModel, user);
        });
        return list;
    }


interface 代码:

List<XfComplainModel> listComplain(Pagination xfComplainModelPage, XfComplainParam param);

三、mapping 映射

1.其中collection 里面的id列,如 <id column="fileId" property="fileId"/>,可以保证collection结果集合中fileId数据唯一,即去重;

参考文章:mybatis – MyBatis 3 | XML 映射器

应用实例:

<resultMap id="complainInfoResult" type="com.shencai.xf.complain.model.XfComplainModel">
        <result column="id" property="id"/>
        <result column="parentId" property="parentId"/>
        <result column="createBy" property="createBy"/>

        <collection property="pollutionSourceList" ofType="com.shencai.xf.complain.model.XfComplainPollutionSourceModel"
                    column="complainId">
            <result column="codeId" property="codeId"/>
            <result column="codeName" property="codeName"/>
        </collection>
        <collection property="caseSourceList" ofType="com.shencai.xf.complain.model.XfComplainSourceModel"
                    column="complainId">
            <result column="sourceId" property="sourceId"/>
            <result column="sourceCode" property="sourceCode"/>
            <result column="sourceName" property="sourceName"/>
        </collection>
        
        <collection property="localeSurveyList" ofType="com.shencai.xf.complain.entity.XfLocaleSurvey"
                    column="complainId">
            <id column="fileId" property="fileId"/>
            <!--<result column="fileId" property="fileId"/>-->
            <result column="fileType" property="fileType"/>
            <result column="fileName" property="fileName"/>
            <result column="fileAddress" property="fileAddress"/>
        </collection>
        
    </resultMap>

2.一对一、一对多结果集映射

<select id="getManageResult" parameterType="com.shencai.xf.complain.entity.XfComplain"
            resultMap="manageResultRef">
        SELECT
            manage.id,
            manage.complainId,
            manage.orgId,
            manage.handingResult,
            org.orgName,
            parentOrg.orgName AS handleOrgName,
            ent.id,
            ent.spName
        FROM xf_complain_manage manage
        LEFT JOIN system_org org on org.id = manage.orgId and org.deleteFlag = '0'
        LEFT JOIN system_org parentOrg on parentOrg.orgCode = org.parentOrgCode and parentOrg.deleteFlag = '0'
        LEFT JOIN xf_complain_enterprise complainEnt on complainEnt.complainId = manage.complainId and complainEnt.deleteFlag = '0'
        LEFT JOIN xf_enterprise ent on ent.id = complainEnt.enterpriseId AND ent.deleteFlag = '0'
        WHERE manage.complainId = #{id}
    </select>

<resultMap id="manageResultRef" type="com.shencai.xf.evaluate.model.ReturnVisitModel">
        <result column="complainId" property="complainId" />
        <association property="manage" javaType="com.shencai.xf.manage.entity.XfComplainManage">
            <id column="id" property="id"/>
            <result column="complainId" property="complainId"/>
            <result column="orgId" property="orgId"/>
            <result column="handingResult" property="handingResult"/>
            <result column="handleOrgName" property="deptName"/>
        </association>
        <collection property="enterpriseList" ofType="com.shencai.xf.complain.entity.XfEnterprise">
            <result column="spName" property="spName"/>
        </collection>
    </resultMap>

四、高级搜索时,一对多和多对多的情况下,匹配查询解决方法 FIND_IN_SET

1.说明

FIND_IN_SET(s1,s2) , 返回在字符串s2中与s1匹配的字符串的位置,例如:

返回字符串 c 在指定字符串中的位置:SELECT FIND_IN_SET("c", "a,b,c,d,e");

2.真实场景

<--! 一对多 -->
<if test="pollutionCtg != null and pollutionCtg != '' ">
    AND FIND_IN_SET (#{pollutionCtg},pollution.fullCodeId)
</if>


<--! 多对多 -->
<if test="pollutionCtgIds != null and pollutionCtgIds.size >0 ">
    AND
    <foreach item="item" index="index" collection="pollutionCtgIds"
             open="(" separator="OR" close=")">
        FIND_IN_SET (#{item},pollution.fullCodeId)
    </foreach>
</if>

五、数据更新操作时,SQL级别判断空值不进行更新,非空时进行更新,解决方案COALESCE

1.说明

COALESCE(expr1, expr2, ...., expr_n):返回参数中的第一个非空表达式(从左向右),例如:

SELECT COALESCE(NULL, NULL, NULL, 'runoob.com', NULL, 'google.com');
-> runoob.com

2.真实场景

<update id="updateById" parameterType="com.shencai.xf.config.entity.XfOrg">
      update system_org
      set orgCode = #{orgCode},
          orgName = #{orgName},
          areaCode = #{areaCode},
          parentOrgCode = #{parentOrgCode},
          isDefaultHandleOverOrg = COALESCE(#{isDefaultHandleOverOrg},isDefaultHandleOverOrg),
          isOfficeLeader = COALESCE(#{isOfficeLeader},isOfficeLeader),
          isWorkOrg = COALESCE(#{isWorkOrg},isWorkOrg),
          workOrgType = COALESCE(#{workOrgType},workOrgType),
          isRegisterOrg = COALESCE(#{isRegisterOrg},isRegisterOrg),
          editBy = #{editBy},
          editTime = #{editTime}
      where id = #{id}
    </update>

六、mybatis 的xml写SQL语句时,<if> 判断可以在任何位置使用

SELECT子句中可以使用, FROM子句中可以使用,WHERE子句中可以使用, <if> 标签内部还可以嵌套使用

 (select 子句中使用 group_concat 组合结果时,一定要配合 group by complain.id 一起使用)

 SELECT
        <if test="acceptStartTime!=null or acceptEndTime!=null">
            DISTINCT
        </if>
        complain.id,
        complain.caseCode,
        group_concat(distinct ent.spName order by ent.spName) AS spName,
FROM xf_complain complain
        left join xf_complain_sound_recoding soundRecoding on soundRecoding.complainId = complain.id
        LEFT join xf_complain_enterprise complainEnt on complainEnt.complainId = complain.id AND complainEnt.deleteFlag='0'
        LEFT JOIN xf_enterprise ent on ent.id = complainEnt.enterpriseId and ent.deleteFlag = '0'
        <if test="zhiFlag!=null and zhiFlag != '' ">
            left join xf_complain_zhifa_rel zhiFaRel
            on zhiFaRel.complainId  = complain.id  and zhiFaRel.deleteFlag = '0'
        </if>
        <if test="agent!=null and agent=='0'.toString()">
            left join xf_complain_user_rel xcur on xcur.complainId=complain.id and xcur.deleteFlag='0'
            <if test="loginUserId != null and loginUserId != ''">
                and xcur.userId = #{loginUserId}
            </if>
        </if>
        <if test="acceptStartTime!=null or acceptEndTime!=null">
            left join xf_operate operate on complain.id=operate.complainId and operate.deleteFlag='0'
        </if>
WHERE complain.deleteFlag = '0'
        <if test="agent!=null and agent=='0'.toString()">
            <if test="loginUserId != null and loginUserId != ''">
                and xcur.userId = #{loginUserId}
            </if>
        </if>
group by complain.id

七.mybatis-plus 之 QueryWrapper 的使用

单表查询的时候,可以不需要写SQL,而使用 QueryWrapper 拼接语句 (建议使用LambdaQueryWrapper)

1.and()方法

当只想进行简单的条件链接时,只需将查询条件直接连写即可,拼装后的sql就是用and连接的

//代码
List<VisitActHandleLog> list = visitActHandleLogService.list(
                new QueryWrapper<VisitActHandleLog>()
                .eq("from_app_type", "wx")
                .eq("zf_code", "M106944")
        );
// sql条件部分
WHERE
	( from_app_type = ? AND zf_code = ? ) 

2.or()方法

条件之间需要用or进行连接,需要调用or()方法,拼装的sql条件就可用or连接

//代码
 List<VisitActHandleLog> list = visitActHandleLogService.list(
                new QueryWrapper<VisitActHandleLog>()
                .eq("from_app_type", "wx")
                .or()
                .eq("zf_code", "M106944")
        );
//sql条件部分
WHERE
	 (from_app_type = ? OR zf_code = ?) 

3.and()和or()连用

在许多查询中可能会用到(A or B)and (C or D)或者 (A and B) or (C and D)这种形式的查询,简单的将and()和or()进行连接,无法在条件上拼接(),变成A or B and C or D这种,无法实现功能,需要在代码中调用or(Consumer consumer)和and(Consumer consumer)这两个方法实现。

//代码
List<VisitActHandleLog> list = visitActHandleLogService.list(
                new QueryWrapper<VisitActHandleLog>()
                .eq("from_app_type", "wx")
                .or(qw->qw.eq("zf_code", "M106944").eq("channel","test"))
        );
//sql条件部分
WHERE
	( from_app_type = ? OR ( ( zf_code = ? AND channel = ? ) ) )

这样就可以在or的后面拼接(),实现功能,and()也是如此:

.and(qw->qw.eq("zf_code", "M106944").eq("channel","test"))

like和or一起使用

public PageUtils queryPage(PartsVO partsVO) {
        Page<Parts> page = new Page<>(partsVO.getPageNo(), partsVO.getPageSize());
        QueryWrapper<Parts> wrapper = new QueryWrapper<>();
        if (StringUtils.isNotEmpty(partsVO.getMultiMatchField()) && StringUtils.isNotBlank(partsVO.getMultiMatchField())){
            wrapper.lambda().like(Parts::getPartsNo, partsVO.getMultiMatchField())
                    .or().like(Parts::getPartsBatch,partsVO.getMultiMatchField())
                    .or().like(Parts::getProductCode,partsVO.getMultiMatchField());
        }
        wrapper.lambda().orderByDesc(Parts::getBatchScantime);
        Page<Parts> selectPage = baseMapper.selectPage(page, wrapper);
        return new PageUtils(selectPage);
    }

   a  and ( b or c) 的写法

 LambdaQueryWrapper<Oilpump> oilpumpWrapper = new QueryWrapper<Oilpump>().lambda()
                .eq(Oilpump::getOilPumpIdNr, st310.getPumpIdNr())
                .and(e-> e.isNull(Oilpump::getTrmNr).or().eq(Oilpump::getTrmNr,""))
                .orderByDesc(Oilpump::getDateTime).last("limit 1");

4.使用 QueryWrapper实现查询字段控制

场景1:当查询实体中某些字段不需要的时候,可以设置条件过滤,这样查询结果就不会返回,比如icon图片字段较长,可以设置查询结果排除。

/**
     * 查应用模板
     * @param applicationCode
     * @return
     */
    public ApplicationEntity selectTemplateSimpleByCode(String applicationCode) {
        LambdaQueryWrapper<ApplicationEntity> queryWrapper = new LambdaQueryWrapper<ApplicationEntity>();
        queryWrapper.select(ApplicationEntity.class, info -> !info.getColumn().equals("application_icon"));
        queryWrapper.eq(ApplicationEntity::getApplicationCode, applicationCode);
        queryWrapper.isNull(ApplicationEntity::getTenantId);
        queryWrapper.last(CommonConstants.LIMIT_ONE.getMessage());
        return mapper.selectOne(queryWrapper);
    }

场景2:指定查询字段,而不是返回全部

queryWrapper.select(KdgcType::getTypeCode,KdgcType::getTypeName);

八.mybatis-plus 之 LambdaQueryWrapper 的使用

功能与QueryWrapper类似,然而使用 LambdaQueryWrapper 可以避免查询条件字段代码 hard code。

LambdaQueryWrapper<KdgClass> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(KdgClass::getOrgId, orgId);
        if(StringUtils.isNotBlank(className)) {
            wrapper.like(KdgClass::getClassName, "%" + className + "%");
        }
if(!isKdgAdminUser()) {
            //非管理员,老师只能看到自己的班级
            List<Integer> classIdList = kdgClassTeacherService.findKdgClassIdList();
            classIdList = Optional.ofNullable(classIdList).orElseGet(() -> {
                List<Integer> list = new ArrayList<>();
                list.add(0);
                return list;
            });
            wrapper.in(KdgClass::getId, classIdList);
        }
PageInfo<KdgClass> pageInfo = listPage(wrapper, request);

九.根据前端参数动态排序

1.请求类中定义排序字段和排序类型字段

/**
     * 排序类型和排序字段
     */
    @ApiModelProperty(value = "排序字段", name="orderField",example = "registerTime,orderTime,courseBeginTime")
    private String orderField;

    @ApiModelProperty(value = "排序类型", name="orderType",example = "ASC,DESC")
    private String orderType;

2.查询的 SQL 最后添加如下代码

        ****
        GROUP BY userBill.id
        <if test="orderField != null and orderField != ''">
            ORDER BY
            <choose>
                <when test="orderField == 'registerTime'">
                    upm.register_date ${orderType}
                </when>
                <when test="orderField == 'orderTime'">
                    userBill.create_time ${orderType}
                </when>
                <when test="orderField == 'courseBeginTime'">
                    userBill.target_start_time ${orderType}
                </when>
            </choose>
        </if>
        <if test="orderField == null or orderField == ''">
            ORDER BY upm.register_date DESC
        </if>

十.mybatis中<if> 标签中不同数据类型判断方式

1.String类型

<if test="agent!=null and agent=='0'.toString()">
            left join xf_complain_user_rel xcur on xcur.complainId=complain.id and xcur.deleteFlag='0'
            <if test="loginUserId != null and loginUserId != ''">
                and xcur.userId = #{loginUserId}
            </if>
</if>

2.Boolean类型

<if test="isQuit != null and 'true'.toString() == isQuit.toString()">
  AND stage = 7
</if>

<if test="publicSeaFlag != null and 'true'.toString() == publicSeaFlag.toString()">
            ,`public_sea_flag` = b'1'
</if>
 <if test="publicSeaFlag != null and 'false'.toString() == publicSeaFlag.toString()">
            ,`public_sea_flag` = b'0'
 </if>

十一,批量操作

1.批量插入例子

<insert id="batchInsert" parameterType="java.util.List">
                INSERT INTO kdgc_bi_kanban_module
                (bi_kanban_code,module_code,module_name,module_type,
                module_content,data_set_busi_code,description,create_time,update_time,sort)
                values
                <foreach collection="biModuleList" item="module" separator="," index="index">
                   ( #{module.biKanbanCode},
                        #{module.moduleCode},
                        #{module.moduleName},
                        #{module.moduleType},
                        #{module.moduleContent},
                        #{module.dataSetBusiCode},
                        #{module.description},
                        #{module.createTime},
                        #{module.updateTime},
                        #{module.sort}
                        )
                </foreach>
        </insert>

2.批量更新

<update id="updateBatchById">
    <foreach collection="list" item="item" separator=";">
        update
            `t_student`
        set
            `name` = #{item.name},
            `age` = #{item.age}
        where
            id = #{item.id}
    </foreach>
</update>

这条SQL长串会一次性发送给数据库执行,只需要进行一次网络IO,提高了效率。当然,默认情况下,数据库是不支持执行这样由";“号拼接的长串的,执行的时候会报错,提示说执行的SQL有语法错误。我们需要通过在数据库连接URL中指定allowMultiQueries参数值为true告诉数据库以支持”;"号分隔的多条语句的执行。

spring.datasource.url=jdbc:mysql://localhost:3306/test?allowMultiQueries=true

十二、设置字段更新规则

当发现更新数据的时候,null值没有更新,可以采用如下两种方式

(1)如果希望所有实体的更新操作都支持空值更新,可以修改 Mybatis-Plus 的全局更新策略。这需要在项目的配置文件中进行设置。例如,在 Spring Boot 项目中,可以在 application.yml 或 application.properties 文件中添加如下配置:

mybatis-plus:
  global-config:
    db-config:
      update-strategy: ignored

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #开启sql打印
    call-setters-on-nulls: true
  mapperLocations:
    - classpath*:/mapper/**/*.xml
    - classpath*:/modeler-mybatis-mappings/**/*.xml
  global-config:
    db-config:
      update-strategy: ignored

(2)字段级别的更新策略

如果只是希望实体中的某几个字段支持空值更新,可以在这些字段上通过 @TableField 注解指定字段的更新策略为 FieldStrategy.IGNOREDFieldStrategy.ALWAYS。这样就可以忽略空值判断,直接更新字段为 null。这种方式是字段级别的控制。

public class User {
    private Long id;

    @TableField(updateStrategy = FieldStrategy.IGNORED)
    private String email;

    // 其他字段和方法
}

十三、mybatis-plus配置

# mybatis-plus配置
mybatis-plus:
  mapper-locations: classpath*:/mapper/**/*Mapper.xml
  #实体扫描,多个package用逗号或者分号分隔
  #typeAliasesPackage:
  configuration:
    call-setters-on-nulls: true
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #打印sql语句,调试用
  global-config:
    #数据库相关配置
    db-config:
      #主键类型  AUTO:"数据库ID自增", INPUT:"用户输入ID", ID_WORKER:"全局唯一ID (数字类型唯一ID)", UUID:"全局唯一ID UUID";
      id-type: ASSIGN_ID
      logic-delete-field: delFlag
      logic-delete-value: 1
      logic-not-delete-value: 0
    banner: false

(1)其中下面的配置用于打印日志:

map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #打印sql语句,调试用

(2)下面的配置用于生成UUID:
id-type: ASSIGN_ID

十三、值填充规则

(1)mybatis支持数据插入和更新类型,使用的时候可以根据需要指定:

DEFAULT,
INSERT,
UPDATE,
INSERT_UPDATE

    @TableField(value = "CREATE_BY", fill = FieldFill.INSERT)
    private String createBy;

    @TableField(value = "CREATE_TIME", fill = FieldFill.INSERT)
    private Date createTime;

    @TableField(value = "UPDATE_BY", fill = FieldFill.INSERT_UPDATE)
    private String updateBy;

    @TableField(value = "UPDATE_TIME", fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;

(2)逻辑删除

  @TableLogic

    @TableField("DEL_FLAG")
    @TableLogic
    private String delFlag;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值