一. mybatis的PageHelper分页插件使用
Mybatis使用插件Mybatis-PageHelper进行翻页(SpringMVC+Spring+Mybatis-PageHelper)_pagehelper翻页_Orient_的博客-优快云博客
https://www.cnblogs.com/QingXiaxu/p/8247164.html
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.IGNORED
或FieldStrategy.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;