方式一,数据库查询tree;

MyBatis collection 集合

MyBatis 是数据持久层框架,支持定制化 SQL、存储过程以及高级映射。尤其强大在于它的映射语句,比如高级映射中的 collection 集合。

collection 集合,集合常用的两个场景是集合的嵌套查询、集合的嵌套结果。集合的嵌套结果就是查询结果对应嵌套子对象。这里就是利用 collection 集合嵌套查询树形节点。下面来一一实现。

查询树形节点 Web 案例

创建数据库表

节点表:

CREATE TABLE `node` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL,
`parent_id` int(11) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `parent_id` (`parent_id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COMMENT='节点表'

简单的节点父子关系设计,下面插入几条数据:

INSERT INTO node (name, parent_id) VALUES ('一级节点A', 0);
INSERT INTO node (name, parent_id) VALUES ('一级节点B', 0);
INSERT INTO node (name, parent_id) VALUES ('一级节点C', 0);
INSERT INTO node (name, parent_id) VALUES ('二级节点AA', 1);
INSERT INTO node (name, parent_id) VALUES ('二级节点aa', 1);
INSERT INTO node (name, parent_id) VALUES ('二级节点BB', 2);
INSERT INTO node (name, parent_id) VALUES ('三级级节点AAA', 4);
INSERT INTO node (name, parent_id) VALUES ('三级级节点aaa', 4);
INSERT INTO node (name, parent_id) VALUES ('三级级节点BBB', 6);

重要的还是看 collection 在 xml 的映射实现,NodeMapper.xml 代码如下:

<mapper namespace="org.mybatis.dao.NodeDao">

  <resultMap id="BaseTreeResultMap" type="org.mybatis.domain.Node">
<result column="id" property="id"/>
<result column="name" property="name"/>
<collection column="id" property="next" javaType="java.util.ArrayList"
ofType="org.mybatis.domain.Node" select="getNextNodeTree"/>
</resultMap> <resultMap id="NextTreeResultMap" type="org.mybatis.domain.Node">
<result column="id" property="id"/>
<result column="name" property="name"/>
<collection column="id" property="next" javaType="java.util.ArrayList"
ofType="org.mybatis.domain.Node" select="getNextNodeTree"/>
</resultMap> <sql id="Base_Column_List">
id, name
</sql> <select id="getNextNodeTree" resultMap="NextTreeResultMap">
SELECT
<include refid="Base_Column_List"/>
FROM node
WHERE parent_id = #{id}
</select> <select id="getNodeTree" resultMap="BaseTreeResultMap">
SELECT
<include refid="Base_Column_List"/>
FROM node
WHERE parent_id = 0
</select> </mapper>

在 dao 层,我们只调用 getNodeTree 方法,parent_id = 0 代表顶级节点。然后通过 collection 节点继续调用 getNextNodeTree 方法进行循环调用。

<collection column="id" property="next" javaType="java.util.ArrayList"
ofType="org.mybatis.domain.Node" select="getNextNodeTree"/>

以下是关键的知识点:

  • column 代表会拿父节点 id ,作为参数获取 next 对象
  • javaType 代表 next 对象是个列表,其实可以省略不写
  • ofType 用来区分 JavaBean 属性类型和集合包含的类型
  • select 是用来执行循环哪个 SQL

工程代码地址:https://github.com/JeffLi1993/myabtis-learning-example
工程演示后的结果如图所示:

 
 
 
方式二,内存计算
   方式一查询数据库效率较低,方式二一次查询所有数据,任何用stream流来计算转化为树,建议采用

普通list转树状list

public static List<User> list2tree(List<User> list) {
List<User> result = new ArrayList<>();
Map<Object, User> hash = list.stream().collect(Collectors.toMap(u -> u.getId(), u -> u));
for (User u : list) {
User p = hash.get(u.getParent());
if (p == null) {
result.add(u);
} else {
if (p.getChildren() == null) {
p.setChildren(new ArrayList<>());
}
p.getChildren().add(u);
}
}
return result;
}

树状list转普通list

public static List<User> tree2list(List<User> list) {
List<User> result = new ArrayList<>();
for (User u : list) {
List<User> c = u.getChildren();
result.add(u);
if (!CollectionUtils.isEmpty(c)) {
result.addAll(tree2list(c));
u.setChildren(null);//
}
}
return result;
}

java8 stream多字段排序

使用java8新特性,下面先来点基础的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
List<类> list; 代表某集合
 
//返回 对象集合以类属性一升序排序
 
list.stream().sorted(Comparator.comparing(类::属性一));
 
//返回 对象集合以类属性一降序排序 注意两种写法
 
list.stream().sorted(Comparator.comparing(类::属性一).reversed());//先以属性一升序,结果进行属性一降序
 
list.stream().sorted(Comparator.comparing(类::属性一,Comparator.reverseOrder()));//以属性一降序
 
//返回 对象集合以类属性一升序 属性二升序
 
list.stream().sorted(Comparator.comparing(类::属性一).thenComparing(类::属性二));
 
//返回 对象集合以类属性一降序 属性二升序 注意两种写法
 
list.stream().sorted(Comparator.comparing(类::属性一).reversed().thenComparing(类::属性二));//先以属性一升序,升序结果进行属性一降序,再进行属性二升序
 
list.stream().sorted(Comparator.comparing(类::属性一,Comparator.reverseOrder()).thenComparing(类::属性二));//先以属性一降序,再进行属性二升序
 
//返回 对象集合以类属性一降序 属性二降序 注意两种写法
 
list.stream().sorted(Comparator.comparing(类::属性一).reversed().thenComparing(类::属性二,Comparator.reverseOrder()));//先以属性一升序,升序结果进行属性一降序,再进行属性二降序
 
list.stream().sorted(Comparator.comparing(类::属性一,Comparator.reverseOrder()).thenComparing(类::属性二,Comparator.reverseOrder()));//先以属性一降序,再进行属性二降序
 
//返回 对象集合以类属性一升序 属性二降序 注意两种写法
 
list.stream().sorted(Comparator.comparing(类::属性一).reversed().thenComparing(类::属性二).reversed());//先以属性一升序,升序结果进行属性一降序,再进行属性二升序,结果进行属性一降序属性二降序
 
list.stream().sorted(Comparator.comparing(类::属性一).thenComparing(类::属性二,Comparator.reverseOrder()));//先以属性一升序,再进行属性二降序<br><br><br>

通过以上例子我们可以发现

1. Comparator.comparing(类::属性一).reversed();

2. Comparator.comparing(类::属性一,Comparator.reverseOrder());

两种排序是完全不一样的,一定要区分开来 1 是得到排序结果后再排序,2是直接进行排序,很多人会混淆导致理解出错,2更好理解,建议使用2

3.注意排序后需要另外一个lis来接收List<xxx> list= Stream.sort(xxx).collect(toList());

class testRun {
public static void main(String[] args) {
List<test> testList = new ArrayList<>();
Date d = DateUtils.now();
for (int i = 1; i <= 3; i++) {
test t = new test(i, DateUtils.addDays(d, i));
testList.add(t);
}
for (int i = 1; i <= 3; i++) {
test t = new test(i, DateUtils.addMonths(d, i));
testList.add(t);
} testList.forEach(o -> {
System.out.println(o.toString());
});
List<test> sort = testList.stream().sorted(Comparator.comparing(test::getState).thenComparing(test::getTime,Comparator.reverseOrder())).collect(toList());
System.out.println("------------------------------------");
sort.forEach(o -> {
System.out.println(o.toString());
}); }
}

参考

链接:https://www.jianshu.com/p/fa20d4bd8ad4

链接:https://blog.csdn.net/qq_41991665/article/details/90484690

 

查询list转化为tree的两种方式及排序的更多相关文章

  1. Java中将xml文件转化为json的两种方式

    原文地址https://blog.csdn.net/a532672728/article/details/76312475 最近有个需求,要将xml转json之后存储在redis中,找来找去发现整体来 ...

  2. C#复杂XML反序列化为实体对象两种方式

    前言 今天主要讲的是如何把通过接口获取到的Xml数据转换成(反序列化)我们想要的实体对象,当然Xml反序列化和Json反序列化的方式基本上都是大同小异.都是我们事先定义好对应的对应的Xml实体模型,不 ...

  3. easyui里面的加载tree的两种方式

    第一种: 使用EasyUI中Tree 符合EasyUI中Tree的Json格式,我们先看一下,格式是如何的 [{ "id":1, "text":"My ...

  4. linq 实现查询字符串拼接 : And 和 OR 两种方式

    N年前我们是这样来 拼接查询字符串的: // 何问起 hovertree.com public string Test(string a, string b, string c,string d) { ...

  5. java.util.Arrays.sort两种方式的排序(及文件读写练习)

    import java.io.*; import java.util.*; public class SortTest{ public static void main(String args[]) ...

  6. hibernate级联查询映射的两种方式

    Hibernate主要支持两种查询方式:HQL查询和Criteria查询.前者应用较为广发,后者也只是调用封装好的接口. 现在有一个问题,就是实现多表连接查询,且查询结果集不与任何一个实体类对应,怎么 ...

  7. SpringBoot集成Mybatis实现多表查询的两种方式(基于xml)

     下面将在用户和账户进行一对一查询的基础上进行介绍SpringBoot集成Mybatis实现多表查询的基于xml的两种方式.   首先我们先创建两个数据库表,分别是user用户表和account账户表 ...

  8. MySQL关闭查询缓存(QC)的两种方法

    MySQL Query Cache 会缓存select 查询,安装时默认是开启的,但是如果对表进行INSERT, UPDATE, DELETE, TRUNCATE, ALTER TABLE, DROP ...

  9. 五 Mybatis一对一关联查询的两种方式(基于resultType&基于resultMap)

    关联查询: 一个用户对应多个订单,一个订单只有一个用户 订单关联用户:两种方式 一:基于resultTYpe,一个与表关系一样的pojo实现 主表订单,从表用户 首先要有一个与关联查询表关系一样的po ...

随机推荐

  1. Clone failed: Could not read from remote repository

    问题: 使用idea下载项目代码时报错,内容如下: Clone failed: Could not read from remote repository 解决方案: 把 SSH切换成 HTTP重新c ...

  2. MySQL基础练习02---牛客网

    目录 1. 从titles表中获取title并按照title分组 2.从titles表中获取title并按照title分组,重复的emp_no忽略 3 查找employees表 4 统计平均工资 5 ...

  3. Solution: The process cannot access the file [filename] because it is being used by another process.

    http://www.brianstevenson.com/blog/solution-the-process-cannot-access-the-file-filename-because-it-i ...

  4. 一种关闭Windows 8.1 Windows Defender的简单办法

    背景 安装好Windows 8.1,像往常一样,打开[服务]准备关闭Windows Defender,发现不能设置启动类型而且其默认为启动状态,如下图所示. 两个有两种方式关闭它.一是安装第三方安全软 ...

  5. [Luogu] trip

    https://www.luogu.org/problemnew/show/T28848#sub #include <iostream> #include <cstdio> u ...

  6. luogu P2585 [ZJOI2006]三色二叉树

    P2585 [ZJOI2006]三色二叉树 题目描述 输入输出格式 输入格式: 输入文件名:TRO.IN 输入文件仅有一行,不超过10000个字符,表示一个二叉树序列. 输出格式: 输出文件名:TRO ...

  7. 「BZOJ 4565」「HAOI 2016」字符合并「区间状压DP」

    题意 给一个长度为\(n(\leq 300)\)的\(01\)串,每次可以把\(k(\leq 8)\)个相邻字符合并,得到新字符和一定分数,最大化最后的得分 题解 考虑设计dp:\(dp[S][i][ ...

  8. 「CF712E」Memory and Casinos「线段树」「概率」

    题解 解法1:(官方做法) 一段区间的\(L\)定义为从最左边开始出发,最左不失败,一直到最右边胜利的概率,\(R\)定义为从最右边开始出发,最左不失败,又回到最右边胜利的概率 考虑一个区间\([l, ...

  9. javaScript基础用Number()把其它类型转换为Number类型

    一:基本类型 字符串 把字符串转换为数字,只要字符串中包含任意一个非有效数字字符(第一个点除外)结果都是NaN,空字符串会变为数字零 console.log(Number("12.5&quo ...

  10. 微信小程序swiper禁止用户手动滑动

    最近做一个项目,由于用到了竖向swiper,导致占用屏幕过大,用户滑动总是滑动到swiper组件,页面无法向下拉动,于是找各种办法禁止用户手动滑动swiper组件. 经过网上一番查找,网友们也是闹洞大 ...