纯手写爆肝史上最详细讲解SpringBoot

SpringBoot 基础

一、SpringBoot 简介

1.1. 什么是 Spring Boot

Spring Boot 是 Spring 项目中的一个子工程，与我们所熟知的 Spring-framework 同属于 spring 的产品:

一般把 Spring Boot 称为搭建程序的脚手架或者说是便捷搭建基于 Spring 的工程 脚手架。其最主要作用就是帮助开
发人员快速的构建庞大的 spring 项目，并且尽可能的减少一切 xml 配置，做到开箱即用，迅速上手，让开发人员关注业务而非配置。

1.2. 为什么要学习 Spring Boot

java 一直被人诟病的一点就是臃肿、麻烦。
究其原因注意是两点：

复杂的配置

项目各种配置其实是开发时的损耗， 因为在思考 Spring 特性配置和解决业务问题之间需要进行思维切换，所以写
配置挤占了写应用程序逻辑的时间。

个是混乱的依赖管理

项目的依赖管理也是件吃力不讨好的事情。决定项目里要用哪些库就已经够让人头痛的了，你还要知道这些库的哪
个版本和其他库不会有冲突，这难题实在太棘手。并且，依赖管理也是一种损耗，添加依赖不是写应用程序代码。
一旦选错了依赖的版本，随之而来的不兼容问题毫无疑问会是生产力杀手。

而 Spring Boot 让这一切成为过去！

Copy
Spring Boot 简化了基于Spring的应用开发，只需要“run”就能创建一个独立的、生产级别的Spring应用。
Spring Boot为Spring平台及第三方库提供开箱即用的设置（提供默认设置，存放默认配置的包就是启动器
starter），这样我们就可以简单的开始。多数Spring Boot应用只需要很少的Spring配置。

我们可以使用 Spring Boot 创建 java 应用，并使用 java –jar 启动它，就能得到一个生产级别的 web 工程。

1.3. Spring Boot 的特点

1.3.1 SpringBoot 的特点

为基于 Spring 的开发提供更快的入门体验

开箱即用，没有代码生成，也无需 XML 配置。同时也可以修改默认值来满足特定的需求

提供了一些大型项目中常见的非功能性特性，如嵌入式服务器、安全、指标，健康检测、外部配置等
SpringBoot 不是对 Spring 功能上的增强，而是提供了一种快速使用 Spring 的方式

二、SpringBoot 快速入门

接下来，我们就来利用 Spring Boot 搭建一个 web 工程，体会一下 Spring Boot 的魅力所在！

2.1 创建 Maven 工程

使用 idea 工具创建一个 maven 工程，该工程为普通的 java 工程即可

2.2 添加 SpringBoot 的起步依赖

看到这里很多同学会有疑惑，前面说传统开发的问题之一就是依赖管理混乱，怎么这里我们还需要管理依赖呢？难
道 Spring Boot 不帮我们管理吗？
别着急，现在我们的项目与 Spring Boot 还没有什么关联。Spring Boot 提供了一个名为 spring-boot-starter-parent 的工程，里面已经对各种常用依赖（并非全部）的版本进行了管理，我们的项目需要以这个项目为父工程，这样我们就不用操心依赖的版本问题了，需要什么依赖，直接引入坐标即可 。

2.2.1. 添加父工程坐标

Copy
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐parent</artifactId>
<version>2.1.5.RELEASE</version>
</parent>

2.2.2. 添加 web 启动器

为了让 Spring Boot 帮我们完成各种自动配置，我们必须引入 Spring Boot 提供的自动配置依赖，我们称为 启动器
。因为我们是 web 项目，这里我们引入
web 启动器，在 pom.xml 文件中加入如下依赖：

Copy
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐web</artifactId>
</dependency>
</dependencies>

需要注意的是，我们并没有在这里指定版本信息。因为 Spring Boot 的父工程已经对版本进行了管理了。这个时
候，我们会发现项目中多出了大量的依赖。那些依赖都是 Spring Boot 根据 spring-boot-starter-web 这个依赖自动引入的，而且所有的版本都已经管理
好，不会出现冲突 。

2.3 编写 SpringBoot 引导类 和 Controller

要通过 SpringBoot 提供的引导类起步 SpringBoot 才可以进行访问

Copy
package com.summer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MySpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(MySpringBootApplication.class);
}
}

在引导类 MySpringBootApplication 同级包或者子级包中创建 QuickStartController

