公司业务要求,将邀请用户全部做成层级表放在邀请人的下面,需要使用到递归查询.
首先现将尝试过的递归方法写下来,有的虽然可以实现递归但与业务不相契合,所以弃用
1.树结构查询
我们的这个需求符合树形结构,所以树状查询才符合业务要求(之前找到过一篇自己写的树状结构工具的文章找不到了,写的挺好的可惜的是他是查询父级和下面子集的,不符合业务要求),我们需要的是向下树状查找.
2.Hutool工具实现
使用该工具也可以实现树状结构查询,也能满足业务需求,但是返回结果只能返回Tree<String>数据,很无奈也放弃了.
public HashMap<UserDO, List<Tree<String>>> getChildUserList() {
//获取所有数据
List<UserDO> list = userMapper.selectList(null);
//具有顶级特征的集合
List<UserDO> fatherList = userMapper.selectList(new EntityWrapper<UserDO>().isNull("inv_id"));
// huTool工具构建树形结构对象
TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
//数结构主键ID
treeNodeConfig.setIdKey("id");
//父结构ID
treeNodeConfig.setParentIdKey("inviteUserId");
//子节点
treeNodeConfig.setChildrenKey("childList");
//存放父节点和其下面的子节点
HashMap<UserDO, List<Tree<String>>> userDOListHashMap = new HashMap<>();
for (UserDO fatherDO : fatherList) {
List<Tree<String>> treeNodes = TreeUtil.build(list, fatherDO.getId().toString(), treeNodeConfig, (treeNode, tree) -> {
tree.setId(treeNode.getId().toString());
if (treeNode.getInviteUserId() != null) tree.setParentId(treeNode.getInviteUserId().toString());
//扩展属性
tree.putExtra("childList", treeNode.getChildList());
tree.putExtra("phone", treeNode.getPhone());
tree.putExtra("loginType", treeNode.getLoginType());
tree.putExtra("openId", treeNode.getOpenId());
tree.putExtra("nickname", treeNode.getNickname());
tree.putExtra("avatarUrl", treeNode.getAvatarUrl());
tree.putExtra("gmtLastLogin", treeNode.getGmtLastLogin());
tree.putExtra("lastLoginIp", treeNode.getLastLoginIp());
tree.putExtra("status", treeNode.getStatus());
tree.putExtra("level", treeNode.getLevel());
tree.putExtra("levelExTime", treeNode.getLevelExTime());
tree.putExtra("IndustryAgentDO", treeNode.getIndustryAgentDO());
});
userDOListHashMap.put(fatherDO, treeNodes);
}
return false;
return userDOListHashMap;
}
3.在Java代码中实现递归
上面都不符合要求,那就自己写吧,自己写了一套递归,但是又感觉不合适,因为如果要在程序中进行递归查询必须要读取数据库中所有用户数据到服务器中,如果数据量大的话服务器就崩了(而且我就是个后台程序啊!我把所有用户数据都读过来干嘛?!!!占用业务资源不说,我服务器就只有4g啊现在)
考虑到服务器太拉了,也不知道以后数据量,那么只能把这个重担还给Mysql了
public UserDO getChildUserList(Long adminId, Long userId) {
UserDTO fatherUserDO = userMapper.getUserById(userId);
List<UserDO> childList = getChild(userId, userMapper.selectList(null));
if (childList.size() == 0) return fatherUserDO;
fatherUserDO.setChildList(childList);
return fatherUserDO;
}
/**
* 递归查询子类集合
*
* @param id 父级id
* @param allUser 子类集合
* @return 返回查询到的子集合
*/
public List<UserDO> getChild(Long id, List<UserDO> allUser) {
//子菜单
List<UserDO> childList = new ArrayList<UserDO>();
for (UserDO user : allUser) {
// 遍历所有节点,将所有菜单的父id与传过来的根节点的id比较
//相等说明:为该根节点的子节点。
if (id.equals(user.getInviteUserId())) {
childList.add(user);
}
}
//递归
for (UserDO user : childList) {
user.setChildList(getChild(user.getId(), allUser));
}
//Collections.sort(childList,order());//排序
//如果节点下没有子节点,返回一个空List(递归退出)
if (childList.size() == 0) {
return new ArrayList<UserDO>();
}
return childList;
}
4.使用Mybatis来进行递归查询
其实一开始也看见很多SQL和mybatis的递归,但是考虑到数据库的性能和查询时间的优化并没有第一时间考虑,但是上面几个方法Pass后没办法,只能使用这个办法解决了,Mysql你忍着点,我数据递归不会超过六轮的~^~.
Java代码:
/**
* 查询邀请层级表信息
*
* @param userId 需查询的用户ID
* @return
*/
@Override
public UserDO getChildUserList(Long adminId, Long userId) {
UserDO fatherUserDO = userMapper.selectById(userId);
fatherUserDO.setChildList(userMapper.getUserTree(userId));
return fatherUserDO;
}
Mybatis xml文件
<resultMap id="userTree" type="com.iotechn.unimall.data.domain.UserDO">
<id property="id" column="id"/>
<result property="id" column="id"/>
<result property="phone" column="phone"/>
<result property="password" column="password"/>
<result property="loginType" column="login_type"/>
<result property="openId" column="open_id"/>
<result property="nickname" column="nickname"/>
<result property="avatarUrl" column="avatar_url"/>
<result property="gmtLastLogin" column="gmt_last_login"/>
<result property="lastLoginIp" column="last_login_ip"/>
<result property="status" column="status"/>
<result property="isMessagePush" column="is_message_push"/>
<result property="level" column="level"/>
<result property="levelExTime" column="level_ex_time"/>
<result property="isRecommend" column="is_recommend"/>
<result property="inviteUserId" column="inv_id"/>
<!-- <collection column="id" property="industryAgentDO" select="findIndustry"/>-->
<collection column="id" property="childList" select="getChild"/>
</resultMap>
<select id="getUserTree" resultMap="userTree">
select *
from `unimall_user`
where inv_id = #{userId}
</select>
<select id="getChild" resultMap="userTree">
select *
from `unimall_user`
where inv_id = #{pid}
</select>
这样就也是使用递归进行查询了,以前也没用过mybatis递归查询过,一条sql有时候确实感觉挺爽的,所以深入学习一下.
mybaits 中的参数传递 :
property:指定关联属性,即类中的属性字段变量名
ofType:集合属性的泛型类型 可为基本类型(mybatis会自动匹配可以不写)
column 传入参数 column=“cid” 可传多个 column=“{cid,mname}” 传入的字段为resultMap type类型 即 cid
<collection property="itemList" column="{questTitleId=title_id,examTitleId=exam_title_id}" select="selItemList"></collection>
在这之中呢,property代表了映射需要查询的集合字段,column中表示将查询到的title_id赋值给questTitleId字段,
select表示要使用的查询语句id.
同时如果有多个表查询返回值的时候最好加别名区分一下