在工作中遇到这个问题好多次了,不得不记录一下,因为这确实是新手开发常犯的毛病。

场景:我们在用Mybatis查询,返回List的过程中遇到的

如:以下SQL

SELECT
	t4.template_price_id,
	t4.price_name,
	t4.price,
	t4.production_line,
	t4.type,
	t4.MODE 
FROM
	project_card t
	LEFT JOIN dyeing_notice t1 ON t1.dyeing_notice_id = t.dyeing_notice_id
	LEFT JOIN dyeing_contact_price t2 ON t2.dyeing_notice_id = t1.dyeing_notice_id
	LEFT JOIN contract_price t3 ON t3.contract_price_id = t2.contract_price_id
	LEFT JOIN template_price t4 ON t4.template_price_id = t3.template_price_id 
WHERE
	t.project_card_id = 8660

看似只是简单的查询,但是它返回给我的List的是

这种返回结构确实很怪,之前我们没有查到也是返回list的size() = 0,现在返回了一个size()=1,但是第一条又啥都没有?

仔细分析这段SQL,拿到Navicat跑一下

如果你只是关注返回的结果,可能还是对发生问题的原因扑朔迷离,但仔细看右下角的查出一条记录,通过这个现象我们其实可以分析出,MyBatis的映射是没问题的,只是查出的List的第一条是null,所以问题很有可能是我们的SQL查询的结果有问题。

所以分析到这我们只需要对我们要<mark>查询的结果集</mark>和SQL连接拆解分析就出来了,遇到多表的连接查询问题或SQL优化的一个办法就是把大问题分解,把SQL连接慢慢分解。

SELECT
	t.*
FROM
	project_card t
	LEFT JOIN dyeing_notice t1 ON t1.dyeing_notice_id = t.dyeing_notice_id
	LEFT JOIN dyeing_contact_price t2 ON t2.dyeing_notice_id = t1.dyeing_notice_id
	WHERE
	t.project_card_id = 8660

SELECT
	t.*
FROM
	project_card t
	LEFT JOIN dyeing_notice t1 ON t1.dyeing_notice_id = t.dyeing_notice_id
	LEFT JOIN dyeing_contact_price t2 ON t2.dyeing_notice_id = t1.dyeing_notice_id
	LEFT JOIN contract_price t3 ON t3.contract_price_id = t2.contract_price_id
	LEFT JOIN template_price t4 ON t4.template_price_id = t3.template_price_id 
WHERE
	t.project_card_id = 8660

都是有结果的,但是只要连接contract_price,template_price ,上就获取不到contract_price和template_price 的数据了

SELECT
	t3.*,t4.*
FROM
	project_card t
	LEFT JOIN dyeing_notice t1 ON t1.dyeing_notice_id = t.dyeing_notice_id
	LEFT JOIN dyeing_contact_price t2 ON t2.dyeing_notice_id = t1.dyeing_notice_id
	LEFT JOIN contract_price t3 ON t3.contract_price_id = t2.contract_price_id
	LEFT JOIN template_price t4 ON t4.template_price_id = t3.template_price_id 
WHERE
	t.project_card_id = 8660

所以问题就出来了,就是t2 没有t3的关联id,根据左连接特性,左连接连到t3,t4后,它们都是null,所以返回的也就是null,符合错误现象。

<mark>注意:</mark>
以后我们要避免这种写法,获取哪一张表的信息,尽量使用它当作主表,否则就应该使用内连接(Inner join)避免这种问题。