Copy
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class QuickController {
@RequestMapping("/quick")
@ResponseBody
public String quick(){
return "springboot 访问成功!";
}
}

Copy
@ResponseBody注解作用 其实是将java对象转为json格式的数据响应给客户端，如果返回值是字符串，那
么直接将字符串写到客户端

2.4 启动测试

执行 SpringBoot 起步类的主方法，控制台打印日志如下：

通过日志发现，Tomcat started on port (s): 8080 (http) with context path ''
tomcat 已经起步，端口监听 8080，web 应用的虚拟工程名称为空
打开浏览器访问 url 地址为：http://localhost:8080/quick

2.5 SpringBoot 工程热部署

我们在开发中反复修改类、页面等资源，每次修改后都是需要重新启动才生效，这样每次启动都很麻烦，浪费了大
量的时间，我们可以在修改代码后不重启就能生效，在 pom.xml 中添加如下配置就可以实现这样的功能，我们称
之为热部署 。

Copy
<!‐‐热部署配置‐‐>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐devtools</artifactId>
</dependency>

注意：IDEA 进行 SpringBoot 热部署失败原因
出现这种情况，并不是热部署配置问题，其根本原因是因为 Intellij IEDA 默认情况下不会自动编译，需要对 IDEA 进
行自动编译的设置，如下：

然后 Shift+Ctrl+Alt+/，选择 Registry

2.6 使用 idea 快速创建 SpringBoot 项目

通过 idea 快速创建的 SpringBoot 项目的 pom.xml 中已经导入了我们选择的 web 的起步依赖的坐标

可以使用快速入门的方式创建 Controller 进行访问，此处不再赘述

三、 java 配置应用

在入门案例中，我们没有任何的配置，就可以实现一个 SpringMVC 的项目了，快速、高效！但是有同学会有疑问，如果没有任何的 xml，那么我们如果要配置一个 Bean 该怎么办？比如我们要配置一个数据库连接池，以前会这么配置：

Copy
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>

3.1. Spring 配置历史

事实上，在 Spring3.0 开始，Spring 官方就已经开始推荐使用 java 配置来代替传统的 xml 配置了，我们不妨来回顾一
下 Spring 的历史：

Spring1.0 时代
在此时因为 jdk1.5 刚刚出来，注解开发并未盛行，因此一切 Spring 配置都是 xml 格式，想象一下所有的 bean 都
用 xml 配置，细思极恐啊，心疼那个时候的程序员 2 秒

Spring2.0 时代
Spring 引入了注解开发，但是因为并不完善，因此并未完全替代 xml，此时的程序员往往是把 xml 与注解进行
结 合，貌似我们之前都是这种方式

Spring3.0 及以后
3.0 以后 Spring 的注解已经非常完善了，因此 Spring 推荐大家使用完全的 java 配置来代替以前的 xml，不过似乎
在国内并未推广盛行。然后当 Spring Boot 来临，人们才慢慢认识到 java 配置的优雅。

有句古话说的好：拥抱变化，拥抱未来。所以我们也应该顺应时代潮流，做时尚的弄潮儿，一起来学习下 java 配置的玩法。

3.2. 尝试 java 配置

java 配置主要靠 java 类和一些注解，比较常用的注解有：

@Configuration ：声明一个类作为配置类，代替 xml 文件

@Bean ：声明在方法上，将方法的返回值加入 Bean 容器，代替 标签

@Value ：属性注入

@PropertySource ：加载外部属性文件

我们接下来用 java 配置来尝试实现连接池配置：

在 pom.xml 文件中添加 Druid 连接池依赖如下

Copy
<!‐‐ Druid连接池 ‐‐>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>

2.jdbc.properties

Copy
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=root

配置类

Copy
@Configuration
@PropertySource("classpath:jdbc.properties")
public class JdbcConfig {
@Value("${jdbc.url}")
String url;
@Value("${jdbc.driverClassName}")
String driverClassName;
@Value("${jdbc.username}")
String username;
@Value("${jdbc.password}")
String password;
@Bean
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
}

解读：

@Configuration ：声明我们 JdbcConfig 是一个配置类

@PropertySource ：指定属性文件的路径是: classpath.properties

通过 @Value 为属性注入值

通过 @Bean 将 dataSource () 方法声明为一个注册 Bean 的方法，Spring 会自动调用该方法，将方法的返回值

加入 Spring 容器中。
然后我们就可以在任意位置通过 @Autowired 注入 DataSource 了！

测试

