数据库命令
创建数据库并制定编码
1
Create database 数据库名 default character set utf8
创建表
1
2
3Create table 表名(
列明 类型 约束 auto_increment comment '备注'
)
命名规范
- 项目名:没有要求,不起中文
- 包:公司域名倒写
- 持久层:dao,persist,
mapper - 实体层:entity,model,bean,javabean,
pojo - 业务逻辑:service,biz
- 控制器层:controll,action,
servlet,web - 过滤器:filter
- 异常:exception
- 监听器:listener
- 注释
- 类:大驼峰
- 属性和方法:小驼峰
MVC开发模式
- M:Model 模型,实体类、业务和dao
- V:View 视图,JSP
- C:Controller 控制器,servlet
- MVC应用场景:适合大型项目开发
jsp+Servlet完成查询和新增
框架是什么?
- 框架:软件的半成品。为解决问题制定的一套约束,在提供功能的基础上进行扩充。
- 框架中一些不能被封装的代码(变量),需要使用框架这新建一个xml文件,在文件中添加变量的内容。
- 需要建立特定位置和特定名称的配置文件.
- 需要使用xml解析技术和反射技术。
- 常用概念:
- 类库:提供的类没有封装一定逻辑。
- 举例:类库就是名言警句,写作文时引入名言警句。
- 框架:区别于类库,里面有一定的约束。
- 框架是填空题。
Mybatis简介
- Mybatis是一个开源免费框架。原名叫iBatis,2010在
google code,2013年迁移到github - 作用:数据访问层框架。
- 底层是对JDBC的封装
mybatis优点之一- 使用
Mybatis不需要编写实现类,只需要编写需要执行的sql命令。
- 使用
Mybatis 环境搭建
- 类库:提供的类没有封装一定逻辑。
- 导入jar包

