0%

有时候需要在程序里面做分组操作,类似MySQL中的group by语句。

比如有如下数据:

id name
1 A
1 B
2 C

我们想把它分组成这样的形式:{1=[A, B], 2=[C]}

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
34
public class GroupingByDemo {

@Data
static class IdNamePair {
private int id;
private String name;
}

public static void main(String[] args) {

IdNamePair pair = new IdNamePair();
pair.id = 1;
pair.name = "A";

IdNamePair pair2 = new IdNamePair();
pair2.id = 1;
pair2.name = "B";

IdNamePair pair3 = new IdNamePair();
pair3.id = 2;
pair3.name = "C";

List<IdNamePair> list = new ArrayList<>();
list.add(pair);
list.add(pair2);
list.add(pair3);

Map<Integer, List<String>> map = list.stream()
.collect(Collectors.groupingBy(IdNamePair::getId,
Collectors.mapping(IdNamePair::getName, Collectors.toList())));

System.out.println(map);
}
}

Collectors.mapping(IdNamePair::getName, Collectors.toList()) 相当于再往里面拨一层,取对象里面的一个属性。

在应用中,很多会用到数据库的存储过程,一般都会在程序里面实现数据库的逻辑。

但有时候要快速的获取某个值,逻辑比较复杂的时候,可能会用到存储过程。

比如接下来的案例,会把数据库的表作为一个变量传入。

1
2
3
4
5
6
7
8
9
10
11
12
13
DROP PROCEDURE IF EXISTS getInfo;
DELIMITER $$
CREATE PROCEDURE getInfo(IN tableName VARCHAR(100), IN id INT, OUT name VARCHAR(100))
BEGIN

SET @stmt := CONCAT("SELECT name INTO @var FROM ", tableName, " WHERE id = ", id);
PREPARE stmt FROM @stmt;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

SET name := @var;
END$$
DELIMITER ;

当创建好存储过程以后,可以通过以下方式调用。

1
2
3
SET @tableName := "tb_user";
CALL getInfo(@tableName, 4, @name);
SELECT @name;

如果不写存储过程,还可以通过执行下面代码的方式获取结果。

1
2
3
SET @user := 123456;
SELECT @group := `group` FROM user WHERE user = @user;
SELECT * FROM user WHERE `group` = @group;
1
SET @group = (SELECT `group` FROM user WHERE user = @user);

或者

1
SELECT `group` INTO @group FROM user WHERE user = @user;

nc 用于和服务器建立连接。

在Ubuntu上面做实验

启动一个终端

1
$ nc www.baidu.com 80

再开启另一个终端

1
$ netstat -antp
1
2
3
4
5
6
7
8
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:39351 0.0.0.0:* LISTEN -
tcp 0 0 172.16.64.227:33574 111.3.88.228:80 TIME_WAIT -
tcp 0 0 172.16.64.227:48534 36.152.44.95:80 ESTABLISHED 3366/nc

可以看到最后一行,已经建立了一个TCP连接。

在刚才连接好百度服务器的终端上面,按http协议,请求百度首页。GET / HTTP/1.0并连续输入两个回车。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ nc www.baidu.com 80
GET / HTTP/1.0

HTTP/1.0 200 OK
Accept-Ranges: bytes
Cache-Control: no-cache
Content-Length: 9508
Content-Type: text/html
Date: Sun, 20 Mar 2022 05:48:08 GMT
P3p: CP=" OTI DSP COR IVA OUR IND COM "
P3p: CP=" OTI DSP COR IVA OUR IND COM "
Pragma: no-cache
Server: BWS/1.1
Set-Cookie: BAIDUID=D9BC4FD3680ED7E670988E2B1D948396:FG=1; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie: BIDUPSID=D9BC4FD3680ED7E670988E2B1D948396; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie: PSTM=1647755288; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie: BAIDUID=D9BC4FD3680ED7E6F640384383D296BE:FG=1; max-age=31536000; expires=Mon, 20-Mar-23 05:48:08 GMT; domain=.baidu.com; path=/; version=1; comment=bd
Traceid: 1647755288023296769011190918765782309790
Vary: Accept-Encoding
X-Frame-Options: sameorigin
X-Ua-Compatible: IE=Edge,chrome=1

<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><meta content="always" name="referrer"><meta name="description" content="全球领先的中文搜索引擎、致力于让网民更便捷地获取信息,找到所求。百度超过千亿的中文网页数据库,可以瞬间找到相关的搜索结果。">
...

写一个SocketDemo Server端程序,开启一个监听。

-ff 追踪线程和子线程
-o output

1
$ strace -ff -o ./out java SocketDemo

通过jps或netstat可以看到一个pid

1
$ cd /proc/[pid]

fd目录下面,可以看到开启了多少个IO。

io流
/dev/pts/0 标准输入
/dev/pts/1 标准输出
/dev/pts/2 标准报错

1
ulimit -a

open files 1024

task目录,显示所有的线程

追踪一下redis的多路复用

1
$ strace -ff -o ./redis-out bin/redis-server config/server.properties

通过netstat查看进程监听状态
通过/proc/[pid]查看 fd 和 task,可以看到redis是多线程的。