Copy
@Controller
public class QuickController {
@Autowired
private DataSource dataSource;
@RequestMapping("/quick")
@ResponseBody
public String hello() {
System.out.println("dataSource = " + dataSource);
return "hello, spring boot!";
}
}

3.3. Spring Boot 的属性注入

在上面的案例中 我们实验了 java 配置方式。不过属性注入使用的是 @Value 注解。这种方式虽然可行，但是不够强
大，因为它只能注入基本类型值。
在 Spring Boot 中，提供了一种新的属性注入方式，支持各种 java 基本数据类型及复杂类型的注入。属性文件的名
称有变化，默认的文件名必须是：

application.properties 或application.yml

Copy
/
/将该类声明为属性读取类
@ConfigurationProperties(prefix ="jdbc")
public class JdbcProperties {
private String driverClassName;
private String url;
private String username;
private String password;
// ... 略
// getters 和 setters
}

在类上通过 @ConfigurationProperties 注解声明当前类为属性读取类

prefix="jdbc" 读取属性文件中，前缀为 jdbc 的值。

在类上定义各个属性，名称必须与属性文件中 jdbc. 后面部分一致

需要注意的是，这里我们并没有指定属性文件的地址，所以我们需要把 jdbc.properties 名称改为

application.properties，这是 Spring Boot 默认读取的属性文件名
【注意】如果出现如下提示，项目也可以运行；

如果要去掉上述的提示，则可以在 pom.xml 文件中添加如下依赖：

Copy
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐configuration‐processor</artifactId>
<!‐‐不传递依赖‐‐>
<optional>true</optional>
</dependency>

优雅的注入

Copy
@Configuration
@EnableConfigurationProperties(JdbcProperties.class)
public class JdbcConfig {
@Bean
public DataSource dataSource(JdbcProperties jdbc) {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl(jdbc.getUrl());
dataSource.setDriverClassName(jdbc.getDriverClassName());
dataSource.setUsername(jdbc.getUsername());
dataSource.setPassword(jdbc.getPassword());
return dataSource;
}
}

更优雅的注入
事实上，如果一段属性只有一个 Bean 需要使用，我们无需将其注入到一个类（JdbcProperties，将该类上的所有注
解去掉）中。而是直接在需要的地方声明即可；再次修改 JdbcConfig 类为如下代码：

Copy
@Configuration
public class JdbcConfig {
@Bean
// 声明要注入的属性前缀，Spring Boot会自动把相关属性通过set方法注入到DataSource中
@ConfigurationProperties(prefix = "jdbc")
public DataSource dataSource() {
return new DruidDataSource();
}
}

3.4 Yaml 配置文件

配置文件除了可以使用 application.properties 类型，还可以使用后缀名为：.yml 或者.yaml 的类型，也就是：
application.yml 或者 application.yaml
yaml 与 properties 配置文件除了展示形式不相同以外，其它功能和作用都是一样的；在项目中原路的读取方式不需
要改变。
yml 配置文件的特征：

树状层级结构展示配置项；

配置项之间如果有关系的话需要分行空两格；

配置项如果有值的话，那么需要在：之后空一格再写配置项值；

基本格式：

Copy
jdbc:
driverClassName : com.mysql.jdbc.Driver
url : jdbc:mysql://localhost:3306/kw
username : root
password : root

把 application.properties 修改为 application.yml 进行测试。

四、自动配置原理解析

使用 Spring Boot 之后，一个整合了 SpringMVC 的 WEB 工程开发，变的无比简单，那些繁杂的配置都消失不见了，
这是如何做到的？
一切魔力的开始，都是从我们的 main 函数来的，所以我们再次来看下启动类：
按住 Ctrl 点击查看启动类 MySpringBootApplication 上的注解 @SpringBootApplication

Copy
//创建springboot工程的起步引导类，工程的入口
//自动扫描当前类所在的包以其子包
@SpringBootApplication
public class MySpringBootApplication {
public static void main(String[] args) {
//运行springboot应用
SpringApplication.run(MySpringBootApplication.class,args);
}
}

注解 @SpringBootApplication 的源码

Copy
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
/**
* Exclude specific auto‐configuration classes such that they will never be applied.
* @return the classes to exclude
*/
@AliasFor(annotation = EnableAutoConfiguration.class)
Class<?>[] exclude() default {};
... ... ...
}

这里重点的注解有 3 个：

@SpringBootConfiguration：等同与 @Configuration，既标注该类是 Spring 的一个配置类

@EnableAutoConfifiguration：SpringBoot 自动配置功能开启

