“开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 22 天,点击查看活动详情”
引言
mybatis-plus小技能:多表查询【预备知识篇】blog.csdn.net/z929118967/…
内外连接:blog.csdn.net/z929118967/…
mybatis-plus小技能:多表查询【案例篇】blog.csdn.net/z929118967/…
I 多表查询
1.1 多表查询:在mapper.xml 写语句和拼接查询条件
在mapper.xml 写语句,对应方法写到mapper里,service可以注入对应的mapper进行调用。
.xml
<select id="selectProfitTradeActivityList"
resultType="com.dto.TradeActivityDto"
parameterType="com.dto.GenerateTradeQuery">
select a.id,a.trade_no,a.activity_type,a.activity_code
from trans_flow t
inner join trans_flow_activity a on t.trade_no = a.trade_no
<where>
t.trade_state='S' and a.pay_channel_id='XYD'
<if test="ps.startTradeTime != null">
and t.trade_time >= #{ps.startTradeTime}
</if>
</where>
-- order by t.update_time desc
</select>
@Mapper
public interface TransFlowActivityMapper extends BaseMapper<TransFlowActivity> {
List<GenerateTradeActivityDto> selectProfitTradeActivityList(@Param("ps") GenerateTradeQuery input);
}
1.2 多表关联:Java代码中书写语句和拼接查询条件
实现思路:
- 使用
Select
注解书写sql语句 - 采用apply方法自定义sql拼接条件, 使用条件构造器作为参数。
- 驱动表表和辅表的参数拼接
${ew.customSqlSegment}
条件构造器作为参数都需要添加前缀
,否则如果有字段重名就无法明确使用哪一个。
lambda.apply("m.state = {0}", EMerchantState.NORMAL);
- 书写SQL
1.3 案例:左外连接
实现思路:
- 使用
Select
注解书写sql语句/xml书写语句。 - 采用apply方法自定义sql拼接条件, 使用wrapper条件构造器作为参数。
实现步骤:
- 定义查询接口:
mapper.java/Service.java
- Service层
@Override
public List<RiskEquipmentPositionDto> getlist(LambdaQueryWrapper<RiskEquipmentPosition> input) {
return baseMapper.getList(input);
}
-
Mapper层:采用
${ew.customSqlSegment}
和@Param(Constants.WRAPPER)
实现,将条件构造器作为参数。 -
书写SQL 方式一:使用
Select
注解书写sql语句
@Select("select r.* ,m.merchant_name,m.facilitator_id,m.facilitator_name,m.facilitator_top_id,m.facilitator_top_name from risk_equipment_position r left join mer_merchant m on r.merchant_id = m.merchant_id ${ew.customSqlSegment} ")
List<RiskEquipmentPositionDto> getList(@Param(Constants.WRAPPER) LambdaQueryWrapper<RiskEquipmentPosition> input);
where后面的内容就是条件构造器生成的部分
方式2: 使用xml书写语句
- 拼接查询条件
LambdaQueryWrapper<RiskEquipmentPosition> lambda = new LambdaQueryWrapper<>();
lambda.orderByDesc(TRiskEquipmentPosition::getCreateTime);
if (input.getStartTime() != null) {
lambda.ge(RiskEquipmentPosition::getCreateTime, input.getStartTime());
}
if (input.getEndTime() != null) {
lambda.lt(RiskEquipmentPosition::getCreateTime, input.getEndTime());
}
if (input.getState() != null) {
lambda.eq(RiskEquipmentPosition::getState, input.getState());
}
// 终端SN、商户号本表查询,其他关键词需要关联商户表进行查询。
if (null != input.getKeywordType() && StringUtils.isNotBlank(input.getKeyword())) {
var keyWordTypes = new ArrayList<String>();
keyWordTypes.add(ERiskEquipmentPositionKeyWord.MER_ID.getCode());
keyWordTypes.add(ERiskEquipmentPositionKeyWord.FAC_ID.getCode());
keyWordTypes.add(ERiskEquipmentPositionKeyWord.TOP_ID.getCode());
Long longKeyWord = 0L;
if (keyWordTypes.contains(input.getKeywordType())) {
try {
longKeyWord = Long.parseLong(input.getKeyword());
} catch (Exception ex) {
throw CommonException.create(ServerResponse.createByError("无效的编号"));
}
}
switch (BaseEnum.getEnum(ERiskEquipmentPositionKeyWord.class, input.getKeywordType())) {
case SN:
lambda.eq(RiskEquipmentPosition::getEquipmentSn, input.getKeyword());
break;
case MER_ID:
lambda.apply("r.merchant_id = {0}",input.getKeyword());
break;
case MER_NAME:
lambda.apply("m.merchant_name = {0}",input.getKeyword());
break;
case FAC_ID:
//apply方法用于拼接自定义的条件判断,如果自定义的条件判断是需要独立的结果,就必须记得加括号。
lambda.apply("m.facilitator_id = {0}",input.getKeyword());
break;
case FAC_NAME:
lambda.apply("m.facilitator_name = {0}",input.getKeyword());
break;
case TOP_ID:
lambda.apply("m.faclitator_top_id= {0}",input.getKeyword());
break;
case TOP_NAME:
lambda.apply("m.facilitator_top_name= {0}",input.getKeyword());
break;
}
}
// 分页查询
PageHelper.startPage(input.getPageNum(), input.getPageSize());
List<RiskEquipmentPositionDto> positionList = tRiskEquipmentPositionService.getlist(lambda);
PageInfo pageInfo = new PageInfo(positionList);
PageHelper.clearPage();
return pageInfo;
- 调用查询接口
List<RiskEquipmentPositionDto> positionList = RiskEquipmentPositionService.getlist(lambda);
II mybatis-Plus 之 apply 拼接 in SQL
apply(String applySql, Object... params)
apply(boolean condition, String applySql, Object... params)
2.1 apply源码实现
protected final String formatSqlMaybeWithParam(String sqlStr, String mapping, Object... params) {
if (StringUtils.isBlank(sqlStr)) {
return null;
} else {
if (ArrayUtils.isNotEmpty(params)) {
for(int i = 0; i < params.length; ++i) {
String target = "{" + i + "}";
sqlStr = sqlStr.replace(target, this.formatParam(mapping, params[i]));
}
}
return sqlStr;
}
}
2.2 apply 拼接 in SQL
从源码可以看出第二参数params 无法使用字符串"1,2"
形式。
lambda.apply("m.nature in ({0})","1,2");
如果params使用数组只会获取第一个元素。
正确的实现方式如下:直接在applySql拼接完整
String sql = "m.nature in ("+activity.getMerchantNatures()+")"; lambda.apply(sql);//activity.getMerchantNatures()
如果是主表条件可以使用
lambda.in(TMerMerchant::getNature, natures);//(nature IN (?,?)
III 常见问题
3.1 Cause: comColumn 'xxx' in where clause is ambiguous
需求: wrapper自定义sql: 使用条件构造器作为参数
1. mapper.java/Service.java定义接口方法
2. 只需添加 ${ew.customSqlSegment}
和@Param(Constants.WRAPPER)
即可
@Select("select m.* ,p.merchant_code,p.first_in_net_time from t_mer_merchant m join t_mer_pay_net_register p on m.merchant_id = p.merchant_id ${ew.customSqlSegment} ")
List<MktAllowMerchaterDto> getList(@Param(Constants.WRAPPER) LambdaQueryWrapper<TMerchant> lambda);
${ew.customSqlSegment}
条件构造器作为参数都需要添加前缀
,否则如果有字段重名就无法明确使用哪一个。
修复方式:
lambda.apply("m.state = {0}", EMerchantState.NORMAL);