- asm.jar:Cglib依赖的包
- cglib.jar:动态代理的包
- commons-logging.jar、log4j.jar、slf4j.*.jar:日志包
- javaassist.jar:字节码解析包
- mybatis.jar:mybatis的核心包
- 在src下编写全局配置文件(JDBC四个变量)(mybatis.xml)
- 没有名称配置和地址要求。
- 在全局配置文件中引入dtd或schema
1 |
|
新建以
mapper结尾的包,在包下新建:实体类名+Mapper.xml(FlowerMapper.xml)- 文件作用:编写需要执行的sql语句。
- 把xml文件理解成实现类。
- xml文件内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- namespace:理解成实现类的完全限定名(报名+类名) -->
<mapper namespace="a.b">
<!-- id:方法名 -->
<!-- parameterType:定义参数类型 -->
<!-- resultType:定义结果返回值类型 -->
<!-- 如果方法返回是list,在resultType中写List的泛型,因为Mybatis对jdbc封装,一行一行读取数据 -->
<select id="selAll" resultType="com.zhuchuli.pojo.Flower">
select * from flower
</select>
</mapper>测试结果(只有单独使用Mybatis时使用,最后SSM整合时下面代码不需要编写)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19public static void main(String[] args) {
InputStream is=null;
try {
is = Resources.getResourceAsStream("mybatis.xml");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//使用工厂设计模式
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(is);
//生产SqlSession
SqlSession session=factory.openSession();
List<Flower> list=session.selectList("a.b.selAll");
for (Flower flower : list) {
System.out.println(flower.toString());
}
//释放资源
session.close();
}
- 注意:当表列名与Java的属性名称不一致时,在进行数据库查询时可以指定通过起别名来实现。
环境搭建讲解
- 全局配置文件讲解
<transactionManager>:type属性可取值JDBC:事务管理使用JDBC原生事务管理方式。MANAGED:把事务管理转交给其他容器。原生JDBC事务setAutoMapping(false)
<dataSource>:type属性可取值UNPOOLED:不使用数据库连接池,和直接使用JDBC一样。POOLED:使用数据库连接池JNDI(Java语言调用其他语言):Java命令目录接口技术。
数据库连接池
- 在内存中开辟一块空间,存放多个数据库连接对象
- JDBC Tomcat Pool:直接由tomcat产生数据库连接池
- 图示:

- 使用数据库连接池的目的:
- 在高频率访问数据库时,使用数据库连接池可以降低服务器系统压力,提升程序运行效率。
- 小项目不适用数据库连接池
- 实现JDBC Tomcat Pool的步骤:
- 在META-INF包下添加Context.xml文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14<Context>
<Resource
driverClassName="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://localhost:3306/ssm"
username="root"
password="123456"
maxActive="50"
maxIdle="20"
name="test"
auth="Container"
maxWait="10000"
type="javax.sql.DataSource"
/>
</Context>
- 把项目发布到tomcat中,数据库连接池就产生了.
- 可以使用Java的JNDI获取数据库连接池对象:
- Context:上下文接口,Context.xml文件对象类型
1 | Context ctx=new InitialContext(); |
- 当关闭数据库连接池对象时,把连接对象归还给数据库连接池,把状态改为idle状态。
三种查询方式
selectList():返回值List<resultType属性控制> ,适合于查询结果都需要遍历的需求。
1
2
3
4List<Flower> list=session.selectList("a.b.selAll");
for (Flower flower : list) {
System.out.println(flower.toString());
}selectOne():返回Object,适用于返回结果只是变量或一行数据时
1
2int count=session.selectOne("a.b.selById");
System.out.println(count);selectMap()返回值Map,适用于需求需要在查询结果中通过某列的值取到这行数据的值的需求。
- Map<Object,Object>:第一个Object的数据类型受到selectMap()第二参数影响,第二个Object的数据类型受到<restultType属性值>的控制。
1
2Map<Object,Object> map=session.selectMap("a.b.c", "name");
System.out.println(map);
Log4j复习
- 由
apache提出的开源免费日志处理的类库。 - 为什么需要日志:
- 在项目中编写
system.out.println();输出到控制台,当项目发布到tomcat后,没有控制台(在命令行能看见),不容易观察一些输出结果。 - log4j的作用:不仅能把内容输出到控制台,还能把内容输出到文件中。便于观察结果。
- 在项目中编写
- 使用步骤:
- 导入jar包
- 在src下新建log4j.properties(路径和名称都不允许改变)
- ConversionPattern:写表达式
- log4j.appender.LOGFILE.File:写文件输出路径以及名称(日志文件的扩展名为
.log)
- Log4j输出级别:
- Fatal(指明错误) > error(错误) > warm(警告) > info(普通信息) > debug(调试信息)
- 在
log4j.properties第一行控制输出级别。 - log4j.rootCategory=INFO
- Log4j输出目的地
- log4j.rootCategory=
CONSOLE,LOGFILE
- log4j.rootCategory=
- pattern常用表达式
- %C 输出类名
- %d 输出时间
- %L 输出行号
- %m 输出日志信息
- %n 换行
<settings>标签- 在
mybatis全局配置文件中<settings>标签控制mybatis全局开关。 - 在
mybatis.xml中开启log4j- 必须保证有
jar包 - 在src目录下要有
log4j.properties文件 - 在mybatis.xml配置文件中添加如下代码
- 必须保证有
1
2
3
4<settings>
<!-- Mybatis开启日志功能 -->
<setting name="logImpl" value="LOG4J"/>
</settings>
- log4j中可以指定内容的日志(控制某个局部内容的日志级别)
- 命名级别(包级别):
namespace属性中除了最后一个类名
- 先在总体级别调成error不输出无用信息。
- 在该配置文件中为特定包名设置输出级别为debug。
- 例如:
namespace="com.zhuchuli.mapper.PeopleMapper"其中包级别为com.zhuchuli.mapper,需要在log4j.properties配置文件中配置如下代码:log4j.rootCategory=ERROR, CONSOLE , LOGFILE;log4j.logger.com.zhuchuli.mapper=DEBUG- 目的:输出主要的日志信息。
- 类级别:与上面包级别差不多,此处不再赘述。
- 方法级别:与上面包级别差不多,此处不再赘述。
parameterType 属性
在XxxMapper.xml中等标签的
parameterType可以控制参数类型。SqlSession的selectList()和selectOne()的第二个参数和selectMap()的第三个参数都表示方法的参数
1
2People people=session.selectOne("a.b.selById",2);
System.out.println(people);在
mapper.xml文件中通过#{}获取参数1
2
3<select id="selById" resultType="com.zhuchuli.pojo.People" parameterType="int">
select * from people where id=#{0}
</select>
- parameterType指定参数类型
- #{}获取参数值,使用索引,从0开始,#{0}表示第一个参数。
- 如果只有一个参数(基本数据类型或String),mybatis对#{}里面的内容没有要求,只要写内容即可。
- 如果参数是对象 #{属性名}
- 如果参数时msap #{key}
- 如果想要传递多个参数,可以使用map结构或对象
- #{}与${}的区别:
- #{}获取参数的内容支持 索引获取,param1获取指定位置参数,并且SQL使用?占位符。
- ${}字符串拼接不使用?,默认找${内容}的get/set方法,如果写数字,就是一个数字。
- 如果在xml文件中出现”<”,”>”,双引号等特殊字符时,可以使用xml文件转义标签(XML自身):
<![CDATA[内容]]>
mybatis 实现mysql分页查询
- ?不允许在关键字前后进行数学运算,需要在代码中计算完成后传递到mapper.xml中
- 在java代码中运算
1 |
|
- 在mapper.xml文件中代码
1 | <!-- 分页查询 --> |
别名
- 系统内置别名:把类型全小写
- 给某个类起别名: alias=”自定义”
- mybatis.xml配置文件
1 | <typeAliases> |
- mapper.xml
1 | <select id="page" resultType="peo" parameterType="map"> |
- 直接给某个包下所有类起别名, 别名为类名,区分大小写。
- mybatis.xml配置
1 | <typeAliases> |
- mapper.xml通过类名引用。
1 | <select id="page" resultType="People" parameterType="map"> |
MyBatis实现新增
- 概念复习
- 功能:从应用程序角度出发,软件具有哪些功能。
- 事务: 从数据库角度出发,完成业务时需要执行的SQL集合,统称一个事务。
- 业务: 完成功能时的逻辑。对应Service中一个方法
- 事务回滚:如果在一个事务中某个sql执行事务,希望回归到事务的原点,保证数据库数据的完整性。
- 在Mybatis中默认关闭了JDBC自动提交的功能。
- 每一个SqlSession默认都是不自动提交事务。
- session.commit()提交事务。
- openSession(true):自动提交,setAutoCommit(true);
- mybatis底层是JDBC的封装
- JDBC中
executeUpdate()执行新增,删除,修改的SQL,返回值int,表示受影响的行数 - mybatis中的
标签没有resultType属性,认为返回值int
- JDBC中
- 在openSession()时Mybatis会创建SqlSession时同时创建一个Transaction(事务对象),同时autoCommit为false
- 如果出现异常,应该session.roolback()进行事务回滚。
- 使用
进行数据库操作时,要添加事务提交处理. Mybatis接口绑定方案及多参数传递
- 作用:实现创建一个接口后把mapper.xml由mybatis生成接口的实现类,通常调用接口对象就可以获取mapper.xml中编写的sql。
- 后面mybatis和spring整合时使用的是这个方案。
- 实现步骤:
- 创建一个接口
- 接口包名和接口名与mapper.xml中的
namespace相同。 - 接口中的方法名和mapper的id属性值相同。
- 接口包名和接口名与mapper.xml中的
- 在mybatis.xml中使用
标签来进行扫描接口和mapper.xml
- 创建一个接口
- 代码实现步骤
- 在mybatis.xml的
中使用
1
2
3<mappers>
<package name="com.zhuchuli.mapper"/>
</mappers> - 在mybatis.xml的
- 在com.zhuchuli.mapper新建一个接口
1 |
|
- 在com.zhuchuli.mapper新建一个LogMapper.xml文件
1 | <mapper namespace="com.zhuchuli.mapper.LogMapper"> |
- 测试
1 | LogMapper logMapper = session.getMapper(LogMapper.class); |
- 注意:namespace必须和接口的完全限定路径一致,id值必须与接口中的方法名一致。
- 如果接口中的方法为多个参数,可以省略parameter
- 多参数实现方法
- 在接口中声明方法
1 | List<Log> setByAccInAccount(String accin,String account); |
- 在mapper.xml文件中添加,#{}可以使用[param0,param1,arg0,arg1]
1 | <select id="setByAccInAccount" resultType="log"> |
- 可以使用注解
- 在接口中声明方法
1
2
3
4
5
6
7/***
* mybatis把参数转换为map,@Param("")当成key,后面的参数值当成value
* @param accin
* @param account
* @return
*/
List<Log> setByAccInAccount(@Param("accin") String accin,@Param("account") String account);
- 在mapper.xml文件中添加。#{}里面的内容为@param(“内容”)参数中的内容
1 | select * from log where accin=#{accin} and accout=#{accout} |
动态SQL
根据不同的条件需要执行不同的SQl命令,成为动态sql
Nybatis中动态sql在mapper.xml添加逻辑判断等
1
2
3
4
5
6
7
8
9
10
11<!-- 当多参数时,不需要写parameter -->
<select id="setByAccInAccount" resultType="log">
select * from log where 1=1
<!-- OGNL表达式,直接写key或对象的属,不需要添加任何特殊字符 -->
<if test="accin!=null and accin!='' ">
and accin=#{param1}
</if>
<if test="accout!=null and accout!=''">
and accout=#{param2}
</if>
</select>>* 当编写where标签时,如果内容中第一个是and,去掉第一个and。 >* 如果where中有内容会生成where,如果没有内容不会生成where关键字。 >* 比使用if标签少写了1=1 1
2
3
4
5
6
7
8
9
10
11
12<select id="setByAccInAccount" resultType="log">
select * from log
<!-- OGNL表达式,直接写key或对象的属,不需要添加任何特殊字符 -->
<where>
<if test="accin!=null and accin!='' ">
and accin=#{param1}
</if>
<if test="accout!=null and accout!=''">
and accout=#{param2}
</if>
</where>
</select>- 只要有一个成立,其他的都不会执行。
- 代码示例:如果accin和accout都不是Null或不是””,生成的sql中只有where accin=?
1
2
3
4
5
6
7
8
9
10
11
12
13
14<select id="setByAccInAccount" resultType="log">
select * from log
<!-- OGNL表达式,直接写key或对象的属,不需要添加任何特殊字符 -->
<where>
<choose>
<when test="accin!=null and accin!=''">
and accin=#{param1}
</when>
<when test="accout!=null and accout!=''">
and accout=#{param2}
</when>
</choose>
</where>
</select>标签:用在修改SQL中set从句 - 作用:去掉最后一个逗号
- 如果
里面有内容生成set关键字,没有则不生成 - 代码示例 : id=#{id} 防止
中没有内容。
1
2
3
4
5
6
7
8
9
10
11
12
13<update id="upd" parameterType="log">
update log
<set>
id=#{id},
<if test="accIn!=null and accIn!=''">
accin=#{accIn},
</if>
<if test="accOut!=null and accOut!=''">
accout=#{occOut}
</if>
</set>
where id=#{id}
</update>>* prefix 在前面添加内容 >* prefixOverrides:去掉前面内容 >* suffix:在后面添加内容 >* suffixOverrides 去掉后面内容 >* 执行顺序:先去掉内容再添加内容 实现模糊查询 - 作用:给参数重新赋值
- 场景:模糊查询,在原内容前后添加内容
标签 - 循环参数内容,还具备在内容前后添加内容,还具备加分隔符功能
- 使用场景:in查询中,批量新增中(mybatis中foreach效率较低)
- 示例
- collection=””要遍历的集合
- item:迭代变量,#{迭代变量名获取内容}
- open 循环后左侧要添加的内容
- close 循环后右侧要添加的内容
- separator 每次循环时,元素之间的分隔符
1
2
3
4
5
6<select id="selIn" parameterType="list">
select * from log where id in
<foreach collection="list" item="abc" close="" open="" >
#{abc}
</foreach>
</select>
- 如果希望批量新增,sql命令
1 | insert into log values(default,1,2),(default,2,3) |
- openSession()必须指定 ExecutorType.BATCH
1 | SqlSession session=factory.openSession(ExecutorType.BATCH); |
- 某些sql片段,如果希望复用,可以使用
定义这个片段
1
2
3<sql id="mysql">
id,accin,accout,money
</sql>- 某些sql片段,如果希望复用,可以使用
- 在
<select>、<delete>、<update>、<insert>中使用标签引用
1 | select <include refid="mysql"> from log |
ThreadLocal+OpenSessionInView
- 线程容器,给线程绑定一个Object内容,后只要线程不变,可以随时取出。
- 改变内容,无法取出内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15package com.zhuchuli.test;
public class Test {
public static void main(String[] args) {
ThreadLocal<Integer> threadLocal=new ThreadLocal<Integer>();
threadLocal.set(13);
new Thread(()-> {
threadLocal.set(23);
System.out.println(Thread.currentThread().getName()+"--->"+threadLocal.get());
}).start();
System.out.println(Thread.currentThread().getName()+"--->"+threadLocal.get());
}
}
缓存
- 应用程序和数据库交互的过程是一个相对耗时的过程。
- 缓存存在的意义:让应用程序减少对数据库的访问,提升程序运行效率。
- Mybatis中默认SqlSession缓存开启
- 同一个
SqlSession对象调用同一个<select>时,只有第一次访问数据库,第一次之后把查询结果缓存到SqlSession缓存区(内存)中。 - 缓存的对象是statement对象。(简单记忆:必须是用一个
<select>)- 在mybatis时一个
<select>对应一个Statement对象.
- 在mybatis时一个
- 有效范围必须是同一个SqlSession对象
- 同一个
- 缓存流程
- 先去缓存区中找是否存在statement。
- 返回结果。
- 如果没有缓存statement对象,去数据库获取数据。
- 数据库返回查询结果.
- 把查询结果放到对应的缓存区中。
- SqlSessionFactory缓存
- 二级缓存
- 有效范围:同一个factory内哪个SqlSession都可以获取。
- 什么时候使用二级缓存:
- 当数据频繁被使用,很少被修改
- 使用二级缓存的步骤,在mapper.xml文件中添加
<cache readOnly="true"></cache>- 如果不写
readOnly="true",需要把实体类实例化
- 如果不写
- 当SqlSession对象close()时或commit()时会把SqlSession缓存的数据刷到SqlSessionFactory缓存区中。
多表查询分类
- Mybatis实现多表查询方式:
- 业务装备:对两个表编写单表查询语句,在业务(Service)把查询的两个结果进行关联.
- 使用auto mapping特性,在实现两个表联合查询时通过别名完成映射
- 使用
Mybatis的<resultMap>标签进行实现。
- 多表查询时,类中包含另一类的对象的分类
- 单个对象
- 多个对象
<resultMap>标签- 该标签写在mapper.xml中,由程序员控制sql查询结果与实体类的映射关系。
- 默认Mybatis使用auto mapping特性.
- 使用
<resultMap>标签时,<select>标签不写resultType属性,而是使用resultMap属性引用<resultMap>标签
- 使用resultMap实现单表映射关系
- 实体类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23package com.zhuchuli.pojo;
public class Teacher {
private int id1;
private String name1;
public int getId1() {
return id1;
}
public void setId1(int id1) {
this.id1 = id1;
}
public String getName1() {
return name1;
}
public void setName1(String name1) {
this.name1 = name1;
}
public String toString() {
return "Teacher [id1=" + id1 + ", name1=" + name1 + "]";
}
}
- TeacherMap.xml
1 | <mapper namespace="com.zhuchuli.mapper.TeacherMapper"> |
- 数据库设计

使用resultMap实现关联单个对象(N+1方式)
- N+1查询方式:先查询出某个表的全部信息,根据这个表的信息查询另一个表的信息。
- 与业务转配的区别:
- 在service里面写代码,由mybatis完成转配
- 实现步骤
- 在Student实现类中包含一个Teacher对象
1
2
3
4
5
6
7public class Student {
private int id;
private String name;
private int age;
private int tid;
private Teacher teacher;
}
- 在TeacherMapper中提供一个查询:
1 | <select id="selById" resultType="teacher" parameterType="int"> |
- 在StudentMapper中使用:
<association>装配一个对象时使用。- property:对象在类中的属性名。
- select:通过哪个查询查询这个对象的信息。
- column:把当前表的哪个列值最为参数传递给另一个查询。
- 大前提是使用N+1方式时,如果列名和属性名相同可以不配置,使用Auto mapping特性,但是Mybatis默认只给列装配一次。
1 | <mapper namespace="com.zhuchuli.mapper.StudentMapper"> |
- 可以将上面简化为:
1 | <mapper namespace="com.zhuchuli.mapper.StudentMapper"> |
使用<resultMap>查询关联集合对象(N+1)
在Teacher中添加
List<Student>1
2
3
4
5public class Teacher {
private int id;
private String name;
private List<Student> list;
}在StudentMapper.xml中添加通过tid查询
1
2
3<select id="selByTid" resultType="student" parameterType="int">
select * from student where tid = #{0}
</select>在TeacherMapper.xml中添加查询全部
<collection>当属性是集合类型时使用的标签
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<mapper namespace="com.zhuchuli.mapper.TeacherMapper">
<resultMap type="teacher" id="mymap">
<id column="id" property="id"/>
<result column="name" property="name"/>
<collection property="list" ofType="student" select="com.zhuchuli.mapper.StudentMapper.selByTid" column="id"></collection>
</resultMap>
<select id="selAll" resultMap="mymap">
select * from teacher
</select>
</mapper>
使用<resultMap>实现加载集合数据(联合查询方式)
- 在TeacherMapper.xml添加
- mybatis可以通过主键判断对象是否被加载过
- 不需要担心重复创建Teacher
1 | <resultMap type="teacher" id="mymap1"> |
AutoMapping 结合别名实现多表查询
- 只能使用多表联合查询
- 查询出的列名与属性名必须相同
- 实现方式:
.在sql是关键字,两侧添加反单引号- 这个方法只适合对象的查询,不适合list集合的查询
1 |
|
- Mybatis 注解
注解:就是为了简化配置文件
Mybatis的注解简化Mapper.xml文件
- 如果涉及动态SQL依然使用mapper.xml
mapper.xml和注解可以共存。
使用注解时mybatis.xml中
<mapper>的使用:<package/><mapper class="">
实现查询、修改、新增、删除等功能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19("select * from teacher")
List<Teacher> selAll();
("insert into teacher(id,name) values(default,#{name})")
int insTeacher(Teacher teacher);
("update teacher set name=#{name} where id=#{id}")
int updTeacher(Teacher teacher);
("delete from teacher where id=#{0}")
int delTeacher(int id);
(value ={
(id=true,property="id",column="id"),
(property="name",column="name"),
(property="list",column="id",many=(select="com.zhuchuli.mapper.StudentMapper.selById"))
})
("select * from teacher")
List<Teacher> selTeacher();- @Results():相当于
<resultMap> - @result():相当于
<id/>或<result/> - @Result(id=true):相当于
<id/> - @Many:相当于
<collection/> - @One:相当于
<association/>
Mybatis运行原理
- @Results():相当于
- 运行过程中可能遇到的类:
- Resources:Mybatis中IO流的工具类。
- 作用:负责加载配置文件
- SqlSessionFactoryBuilder():构造器
- 作用:创建SqlSessionFactory接口的实现类
- XMLConfigBuilder:Mybatis全局配置文件内容构造器类
- 负责读取流内容并转换为Java代码
- Configuration 封装了全局配置文件所有配置信息。
- 全局配置文件内容都存在该对象中。
- DefaultSqlSessionFactory是SqlSessionFactory接口的实现类。
- Transaction 事务类
- 每一个SqlSession都会带一个Transaction对象
- TransactionFactory 事务工厂
- 负责创建Transaction对象
- Executor Mybatis执行器
- 作用:负责执行SQL语句
- 相当于JDBC中的statement对象(或PreperedStatement或CallableStatement)
- 默认的执行器SimpleExecutor
- 批量操作:BatchExecutor
- 通过openSession(参数控制)
- DefaultSqlSession是SqlSession接口的实现类
- ExceptionFactory:Mybatis中错误异常工厂
- Resources:Mybatis中IO流的工具类。
Spring全家桶
- SpringData
- SpringCloud
- SpringBoot
- SpringSession