按住 Ctrl 点击查看注解 @EnableAutoConfig

Copy
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
... ... ...
}

其中，@EnableAutoConfifiguration 的作用就是从 META-INF/spring.factories 文件中读取有关自动配置的配
置信息

spring.factories 文件中有关自动配置的配置信息如下：

上面配置文件存在大量的以 AutoConfiguration 为结尾的类名称，这些类就是存有自动配置信息的类，而
SpringApplication 在获取这些类名后再加载
我们以 ServletWebServerFactoryAutoConfiguration 为例来分析源码：

Copy
@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
... ... ...
}

其中，
@EnableConfigurationProperties (ServerProperties.class) 代表加载 ServerProperties 服务器配置属性类，这种玩
法我们玩过～～
进入 ServerProperties.class 源码如下：

Copy
@
ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {
/**
* Server HTTP port.
*/
private Integer port;
/**
* Network address to which the server should bind.
*/
private InetAddress address;
... ... ...
}

其中，
prefix = "server" 表示 SpringBoot 配置文件中的前缀，SpringBoot 会将配置文件中以 server 开始的属性映射到该类
的字段中。映射关系如下：

@ComponentScan

Copy
配置组件扫描的指令。提供了类似与 <context:component-scan> 标签的作用
通过basePackageClasses或者basePackages属性来指定要扫描的包。如果没有指定这些属性，那么将
从声明这个注解的类所在的包开始，扫描包及子包

而我们的 @SpringBootApplication 注解声明的类就是 main 函数所在的启动类，因此扫描的包是该类所在包及
其子包。
因此，一般启动类会放在一个比较前的包目录中。

五、SpringBoot 与整合其他技术

5.1 整合 SpringMVC

虽然默认配置已经可以使用 SpringMVC 了，不过我们有时候需要进行自定义配置。

5.1.1. 修改端口

查看 SpringBoot 的全局属性可知，端口通过以下方式配置：

Copy
server:
port: 80

5.2.2. 访问静态资源

现在，我们的项目是一个 jar 工程，那么就没有 webapp，我们的静态资源该放哪里呢？

回顾我们在上面看的源码，有一个叫做 ResourceProperties 的类，里面就定义了静态资源的默认查找路径

默认的静态资源路径为：

classpath:/META-INF/resources/

classpath:/resources/

classpath:/static/

classpath:/public

Copy
注意：如果访问图片时候没有显示；可以先将项目先clean再启动，或者创建 public、resources 文件夹，然
后 图
片放置到public或resources中。

5.2. 整合 jdbc 和事务

spring 中的 jdbc 连接和事务是配置中的重要一环，在 SpringBoot 中该如何处理呢？
答案是不需要处理，我们只要找到 SpringBoot 提供的启动器即可，在 pom.xml 文件中添加如下依赖：

Copy
<!‐‐整合jdbc和事务‐‐>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐jdbc</artifactId>
</dependency>

当然，不要忘了数据库驱动，SpringBoot 并不知道我们用的什么数据库，这里我们选择 MySQL；同样的在
pom.xml 文件中添加如下依赖：

Copy
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql‐connector‐java</artifactId>
</dependency>

至于事务，SpringBoot 中通过注解来控制。就是我们熟知的 @Transactional 使用的时候设置在对应的类或方法上
即可。

5.3 整合连接池

其实，在刚才引入 jdbc 启动器的时候，SpringBoot 已经自动帮我们引入了一个连接池：

HikariCP 应该是目前速度最快的连接池了，我们看看它与 c3p0 的对比：

因此，我们只需要指定连接池参数即可；打开 application.yml 添加修改配置如下：

Copy
spring:
datasource:
driver‐class‐name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF‐
8&serverTimezone=UTC
username: root
password: root

5.4 SpringBoot 整合 Mybatis

添加 Mybatis 的起步依赖
SpringBoot 官方并没有提供 Mybatis 的启动器，不过 Mybatis 官网自己实现了。在项目的 pom.xml 文件中加入如下
依赖：

Copy
<!‐‐mybatis起步依赖‐‐>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis‐spring‐boot‐starter</artifactId>
<version>2.1.2</version>
</dependency>

添加数据库驱动坐标

Copy
<!‐‐ MySQL连接驱动 ‐‐>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql‐connector‐java</artifactId>
</dependency>

配置 application.yml ，常用配置如下：

