外连接的用法 -- 《SQL进阶教程》 jupyter note
import pandas as pd
import sqlite3
conn = sqlite3.connect('1-5.db')
用外连接进行行列转换1(行 -> 列): 制作交叉表
怎么使用outer join,将row转换成column
下面的方式一,使用的是外连接的方法。但是效果却是最差的。
# create Course Table and insert data
conn.execute("""
CREATE TABLE IF NOT EXISTS Courses (
name VARCHAR(10) NOT NULL,
course VARCHAR(10),
PRIMARY KEY(name, course)
)
""")
conn.execute("""DELETE FROM Courses;""")
conn.execute("""
INSERT INTO Courses(name, course)
VALUES
('赤井', 'SQL入门'),
('赤井', 'UNIX基础'),
('铃木', 'SQL入门'),
('工藤', 'SQL入门'),
('工藤', 'Java中级'),
('吉田', 'UNIX基础'),
('渡边', 'SQL入门')
""")
pd.read_sql_query('SELECT * FROM Courses', conn)
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
-->
| name | course | |
|---|---|---|
| 0 | 赤井 | SQL入门 |
| 1 | 赤井 | UNIX基础 |
| 2 | 铃木 | SQL入门 |
| 3 | 工藤 | SQL入门 |
| 4 | 工藤 | Java中级 |
| 5 | 吉田 | UNIX基础 |
| 6 | 渡边 | SQL入门 |
# 方式一: 每个要转换的列都使用一
pd.read_sql_query("""
SELECT c0.name,
CASE WHEN c1.name IS NOT NULL THEN 'O' ELSE 'X' END AS 'SQL入门',
CASE WHEN c2.name IS NOT NULL THEN 'O' ELSE 'X' END AS 'UNIX基础',
CASE WHEN c3.name is NOT NULL THEN 'O' ELSE 'X' END AS 'Java中级'
FROM (SELECT DISTINCT name FROM Courses) C0
LEFT OUTER JOIN
(SELECT name FROM Courses WHERE course='SQL入门') C1
ON c0.name = c1.name
LEFT OUTER JOIN
(SELECT name FROM Courses WHERE course='UNIX基础') C2
ON c0.name = c2.name
LEFT OUTER JOIN
(SELECT name FROM Courses WHERE course='Java中级') c3
ON c0.name = c3.name;
""", conn)
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
-->
| name | SQL入门 | UNIX基础 | Java中级 | |
|---|---|---|---|---|
| 0 | 吉田 | X | O | X |
| 1 | 工藤 | O | X | O |
| 2 | 渡边 | O | X | X |
| 3 | 赤井 | O | O | X |
| 4 | 铃木 | O | X | X |
# 方式二: 使用标量子查询代替外连接
# 优点是,加入新的列,只需要修改SELECT下的子查询。而方式一需要修改SELECT和FROM两处.
# 缺点是,在SELECT中使用标量子查询,开销比较大。因为需要对每一行都进行一次或多次子查询.
pd.read_sql_query("""
SELECT c0.name,
(SELECT 'O'
FROM Courses AS c1
WHERE course='SQL入门' AND c0.name = c1.name) AS 'SQL入门',
(SELECT 'O'
FROM Courses AS c2
WHERE course='UNIX基础' AND c0.name = c2.name) AS 'UNIX基础',
(SELECT 'O'
FROM Courses AS c3
WHERE course='Java中级' AND c0.name = c3.name) AS 'Java中级'
FROM (SELECT DISTINCT name FROM Courses) AS c0;
""", conn).replace(to_replace=[None], value='X')
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
-->
| name | SQL入门 | UNIX基础 | Java中级 | |
|---|---|---|---|---|
| 0 | 吉田 | X | O | X |
| 1 | 工藤 | O | X | O |
| 2 | 渡边 | O | X | X |
| 3 | 赤井 | O | O | X |
| 4 | 铃木 | O | X | X |
# 方式三: 嵌套使用CASE表单是
pd.read_sql_query("""
SELECT name,
CASE WHEN SUM(CASE WHEN course='SQL入门' THEN 1 ELSE 0 END) = 1 THEN 'O' ELSE 'X' END AS 'SQL入门',
CASE WHEN SUM(CASE WHEN course='UNIX基础' THEN 1 ELSE 0 END) = 1 THEN 'O' ELSE 'X' END AS 'UNIX基础',
CASE WHEN SUM(CASE WHEN course='Java中级' THEN 1 ELSE 0 END) = 1 THEN 'O' ELSE 'X' END AS 'Java中级'
FROM Courses
GROUP BY name
""", conn)
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
-->
| name | SQL入门 | UNIX基础 | Java中级 | |
|---|---|---|---|---|
| 0 | 吉田 | X | O | X |
| 1 | 工藤 | O | X | O |
| 2 | 渡边 | O | X | X |
| 3 | 赤井 | O | O | X |
| 4 | 铃木 | O | X | X |
用外连接进行行列转换2(列 -> 行): 汇总重复项于一列
# create Personnel Table and insert data
conn.execute("""
CREATE TABLE IF NOT EXISTS Personnel (
employee VARCHAR(10) NOT NULL PRIMARY KEY,
child_1 VARCHAR(10),
child_2 VARCHAR(10),
child_3 VARCHAR(10)
)
""")
conn.execute("""DELETE FROM Personnel;""")
conn.execute("""
INSERT INTO Personnel(employee, child_1, child_2, child_3)
VALUES
('赤井', '一郎', '二郎', '三郎'),
('工藤', '春子', '夏子', null),
('铃木', '夏子', null, null),
('吉田', null, null, null)
""")
pd.read_sql_query('SELECT * FROM Personnel', conn)
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
-->
| employee | child_1 | child_2 | child_3 | |
|---|---|---|---|---|
| 0 | 赤井 | 一郎 | 二郎 | 三郎 |
| 1 | 工藤 | 春子 | 夏子 | None |
| 2 | 铃木 | 夏子 | None | None |
| 3 | 吉田 | None | None | None |
# 这个方法,会把child为null的结果也返回。
# 但是如果排除掉child为null的结果,那么吉田这个employee因为没有孩子,就不会出现在结果表里面
pd.read_sql_query("""
SELECT employee, child_1 AS child FROM Personnel
UNION ALL
SELECT employee, child_2 AS child FROM Personnel
UNION ALL
SELECT employee, child_3 AS child FROM Personnel
""", conn)
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
-->
| employee | child | |
|---|---|---|
| 0 | 赤井 | 一郎 |
| 1 | 工藤 | 春子 |
| 2 | 铃木 | 夏子 |
| 3 | 吉田 | None |
| 4 | 赤井 | 二郎 |
| 5 | 工藤 | 夏子 |
| 6 | 铃木 | None |
| 7 | 吉田 | None |
| 8 | 赤井 | 三郎 |
| 9 | 工藤 | None |
| 10 | 铃木 | None |
| 11 | 吉田 | None |
conn.execute("""
CREATE VIEW IF NOT EXISTS Children(child) AS
SELECT child_1 FROM Personnel
UNION
SELECT child_2 FROM Personnel
UNION
SELECT child_3 FROM Personnel
""")
pd.read_sql_query("""
SELECT EMP.employee, CHILDREN.child
FROM Personnel EMP
LEFT OUTER JOIN Children
ON Children.child IN (EMP.child_1, EMP.child_2, EMP.child_3)
""", conn)
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
-->
| employee | child | |
|---|---|---|
| 0 | 赤井 | 一郎 |
| 1 | 赤井 | 三郎 |
| 2 | 赤井 | 二郎 |
| 3 | 工藤 | 夏子 |
| 4 | 工藤 | 春子 |
| 5 | 铃木 | 夏子 |
| 6 | 吉田 | None |
# 习题1-5-2: 求每个雇员的孩子数量
pd.read_sql_query("""
SELECT EMP.employee, COUNT(CHILDREN.child) AS child_cnt
FROM Personnel EMP
LEFT OUTER JOIN Children
ON Children.child IN (EMP.child_1, EMP.child_2, EMP.child_3)
GROUP BY EMP.employee
""", conn)
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
-->
| employee | child_cnt | |
|---|---|---|
| 0 | 吉田 | 0 |
| 1 | 工藤 | 2 |
| 2 | 赤井 | 3 |
| 3 | 铃木 | 1 |
在交叉表里制作嵌套式表侧栏
# 创建相关的表
conn.execute("""
CREATE TABLE IF NOT EXISTS TblAge (
age_class integer PRIMARY KEY,
age_range varchar(20)
);
""")
conn.execute("""
CREATE TABLE IF NOT EXISTS TblSex (
sex_cd char(1) PRIMARY KEY,
sex char(1)
);
""")
conn.execute("""
CREATE TABLE IF NOT EXISTS TblPop (
pref_name VARCHAR(10),
age_class integer,
sex_cd char(1),
population integer,
PRIMARY KEY (pref_name, age_class, sex_cd),
FOREIGN KEY (age_class) REFERENCES TblAge(age_class),
FOREIGN KEY (sex_cd) REFERENCES TblSex(sex_cd)
);
""")
# 确保没有数据
conn.execute("""DELETE FROM TblPop""")
conn.execute("""DELETE FROM TblSex""")
conn.execute("""DELETE FROM TblAge""")
# 插入数据
conn.execute("""
INSERT INTO TblAge(age_class, age_range) VALUES
(1, '21岁 ~ 30岁'),
(2, '31岁 ~ 40岁'),
(3, '41岁 ~ 50岁')
""")
conn.execute("""
INSERT INTO TblSex(sex_cd, sex) VALUES
('m', '男'),
('f', '女')
""")
conn.execute("""
INSERT INTO TblPop(pref_name, age_class, sex_cd, population) VALUES
('秋田', 1, 'm', 400),
('秋田', 3, 'm', 1000),
('秋田', 1, 'f', 800),
('秋田', 3, 'f', 1000),
('青森', 1, 'm', 700),
('青森', 1, 'f', 500),
('青森', 3, 'f', 800),
('东京', 1, 'm', 1500),
('东京', 1, 'f', 1200),
('千叶', 1, 'm', 900),
('千叶', 1, 'f', 1000),
('千叶', 3, 'f', 900)
""")
<sqlite3.Cursor at 0x113c47180>
pd.read_sql("""
SELECT * FROM TblAge
""", conn)
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
-->
| age_class | age_range | |
|---|---|---|
| 0 | 1 | 21岁 ~ 30岁 |
| 1 | 2 | 31岁 ~ 40岁 |
| 2 | 3 | 41岁 ~ 50岁 |
pd.read_sql("""
SELECT * FROM TblSex
""", conn)
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
-->
| sex_cd | sex | |
|---|---|---|
| 0 | m | 男 |
| 1 | f | 女 |
pd.read_sql("""
SELECT * FROM TblPop
""", conn)
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
-->
| pref_name | age_class | sex_cd | population | |
|---|---|---|---|---|
| 0 | 秋田 | 1 | m | 400 |
| 1 | 秋田 | 3 | m | 1000 |
| 2 | 秋田 | 1 | f | 800 |
| 3 | 秋田 | 3 | f | 1000 |
| 4 | 青森 | 1 | m | 700 |
| 5 | 青森 | 1 | f | 500 |
| 6 | 青森 | 3 | f | 800 |
| 7 | 东京 | 1 | m | 1500 |
| 8 | 东京 | 1 | f | 1200 |
| 9 | 千叶 | 1 | m | 900 |
| 10 | 千叶 | 1 | f | 1000 |
| 11 | 千叶 | 3 | f | 900 |
# 下面这种,以两张表作为外连接操作的方式。
# 有时候并不能满足需求,比如不会显示age_class=2的情况,因为没有对应的人口数据
pd.read_sql("""
SELECT MASTER1.age_class AS age_class,
MASTER2.sex_cd AS sex_cd,
DATA.pop_tohoku AS pop_tohoku,
DATA.pop_kanto AS pop_kanto
FROM (SELECT age_class, sex_cd,
SUM(CASE WHEN pref_name IN ('青森', '秋田') THEN population ELSE NULL END) AS pop_tohoku,
SUM(CASE WHEN pref_name IN ('东京', '千叶') THEN population ELSE NULL END) AS pop_kanto
FROM TblPop
GROUP BY age_class, sex_cd) AS DATA
LEFT OUTER JOIN TblAge MASTER1
ON MASTER1.age_class = DATA.age_class
LEFT OUTER JOIN TblSex MASTER2
ON MASTER2.sex_cd = DATA.sex_cd
""", conn)
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
-->
| age_class | sex_cd | pop_tohoku | pop_kanto | |
|---|---|---|---|---|
| 0 | 1 | f | 1300 | 2200.0 |
| 1 | 1 | m | 1100 | 2400.0 |
| 2 | 3 | f | 1800 | 900.0 |
| 3 | 3 | m | 1000 | NaN |
# 解决方式是:调整为一次外连接
# 外连接的表是 TblAge和TblSex 的笛卡尔积,也就是把它们用交叉连接(CROSS JOIN)组合起来,
# 对于不支持CROSS JOIN的库,分别把两个表用FROM引入,也是一样的.
# 同时,请注意下面把临时表放在了 LEFT OUTER JOIN 的左边,充分发挥OUTER JOIN的作用.
pd.read_sql("""
SELECT MASTER.age_class AS age_class,
MASTER.sex_cd AS sex_cd,
DATA.pop_tohoku AS pop_tohoku,
DATA.pop_kanto AS pop_kanto
FROM (SELECT age_class, sex_cd
FROM TblAge CROSS JOIN TblSex) AS MASTER
LEFT OUTER JOIN
(SELECT age_class, sex_cd,
SUM(CASE WHEN pref_name IN ('青森', '秋田') THEN population ELSE NULL END) AS pop_tohoku,
SUM(CASE WHEN pref_name IN ('东京', '千叶') THEN population ELSE NULL END) AS pop_kanto
FROM TblPop
GROUP BY age_class, sex_cd) AS DATA
ON MASTER.age_class = DATA.age_class
AND MASTER.sex_cd = DATA.sex_cd
""", conn)
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
-->
| age_class | sex_cd | pop_tohoku | pop_kanto | |
|---|---|---|---|---|
| 0 | 1 | f | 1300.0 | 2200.0 |
| 1 | 1 | m | 1100.0 | 2400.0 |
| 2 | 2 | f | NaN | NaN |
| 3 | 2 | m | NaN | NaN |
| 4 | 3 | f | 1800.0 | 900.0 |
| 5 | 3 | m | 1000.0 | NaN |
# 更优的解决方法是:把JOIN看作乘法运算
# 关键在于,TblPop可以看作就是DATA。然后 MASTER -> DATA 的关系,就是一对多关系了
pd.read_sql("""
SELECT MASTER.age_class AS age_class,
MASTER.sex_cd AS sex_cd,
SUM(CASE WHEN pref_name IN ('青森', '秋田') THEN population ELSE NULL END) AS pop_tohoku,
SUM(CASE WHEN pref_name IN ('东京', '千叶') THEN population ELSE NULL END) AS pop_kanto
FROM (SELECT age_class, sex_cd
FROM TblAge CROSS JOIN TblSex) AS MASTER
LEFT OUTER JOIN TblPop AS DATA
ON MASTER.age_class = DATA.age_class
AND MASTER.sex_cd = DATA.sex_cd
GROUP BY MASTER.age_class, MASTER.sex_cd
""", conn)
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
-->
| age_class | sex_cd | pop_tohoku | pop_kanto | |
|---|---|---|---|---|
| 0 | 1 | f | 1300.0 | 2200.0 |
| 1 | 1 | m | 1100.0 | 2400.0 |
| 2 | 2 | f | NaN | NaN |
| 3 | 2 | m | NaN | NaN |
| 4 | 3 | f | 1800.0 | 900.0 |
| 5 | 3 | m | 1000.0 | NaN |
用外连接做集合运算
各个数据库的集合运算实现都不尽相同,参差不齐。
集合运算符会尽心排序,所以可能带来性能上的问题。
因此,了解一下集合运算符的替代方案还是有意义的。
# 创建数据库
conn.execute("""
CREATE TABLE IF NOT EXISTS Class_A (
id integer PRIMARY KEY AUTOINCREMENT,
name varchar(10)
);
""")
conn.execute("""
CREATE TABLE IF NOT EXISTS Class_B (
id integer PRIMARY KEY AUTOINCREMENT,
name varchar(10)
)
""")
# 插入数据
conn.execute("""DELETE FROM Class_A;""")
conn.execute("""DELETE FROM Class_B;""")
conn.execute("""
INSERT INTO Class_A(id, name) VALUES
(1, '田中'),
(2, '铃木'),
(3, '伊集院')
""")
conn.execute("""
INSERT INTO Class_B(id, name) VALUES
(1, '田中'),
(2, '铃木'),
(4, '西院寺')
""")
<sqlite3.Cursor at 0x113f3c5e0>
pd.read_sql("""
SELECT * FROM Class_A
""", conn)
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
-->
| id | name | |
|---|---|---|
| 0 | 1 | 田中 |
| 1 | 2 | 铃木 |
| 2 | 3 | 伊集院 |
pd.read_sql("""
SELECT * FROM Class_B
""", conn)
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
-->
| id | name | |
|---|---|---|
| 0 | 1 | 田中 |
| 1 | 2 | 铃木 |
| 2 | 4 | 西院寺 |
用外连接求差集: A - B
pd.read_sql("""
SELECT A.id id, A.name AS A_name
FROM Class_A AS A LEFT OUTER JOIN Class_B AS B
ON A.id = B.id
WHERE B.name IS NULL
""", conn)
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
-->
| id | A_name | |
|---|---|---|
| 0 | 3 | 伊集院 |
用外连接求差集: B - A
pd.read_sql("""
SELECT B.id id, B.name AS B_name
FROM Class_B AS B LEFT OUTER JOIN Class_A AS A
ON A.id = B.id
WHERE A.name IS NULL
""", conn)
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
-->
| id | B_name | |
|---|---|---|
| 0 | 4 | 西院寺 |
用外连接求异或集
pd.read_sql("""
SELECT A.id id, A.name AS name
FROM Class_A AS A LEFT OUTER JOIN Class_B AS B
ON A.id = B.id
WHERE B.name IS NULL
UNION
SELECT B.id id, B.name AS name
FROM Class_B AS B LEFT OUTER JOIN Class_A AS A
ON A.id = B.id
WHERE A.name IS NULL
""", conn)
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
-->
| id | name | |
|---|---|---|
| 0 | 3 | 伊集院 |
| 1 | 4 | 西院寺 |
外连接的用法 -- 《SQL进阶教程》 jupyter note的更多相关文章
- 《SQL基础教程》+ 《SQL进阶教程》 学习笔记
写在前面:本文主要注重 SQL 的理论.主流覆盖的功能范围及其基本语法/用法.至于详细的 SQL 语法/用法,因为每家 DBMS 都有些许不同,我会在以后专门介绍某款DBMS(例如 PostgreSQ ...
- (一)《SQL进阶教程》学习记录--CASE
背景:最近用到统计之类的复杂Sql比较多,有种"提笔忘字"的感觉,看书练习,举一反三,巩固加强. (一) <SQL进阶教程>学习记录--CASE (二) <SQL ...
- SQL进阶系列之5外连接的用法
写在前面 SQL本身是作为一种数据提取工具而出现,使用SQL生成各种定制化报表和非定制化报表并非SQL原本用途的功能,但这并不意味着SQL无法实现这些功能. 用外连接进行行列转换(1)(行 → 列): ...
- Oracle学习笔记:外连接(+)的用法
Oracle中常用 left join 和 right join 来进行外连接,同时,oracle也支持 (+) 的特殊用法,也是表示外连接,并且总是放在非主表的一方. 例如: 左外连接: selec ...
- 《SQL 进阶教程》case :用一条 SQL 语句进行不同条件的统计
进行不同条件的统计是case表达式的著名用法之一 select name,sum(case when sex = 1 then population else 0 end) as cnt_m,sum( ...
- 《SQL 进阶教程》 case:将已有编号方式转换为新的方式并统计
SQL 权威指南SQL 解惑在进行非定制化统计时,需要将已有编号方式转换为另外一种便于分析的方式进行统计需求 select case when name='哈尔滨' then '黑龙江' when n ...
- 《SQL 进阶教程》 自连接排序
子查询所做的,是计算出价格比自己高的记录的条数并将其作为自己的位次 -- 自连接实现排序功能SELECT P1.name,P1.price,(SELECT COUNT(P2.price)FROM Pr ...
- 《SQL 进阶教程》 自连接分组排序:练习题1-2-2
分组排序 SELECT d1.district, d1. NAME, (SELECT COUNT(d2.price) FROM district_products d2 WHERE d2.price ...
- 《SQL 进阶教程》 case:练习题1-1-3 用 ORDER BY 指定顺序进行排序
select name from greatestsORDER BY case when name ='B' then 1 when name ='A' then 2 when name ='D' t ...
随机推荐
- React全家桶构建一款Web音乐App实战(六):排行榜及歌曲本地持久化
上一节使用Redux管理歌曲相关数据,实现核心播放功能,播放功能是本项目最复杂的一个功能,涉及各个组件之间的数据交互,播放逻辑控制.这一节继续开发排行榜列表和排行榜详情,以及把播放歌曲和播放歌曲列表的 ...
- [人物存档]【AI少女】【捏脸数据】甜美粉色
点击下载(城通网盘):AISChaF_20191028024804811.png
- CentOS下安装libjpeg库及编译GD库
GD库明明安装了,可处理图片的时候还是报错 Fatal error: Call to undefined function imagecreatefromjpeg() .PHP安装后,默认的gd库不支 ...
- mysql 导出导入数据库(Mysqldump)备份
使用mysql不熟练啊!!! mysqldump导出数据库,必须以cmd命令行的形式,在Navicat中以新建查询形式使用Mysqldump不好使的.(本来使用Navicat转储SQL,再导入SQL, ...
- JavaWeb_(Struts2框架)使用Struts框架实现用户的登陆
JavaWeb_(Struts2框架)使用Servlet实现用户的登陆 传送门 JavaWeb_(Struts2框架)Servlet与Struts区别 传送门 MySQL数据库中存在Gary用户,密码 ...
- Android学习_广播接收器
一.广播 1. 标准广播和有序广播 标准广播:异步,发出消息,所有接收器同时接收.但无法被截断 有序广播:同步,同一时刻只有一个广播接收器接收.可截断消息. 2. 广播注册 代码中注册(动态注册).A ...
- django分页模块--django-pure-pagination
Django自带有分页的两个类,但是用起来没有第三方这个分页模块方便,下面介绍一下这个模块的使用方法. 1. 安装模块: pip install django-pure-pagination 2. ...
- 微信小程序<web-view>出现{"base_resp":{"ret":-1}}
最近在使用小程序<web-view>这个标签加载一个https网页的时候出现了{"base_resp":{"ret":-1}}这一个问题 搞了好久~ ...
- Java程序如何限速(控制下载和上传速度)
转自 http://www.blogjava.net/canvas/articles/bandwidthlimiter.html 这里简单的讨论一下java设计网络程序中如何控制上传和下载速度,我们常 ...
- 理解Dubbo
1.Dubbo应用场景 2.Dubbo支持的协议 3.Dubbo性能比较 4.负载均衡策略 5.容错方案 6.Dubbo vs SpringCloud 7.深入Dubbo需要的技能