项目使用Spring Data JPA作为数据层的框架,用来操作数据库。
其支持使用 @Query 注解来自定义查询语句,正是此功能,遇到了一个问题,返回的结果集包含了null的元素
项目中有 用户表、角色表、用户关联角色表,想要实现通过角色ID查询所有相关联用户信息。
代码如下,大家可以先思考下异同:
public interface UserToRoleDao extends JpaRepositoryImplementation<UserToRolePO, String> {
@Query("select u from UserToRolePO utr left join UserPO u on utr.userId = u.id and utr.roleId = ?1")
List<UserPO> findUsersByRoleId(String roleId);
@Query("select u from UserToRolePO utr left join UserPO u on utr.userId = u.id where utr.roleId = ?1")
List<UserPO> findUsersByRoleId2(String roleId);
}
有区别吗?
是的,sql的左后一段,判断roleId用了不同的方式。
findUsersByRoleId 方法使用了 and,findUsersByRoleId2方法使用了 where。
最终的结果就是,当查询的角色并没有关联任何一个用户时,findUsersByRoleId 返回了拥有1个元素的list,但是这一个元素是null;findUsersByRoleId2 返回了一个空的list。
探究下所以然,开启了jpa的show_sql = true。当执行查询时打印日志。在控制台看到两个查询对应的sql语句。
@Query("select u from UserToRolePO utr left join UserPO u on utr.userId = u.id and utr.roleId = ?1")
List<UserPO> findUsersByRoleId(String roleId);
对应的sql,记为sql1:
SELECT
userpo1_.id AS id1_13_,
userpo1_.name AS name10_13_,
userpo1_.nickname AS nicknam11_13_,
userpo1_.password AS passwor12_13_
FROM
role_to_user roletou0_
LEFT OUTER JOIN sys_user userpo1_ ON (
roletou0_.user_id = userpo1_.id
AND roletou0_.role_id = '?'
)
///
///
@Query("select u from UserToRolePO utr left join UserPO u on utr.userId = u.id where utr.roleId = ?1")
List<UserPO> findUsersByRoleId2(String roleId);
对应的sql是,记为sql2:
SELECT
userpo1_.id AS id1_13_,
userpo1_.name AS name10_13_,
userpo1_.nickname AS nicknam11_13_,
userpo1_.password AS passwor12_13_
FROM
role_to_user roletou0_
LEFT OUTER JOIN sys_user userpo1_ ON (
roletou0_.user_id = userpo1_.id
)
WHERE
roletou0_.role_id = '?'
}
随便填个role_id,拿这两条sql语句分别在数据库中执行,果然,返回结果是不一样的。(如果是在图形化工具上执行sql,可能看到结果是一样的。为了避免图形化工具瞎掺和的情况,博主特意在shell窗口执行sql。)
开启shell终端,执行 mysql -uroot -proot
登录mysql,执行 use test_db;
切换到指定数据库。
分别执行上述sql语句,可以看到,
sql1 返回了一行全是null值的记录。
sql2返回了 “Empty set”
这就可以初略解释为什么两种写法在程序中的结果不一致。至于msyql是如何解析执行sql的,等有时间再研究吧。
end