Copy
#mybatis配置
mybatis:
type‐aliases‐package: com.bailiban.domain
mapper‐locations: classpath:com/bailiban/mapper/*Mapper.xml
configuration:
log‐impl: org.apache.ibatis.logging.stdout.StdOutImpl

配置 Mapper 扫描
需要注意，这里没有配置 mapper 接口扫描包，因此我们需要给每一个 Mapper 接口添加 @Mapper 注解，才能被
识别。

Copy
@Mapper
public interface UserMapper {
}

或者，我们也可以不加注解，而是在启动类上添加扫描包注解 (推荐)：

Copy
@SpringBootApplication
@MapperScan("com.bailiban.mapper")
public class MySpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(MySpringBootApplication.class);
}
}

5.4.1 创建 user 表

在 test 数据库中创建 user 表

Copy
DROP table if EXISTS user;
##用户
CREATE TABLE `user` (
`uid` INT AUTO_INCREMENT ,
`username` VARCHAR(20) DEFAULT NULL,
`password` VARCHAR(20) DEFAULT NULL,
`realname` VARCHAR(20) DEFAULT NULL,
`email` VARCHAR(30) DEFAULT NULL,
`telephone` VARCHAR(20) DEFAULT NULL,
PRIMARY KEY (`uid`)
);
INSERT INTO `user` VALUES (NULL,'wc001','888888','旺财','aaa@store.com','15723689921'),
(NULL,'xq001','888888','小强','bbb@store.com','15723689922'),
(NULL,'xb001','888888','小宝','ccc@store.com','15723689923');

5.4.2 创建实体 Bean

Copy
package com.bailiban.domain;
public class User {
private int uid;//用户编号
private String username;//用户名
private String password;//密码
private String realname;//真实姓名
private String email;//邮箱
private String telephone;// 电话
//省略 setter getter方法
}

5.4.3 编写 Mapper

Copy
@Mapper
public interface UserMapper {
public List<User> queryUserList();
}

注意：@Mapper 标记该类是一个 mybatis 的 mapper 接口，可以被 spring boot 自动扫描到 spring 上下文中

5.4.4 配置 Mapper 映射文件

在 src/main/resources/com/bailiban/mapper 路径下加入 UserMapper.xml 配置文件 "

Copy
<
?xml version="1.0" encoding="utf‐8" ?>
<!DOCTYPE mapper PUBLIC "‐//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis‐3‐
mapper.dtd" >
<mapper namespace="com.bailiban.mapper.UserMapper">

select * from user

</mapper>

5.4.5 在 application.yml 中添加 mybatis 的信息

Copy
#mybatis配置
mybatis:
type‐aliases‐package: com.bailiban.domain
mapper‐locations: classpath:com/bailiban/mapper/*Mapper.xml
configuration:
log‐impl: org.apache.ibatis.logging.stdout.StdOutImpl

5.4.6 编写测试 Controller

Copy
@Controller
public class MapperController {
@Autowired
private UserMapper userMapper;
@RequestMapping("/queryUser")
@ResponseBody
public List<User> queryUser(){
List<User> users = userMapper.queryUserList();
return users;
}
}

5.5 Junit 测试

在 springboot 项目中如果要使用 Junit 进行单元测试，则需要添加如下的启动器：

Copy
<!‐‐单元测试启动器‐‐>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis‐spring‐starter‐test</artifactId>
</dependency>

在测试包下编写测试类
在测试类上面必须要添加 @SpringBootTest 注解。

Copy
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceTest {
@Autowired
private UserService userService;
@Test
public void test1(){
List<User> users = userService.selectAll();
System.out.println(users);
}
}

5.6 整合 Redis

概念： redis 是一款高性能的 NOSQL 系列的非关系型数据库

5.6.1 什么是 NOSQL

NoSQL (NoSQL = Not Only SQL)，意即 “不仅仅是 SQL”，是一项全新的数据库理念，泛指非关系型的数据库。
随着互联网 web2.0 网站的兴起，传统的关系数据库在应付 web2.0 网站，特别是超大规模和高并发的 SNS 类型的
web2.0 纯动态网站已经显得力不从心，暴露了很多难以克服的问题，而非关系型的数据库则由于其本身的特点得
到了非常迅速的发展。NoSQL 数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战，尤其是大数据应用难题

5.6.2 NOSQL 和关系型数据库比较

优点：

优点：

成本：nosql 数据库简单易部署，基本都是开源软件，不需要像使用 oracle 那样花费大量成本购买使用，相比
关系型数据库价格便宜。

查询速度：nosql 数据库将数据存储于缓存之中，关系型数据库将数据存储在硬盘中，自然查询速度远不及
nosql 数据库。

存储数据的格式：nosql 的存储格式是 key,value 形式、文档形式、图片形式等等，所以可以存储基础类型以及对象或者是集合等各种格式，而数据库则只支持基础类型。

扩展性：关系型数据库有类似 join 这样的多表查询机制的限制导致扩展很艰难。
缺点：

维护的工具和资料有限，因为 nosql 是属于新的技术，不能和关系型数据库 10 几年的技术同日而语。

不提供对 sql 的支持，如果不支持 sql 这样的工业标准，将产生一定用户的学习和使用成本。

不提供关系型数据库对事务的处理。

总结：
关系型数据库与 NoSQL 数据库并非对立而是互补的关系，即通常情况下使用关系型数据库，在适合使用 NoSQL 的
时候使用 NoSQL 数据库，让 NoSQL 数据库对关系型数据库的不足进行弥补。
一般会将数据存储在关系型数据库中，在 nosql 数据库中备份存储关系型数据库的数据

5.6.3 主流的 NOSQL 产品

相关产品： Tokyo Cabinet/Tyrant、Redis、Voldemort、Berkeley DB
典型应用： 内容缓存，主要用于处理大量数据的高访问负载。
数据模型： 一系列键值对
优势： 快速查询
劣势： 存储的数据缺少结构化
文档型数据库
相关产品：CouchDB、MongoDB
典型应用：Web 应用（与 Key-Value 类似，Value 是结构化的）
数据模型： 一系列键值对
优势：数据结构要求不严格
劣势： 查询性能不高，而且缺乏统一的查询语法

5.6.4 什么是 Redis

Redis 是用 C 语言开发的一个开源的高性能键值对（key-value）数据库，官方提供测试数据，50 个并发执行
100000 个请求，读的速度是 110000 次 /s, 写的速度是 81000 次 /s ，且 Redis 通过提供多种键值数据类型来适应不同场
景下的存储需求，目前为止 Redis 支持的键值数据类型如下：
\1. 字符串类型 string
\2. 哈希类型 hash
\3. 列表类型 list
\4. 集合类型 set
\5. 有序集合类型 sortedset

5.6.5 redis 的应用场景

缓存（数据查询、短连接、新闻内容、商品内容等等）

聊天室的在线好友列表

任务队列。（秒杀、抢购、12306 等等）

应用排行榜

网站访问统计

数据过期处理（可以精确到毫秒）

分布式集群架构中的 session 分离

5.6.6 整合

在 pom.xml 文件中添加如下依赖

Copy
<!‐‐redis‐‐>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐data‐redis</artifactId>
</dependency>

配置 application.yml 文件

Copy
spring:
redis:
host: localhost
port: 6379

测试代码

Copy
package com.summer.test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.*;
@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisTest {
@Autowired
private RedisTemplate redisTemplate;
@Test
public void test1() {
//保存字符串 最常用的
redisTemplate.opsForValue().set("hello", "哈哈");
//获取
String hello = (String) redisTemplate.opsForValue().get("hello");
System.out.println(hello);
//保存和读取set
redisTemplate.opsForSet().add("s_key", "a", "b", "c");
Set set = redisTemplate.opsForSet().members("s_key");
System.out.println("set集合"+set);
//保存和读取List
List<String> list = Arrays.asList("a", "b", "c");
redisTemplate.opsForList().leftPush("l_key", list);
//获取
List<String> list1 = (List<String>) redisTemplate.opsForList().leftPop("l_key");
System.out.println("list集合"+list1);
//保存和读取map集合
Map<String, String> map = new HashMap<>();
map.put("name", "旺财");
map.put("age", "18");
redisTemplate.opsForHash().putAll("h_key", map);
//获取 map
Map<String, String> map1 = redisTemplate.opsForHash().entries("h_key");
//获取key的集合
Set key_set = redisTemplate.opsForHash().keys("h_key");
//获取value的集合
List value_list = redisTemplate.opsForHash().values("h_key");
System.out.println("key的集合:"+key_set);
System.out.println("value的集合:"+value_list);
System.out.println("map集合:"+map1);
//保存有序的set
redisTemplate.opsForZSet().add("z_key","a",10);
redisTemplate.opsForZSet().add("z_key","b",20);
redisTemplate.opsForZSet().add("z_key","c",30);
//获取
Set z_set = redisTemplate.opsForZSet().range("z_key", 0, ‐1);
System.out.println("有序的set"+z_set);
}
}