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

您所在的位置:网站首页 mybatis查到数据返回null 吐血解决MyBatis连表查询(3张表)从表字段为null问题(使用VO)

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

#吐血解决MyBatis连表查询(3张表)从表字段为null问题(使用VO)| 来源: 网络整理| 查看: 265

背景

最近刚换了新工作,面试题周末再慢慢整理放上来。先说这次问题,刚进入新公司,领导直接让我参与他在做的一个项目,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种解决办法:

根据连表查询结果集aBc重新建一个aBc.java,同VO实体类的原理(创建麻烦,但是层次清晰);使用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 ckdCartonList = ckdCartonService.findCkdCartons(pageNum, pageSize, ckdCartonVO); return ResponseBean.success(ckdCartonList); } 2. Service层 public interface CkdCartonService { // ② service接口 PageVO 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 findCkdCartons(Integer pageNum, Integer pageSize, CkdCartonVO ckdCartonVO) { PageHelper.startPage(pageNum, pageSize); // ④ 注意这里调用了mapper映射层接口的方法(与mapper.xml对应)此处方法名与mapper接口方法名重名,但不是必须哈,不要被误导 List ckdCartonVOList=ckdCartonMapper.findCkdCartons(ckdCartonVO); PageInfo info = new PageInfo(ckdCartonVOList); return new PageVO(info.getTotal(), ckdCartonVOList); } } 4. mapper层 public interface CkdCartonMapper extends Mapper { // 这里接口继承了通用Mapper,里面封装的是CkdCarton对象,就是获取它的属性字段而已。而且我们都知道mybatis不用写mapper.java的实现,它帮我们做了 List findCkdCartons(CkdCartonVO ckdCartonVO); }

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

5. mapper.xml sql查询 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` and po.purchase_order like concat('%',#{purchase_order}, '%') and pa.pallet_number like concat('%',#{pallet_number}, '%') and ca.carton_number like concat('%',#{carton_number}, '%')

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

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

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



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3