吐血解决MyBatis连表查询(3张表)从表字段为null问题(使用VO)

40 篇文章 2 订阅
27 篇文章 1 订阅

背景

最近刚换了新工作,面试题周末再慢慢整理放上来。先说这次问题,刚进入新公司,领导直接让我参与他在做的一个项目,Spring Boot+MyBatis+ Shiro +Vue,反正就这些技术栈,不是重点。重点是领导做了个多表关联查询,前台获取结果列表显示总是显示主表的所有字段,要显示的从表的两个字段均为空。让我看看怎么回事。这问题困扰了我两天,也是自己菜,刚工作一年,里面很多代码,设计逻辑都特么硬学。好在终于解决这个问题了,攻克难关的感觉太美好了(菜鸡轻喷)。

先上总结

记录一下网上查找时这类问题解决办法:

首先 确保mapper.xml标签与mapper.java中的方法名对应,与它所在的包路径对应
其次确保 sql语句字段 数据库字段——sql查询——实体类属性 一摸一样

上述没问题情况下, 可能原因:
① 数据库字段名使用了_下划线,但是实体类属性名用的驼峰命名(这种情况下如果不想写mybatis-config.xml,直接在application.yml中配置开启驼峰命名):

mybatis:
  mapper-locations: classpath*:mapper/*/*Mapper.xml
  configuration:    # 开启驼峰命名规则
    map-underscore-to-camel-case: true

② 数据库字段名使用了_下划线,实体类属性名与它一摸一样也是下划线。此时注意要关闭 驼峰命名配置!!!否则匹配不到,结果为null。
直接一摸一样最好,省的还要配置驼峰命名。

③ 假设A,B, C 表,查询结果集算作aBc,有可能你把关系表aBc表的字段映射到A表的属性里,那当然除了A表的字段,其他都查不到。这里有2种解决办法:

  1. 根据连表查询结果集aBc重新建一个aBc.java,同VO实体类的原理(创建麻烦,但是层次清晰);
  2. 使用resultMap,将实体表映射到关系表,即在关系表实体类A中定义B、C的类对象(或者集合)。但这里又涉及到resultMap的关联映射。(id,result,association,collection标签的作用)周末我再总结一下。(方便快捷,但修改了原实体类,不太好,个人拙见)

④ 也是我的原因,领导一直在拿查询单表的实现方法调用mapper.java中查连表查询的mapper.xml (即xml文件没问题,但是id对应的方法不对)现在看来,问题很简单,主要大部分时间还是用来捋清整套代码的业务以及调用逻辑了。。。不过顺便学到了很多其他的知识,不虚此行哈哈哈。

个人问题及原因

首先,项目中大量地采用了将查询结果集封装成VO类的写法,(是我菜,这种方式第一次接触),然后花一段时间理解了一下,大概就是和数据库表对应的实体类区别开来吧,专门用作自定义结果集封装。贴几段代码出来捋一下调用流程:

1. Controller层 接口

    public ResponseBean findCkdCartonList(
            @RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
            @RequestParam(value = "pageSize") Integer pageSize,
            CkdCartonVO ckdCartonVO) {
// ① 这里调用了Service层的 findCkdCartons()方法           
        PageVO<CkdCartonVO> ckdCartonList = ckdCartonService.findCkdCartons(pageNum, pageSize, ckdCartonVO);
        return ResponseBean.success(ckdCartonList);
    }

2. Service层

public interface CkdCartonService {
	// ② service接口
	PageVO<CkdCartonVO> findCkdCartons(Integer pageNum, Integer pageSize, CkdCartonVO ckdCartonVO);
}

3. ServiceImpl

@Transactional
@Service
public class CkdCartonServiceImpl implements CkdCartonService {
	// 注入Mapper接口
	@Autowired
    private CkdCartonMapper ckdCartonMapper;
	
	// ③  实现service接口的方法
	@Override
    public PageVO<CkdCartonVO> findCkdCartons(Integer pageNum, Integer pageSize, CkdCartonVO ckdCartonVO) {
        PageHelper.startPage(pageNum, pageSize);
        // ④  注意这里调用了mapper映射层接口的方法(与mapper.xml对应)此处方法名与mapper接口方法名重名,但不是必须哈,不要被误导
        List<CkdCartonVO> ckdCartonVOList=ckdCartonMapper.findCkdCartons(ckdCartonVO);
        PageInfo<CkdCartonVO> info = new PageInfo<>(ckdCartonVOList);
        return new PageVO<>(info.getTotal(), ckdCartonVOList);
    }
}

4. mapper层

public interface CkdCartonMapper extends Mapper<CkdCarton> {

    // 这里接口继承了通用Mapper,里面封装的是CkdCarton对象,就是获取它的属性字段而已。而且我们都知道mybatis不用写mapper.java的实现,它帮我们做了
    List<CkdCartonVO> findCkdCartons(CkdCartonVO ckdCartonVO);
}    

自定义封装的结果集CkdCartonVO 比 CkdCarton 多了两个字段,即前面提到的另外两张表的主键id。

5. mapper.xml sql查询

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yunsystem.business.mapper.CkdCartonMapper">
<select id="findCkdCartons"  parameterType="com.yunsystem.common.vo.business.CkdCartonVO"
            resultType="com.yunsystem.common.vo.business.CkdCartonVO">
        SELECT ca.*, pa.pallet_number, po.purchase_order
        FROM ckd_carton_info ca, ckd_pallet_info pa, ckd_po_info po
        WHERE ca.`pallet_id` = pa.`pallet_id` and po.`po_id`=ca.`po_id`

        <if test="purchase_order != null and purchase_order != ''">
            and po.purchase_order like concat('%',#{purchase_order}, '%')
        </if>
        <if test="pallet_number != null and pallet_number != ''">
            and pa.pallet_number like concat('%',#{pallet_number}, '%')
        </if>
        <if test="carton_number != null and carton_number != ''">
            and ca.carton_number like concat('%',#{carton_number}, '%')
        </if>
    </select>

字段解释:
namespace: 指向映射的mapper.java所在的接口路径
id=“xxxx” > 表示此段sql执行语句的唯一标识,也是接口的方法名称【必须一致才能找到】
parameterType="" >表示该sql语句中需要传入的参数, 类型要与对应的接口方法的类型一致【可选】

resultMap=“ ”> 定义出参,调用已定义的映射管理器的id值

resultType=“ ”>定义出参,匹配普通java类型或自定义的pojo【出参类型若不指定,将为语句类型默认类型,如语句返回值为int】

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值