前言
上一篇:Spring Boot Web
下一篇:启动配置原理
一、Docker
1、简介
Docker是一个开源的应用容器引擎;是一个轻量级容器技术;Docker支持将软件编译成一个镜像;然后在镜像中各种软件做好配置,将镜像发布出去,其他使用者可以直接使用这个镜像;运行中的这个镜像称为容器,容器启动是非常快速的。
Docker架构:
2、核心概念
2.1 概念
docker主机(Host):安装了Docker程序的机器(Docker直接安装在操作系统之上);
docker客户端(Client):连接docker主机进行操作;
docker仓库(Registry):用来保存各种打包好的软件镜像;
docker镜像(Images):软件打包好的镜像;放在docker仓库中;
docker容器(Container):镜像启动后的实例称为一个容器;容器是独立运行的一个或一组应用
2.2 使用Docker的步骤:
1)、安装Docker
2)、去Docker仓库找到这个软件对应的镜像;
3)、使用Docker运行这个镜像,这个镜像就会生成一个Docker容器;
4)、对容器的启动停止就是对软件的启动停止;
3、安装Docker
3.1 安装Linux并配置好客户端
1)、VMWare、VirtualBox(安装);
2)、导入虚拟机文件centos7-atguigu.ova;
3)、双击启动linux虚拟机;使用 root/ 123456登陆
4)、使用客户端连接linux服务器进行命令操作;
5)、设置虚拟机网络;
桥接网络=选好网卡==接入网线;
6)、设置好网络以后使用命令重启虚拟机的网络
service network restart
7)、查看linux的ip地址
ip addr
8)、使用客户端连接linux;
3.2 安装Docker(CentOS)
- 安装docker:
yum install docker
- 在安装过程中输入:y 确认安装
- 启动docker:
[root@localhost ~]# systemctl start docker
查看版本
[root@localhost ~]# docker -v
Docker version 1.12.6, build 3e8e77d/1.12.6
- 设置开机自启动
[root@localhost ~]# systemctl enable docker
Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to /usr/lib/systemd/system/docker.service.
- 停止docker
systemctl stop docker
4、常用命令与操作
4.1 镜像操作
操作 | 命令 | 说明 |
---|---|---|
检索 | docker search 关键字 eg:docker search redis | 我们经常去docker hub上检索镜像的详细信息,如镜像的TAG。 |
拉取 | docker pull 镜像名:tag | :tag是可选的,tag表示标签,多为软件的版本,默认是latest |
列表 | docker images | 查看所有本地镜像 |
删除 | docker rmi image-id | 删除指定的本地镜像 |
4.2 容器操作
- 搜索镜像:
docker search tomcat
- 拉取镜像:
docker pull tomcat
- 根据镜像启动容器:
docker run --name mytomcat -d tomcat:latest
- 查看运行中的容器:
docker ps
- 停止运行中的容器
- 查看所有容器:
docker ps -a
- 删除一个容器:
docker rm 容器id
- 启动容器:
docker start 容器id
- 查看日志:
docker logs container-name/container-id
二、SpringBoot数据访问
1、JDBC
1.1 引入JDBC依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.22</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
1.2 配置DataSource
spring:
datasource:
username: root
password: root
url: jdbc:mysql://192.168.0.103:3306/jdbc
driver-class-name: com.mysql.cj.jdbc.Driver
#spring.datasource.initialization-mode 初始化模式(springboot2.0),其中有三个值,always为始终执行初始化,embedded只初始化内存数据库(默认值),如h2等,never为不执行初始化。
initialization-mode: always
1.3 连接测试
@SpringBootTest
class JdbcApplicationTests {
@Autowired
DataSource dataSource;
@Test
void contextLoads() throws SQLException {
System.out.println(dataSource.getClass());
Connection conn = dataSource.getConnection();
System.out.println(conn);
conn.close();
}
}
1.4 自动配置原理
-
Spring Boot对于JDBC的配置都在:
org.springframework.boot.autoconfigure.jdbc
下。 -
在
DataSourceConfiguration
类中定义了springBoot支持的数据源:- DBCP:
org.apache.commons.dbcp2.BasicDataSource
- Hikari:
com.zaxxer.hikari.HikariDataSource
- tomcat JDBC:
org.apache.tomcat.jdbc.pool.DataSource
- 自定义连接池:
@Configuration( proxyBeanMethods = false ) @ConditionalOnMissingBean({DataSource.class}) @ConditionalOnProperty( name = {"spring.datasource.type"} ) static class Generic { Generic() { } @Bean DataSource dataSource(DataSourceProperties properties) { //使用DataSourceBuilder创建数据源,利用反射创建响应type的数据源,并且绑定相关属性 return properties.initializeDataSourceBuilder().build(); } }
- DBCP:
-
在
DataSourceAutoConfiguration
类中自动导入了DataSourceInitializationConfiguration
类,而该类又自动导入了DataSourceInitializerInvoker
类,在该类中有如下两个方法:
public void afterPropertiesSet() {
DataSourceInitializer initializer = this.getDataSourceInitializer();
if (initializer != null) {
boolean schemaCreated = this.dataSourceInitializer.createSchema();
if (schemaCreated) {
this.initialize(initializer);
}
}
}
private void initialize(DataSourceInitializer initializer) {
try {
this.applicationContext.publishEvent(new DataSourceSchemaCreatedEvent(initializer.getDataSource()));
if (!this.initialized) {
this.dataSourceInitializer.initSchema();
this.initialized = true;
}
} catch (IllegalStateException var3) {
logger.warn(LogMessage.format("Could not send event to complete DataSource initialization (%s)", var3.getMessage()));
}
}
- 在这两个方法中分别调用了如下方法:
boolean schemaCreated = this.dataSourceInitializer.createSchema();
this.dataSourceInitializer.initSchema();
- 这两个方法如下:
boolean createSchema() {
List<Resource> scripts = this.getScripts("spring.datasource.schema", this.properties.getSchema(), "schema");
if (!scripts.isEmpty()) {
if (!this.isEnabled()) {
logger.debug("Initialization disabled (not running DDL scripts)");
return false;
}
String username = this.properties.getSchemaUsername();
String password = this.properties.getSchemaPassword();
this.runScripts(scripts, username, password);
}
return !scripts.isEmpty();
}
void initSchema() {
List<Resource> scripts = this.getScripts("spring.datasource.data", this.properties.getData(), "data");
if (!scripts.isEmpty()) {
if (!this.isEnabled()) {
logger.debug("Initialization disabled (not running data scripts)");
return;
}
String username = this.properties.getDataUsername();
String password = this.properties.getDataPassword();
this.runScripts(scripts, username, password);
}
}
- 他们均利用了
getScripts
方法 :
private List<Resource> getScripts(String propertyName, List<String> resources, String fallback) {
if (resources != null) {
return this.getResources(propertyName, resources, true);
} else {
String platform = this.properties.getPlatform();
List<String> fallbackResources = new ArrayList();
fallbackResources.add("classpath*:" + fallback + "-" + platform + ".sql");
fallbackResources.add("classpath*:" + fallback + ".sql");
return this.getResources(propertyName, fallbackResources, false);
}
}
- 而从该方法可以看出可以看出,如果我们没有在配置文件中配置脚本的具体位置,就会在classpath下找.sql文件。
- 在
initschema()
与createSchema()
中可以看出:- 创建SQL使用的是:
scheam.sql
或schema-all.sql
- 初始化数据使用的是:
data.sql
或data-all.sql
- 创建SQL使用的是:
- 我们也可以在配置文件中自己指定位置:
spring:
datasource:
schema:
- classpath:department.sql
- 指定位置
2、整合Druid数据源
2.1 数据库连接池的选择
选择哪个数据库连接池
- DBCP2 是 Appache 基金会下的项目,是最早出现的数据库连接池 DBCP 的第二个版本。
- C3P0 最早出现时是作为 Hibernate 框架的默认数据库连接池而进入市场。
- Druid 是阿里巴巴公司开源的一款数据库连接池,其特点在于有丰富的附加功能。
- HikariCP 相较而言比较新,它最近两年才出现,据称是速度最快的数据库连接池。最近更是被 Spring 设置为默认数据库连接池。
不选择 C3P0 的原因:
- C3P0 的 Connection 是异步释放。这个特性会导致释放的在某些情况下 Connection 实际上 still in use ,并未真正释放掉,从而导致连接池中的 Connection 耗完,等待状况。
- Hibernate 现在对所有数据库连接池一视同仁,官方不再指定『默认』数据库连接池。因此 C3P0 就失去了『官方』光环。
不选择 DBCP2 的原因:
- 相较于 Druid 和 HikariCP,DBCP2 没有什么特色功能/卖点。基本上属于
能用,没毛病
的情况,地位显得略有尴尬。引用自:https://cloudlandboy.github.io/myNote/#/backend/springboot/jdbc
2.2 整合Druid
- 首先导入Druid依赖:
<!-- https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.22</version>
</dependency>
-
在配置文件中指定数据源类型:
spring: datasource: username: root password: root url: jdbc:mysql://192.168.0.103:3306/jdbc driver-class-name: com.mysql.cj.jdbc.Driver initialization-mode: always type: com.alibaba.druid.pool.DruidDataSource
-
运行之前的测试类,查看数据源的类型。
-
配置参数,Druid的配置参数有两种方式,一种为编写代码,另一种为配置方式,接下来分别举例
- 编写代码:
@Configuration public class MyConfig { @ConfigurationProperties(prefix = "spring.datasource") @Bean public DataSource dataSource(){ return new DruidDataSource(); } @Bean public ServletRegistrationBean statViewServlet(){ ServletRegistrationBean<StatViewServlet> regist = new ServletRegistrationBean<StatViewServlet>(new StatViewServlet(), "/druid/*"); Map<String,String> initMap = new HashMap<>(); initMap.put("loginUsername","admin"); initMap.put("loginPassword","admin"); regist.setInitParameters(initMap); return regist; } @Bean public FilterRegistrationBean webStatFilter(){ FilterRegistrationBean bean = new FilterRegistrationBean(); bean.setFilter(new WebStatFilter()); Map<String,String> initMap = new HashMap<>(); initMap.put("exclusions","*.js,*.css,/druid/*"); bean.setInitParameters(initMap); bean.setUrlPatterns(Arrays.asList("/*")); return bean; } }
- 编写配置文件
spring: datasource: username: root password: root url: jdbc:mysql://192.168.0.103:3306/jdbc driver-class-name: com.mysql.cj.jdbc.Driver initialization-mode: always type: com.alibaba.druid.pool.DruidDataSource druid: # 连接池配置 # 配置初始化大小、最小、最大 initial-size: 1 min-idle: 1 max-active: 20 # 配置获取连接等待超时的时间 max-wait: 3000 validation-query: SELECT 1 FROM DUAL test-on-borrow: false test-on-return: false test-while-idle: true pool-prepared-statements: true time-between-eviction-runs-millis: 60000 min-evictable-idle-time-millis: 300000 filters: stat,wall,slf4j # 配置web监控,默认配置也和下面相同(除用户名密码,enabled默认false外),其他可以不配 web-stat-filter: enabled: true url-pattern: /* exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*" stat-view-servlet: enabled: true url-pattern: /druid/* login-username: admin login-password: root allow: 127.0.0.1
3、整合MyBatis
3.1 环境搭建
- 引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.22</version>
</dependency>
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
-
在resources下创建
department.sql
和employee.sql
,项目启动时创建表DROP TABLE IF EXISTS `department`; CREATE TABLE `department` ( `id` int(11) NOT NULL AUTO_INCREMENT, `departmentName` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `employee`; CREATE TABLE `employee` ( `id` int(11) NOT NULL AUTO_INCREMENT, `lastName` varchar(255) DEFAULT NULL, `email` varchar(255) DEFAULT NULL, `gender` int(2) DEFAULT NULL, `d_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-
创建实体类
-
编辑配置文件
spring:
datasource:
username: root
password: root
url: jdbc:mysql://192.168.0.103:3306/jdbc
driver-class-name: com.mysql.cj.jdbc.Driver
initialization-mode: always
type: com.alibaba.druid.pool.DruidDataSource
druid:
# 连接池配置
# 配置初始化大小、最小、最大
initial-size: 1
min-idle: 1
max-active: 20
# 配置获取连接等待超时的时间
max-wait: 3000
validation-query: SELECT 1 FROM DUAL
test-on-borrow: false
test-on-return: false
test-while-idle: true
pool-prepared-statements: true
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
filters: stat,wall,slf4j
# 配置web监控,默认配置也和下面相同(除用户名密码,enabled默认false外),其他可以不配
web-stat-filter:
enabled: true
url-pattern: /*
exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
stat-view-servlet:
enabled: true
url-pattern: /druid/*
login-username: admin
login-password: root
allow: 127.0.0.1
schema:
- classpath:department.sql
- classpath:employee.sql
-
Mybatis环境整合有两种方式,接下来分别介绍:
- xml方式:
-
创建mybatis全局配置文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <typeAliases> <package name="cn.clboy.springbootmybatis.model"/> </typeAliases> </configuration>
-
创建EmployeeMapper接口
public interface EmployeeMapper { List<Employee> selectAll(); int save(Employee employee); }
-
创建EmployeeMapper.xml映射文件
<?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="cn.clboy.springbootmybatis.mapper.EmployeeMapper"> <select id="selectAll" resultType="employee"> SELECT * FROM employee </select> <insert id="save" parameterType="employee" useGeneratedKeys="true" keyProperty="id"> INSERT INTO employee(lastName,email,gender,d_id) VALUES (#{lastName},#{email},#{gender},#{d_id}) </insert> </mapper>
-
配置文件(application.yaml)中指定配置文件和映射文件的位置
mybatis: config-location: classpath:mybatis/mybatis-config.xml mapper-locations: classpath:mybatis/mapper/*.xmlCopy to clipboardErrorCopied
-
给表中插入两个数据,用于测试
INSERT INTO employee(lastName,email,gender,d_id) VALUES ('张三','123456@qq.com',1,1); INSERT INTO employee(lastName,email,gender,d_id) VALUES ('lisi','245612@qq.com',1,1);
-
创建EmployeeController
@RestController public class EmployeeController { @Autowired private EmployeeMapper employeeMapper; @RequestMapping("/empl/list") public List<Employee> getALl() { return employeeMapper.selectAll(); } @RequestMapping("/empl/{id}") public Employee save(Employee employee) { employeeMapper.save(employee); return employee; } }
- 注解方式
1.创建
DepartmentMapper
类@Mapper public interface DepartmentMapper { @Select("select * from department") public List<Department> selectAll(); @Select("select * from department where id = #{id}") public Department selectDepartment(Integer id); @Delete("delete from department where id = #{id}") public Integer deleteDepartment(Integer id); @Options(useGeneratedKeys = true,keyProperty = "id") @Insert("insert into department(department_name) values(#{departmentName})") public Integer insertDepartment(Department department); @Update("update department set department_name=#{departmentName} where id=#{id}") public Integer updateDepartment(Department department); }
2.编写
DeptController
类:@RestController public class DeptController { @Autowired private DepartmentMapper dept; @GetMapping("/dept/all") public List<Department> selectAllDept(){ return dept.selectAll(); } @GetMapping("/dept/{id}") public Department select(@PathVariable("id") Integer id){ return dept.selectDepartment(id); } @GetMapping("/dept") public Department insert(Department department){ dept.insertDepartment(department); return department; } }
3.2 mybatis的配置
- 开启驼峰命名法
我们的实体类和表中的列名一致,一点问题也没有,我们把department表的departmentName列名改为department_name看看会发生什么,访问:http://localhost:8080/dep/1获取数据
[{"id":1,"departmentName":null}]Copy to clipboardErrorCopied
由于列表和属性名不一致,所以就没有封装进去,我们表中的列名和实体类属性名都是遵循驼峰命名规则的,可以开启mybatis的开启驼峰命名配置
mybatis:
configuration:
map-underscore-to-camel-case: true
然后重启项目,重新插入数据,再查询就发现可以封装进去了,也可以通过向spring容器中注入org.mybatis.spring.boot.autoconfigure.ConfigurationCustomizer
的方法设置mybatis参数
@Configuration
public class MybatisConfig {
@Bean
public ConfigurationCustomizer mybatisConfigurationCustomizer() {
return new ConfigurationCustomizer() {
@Override
public void customize(org.apache.ibatis.session.Configuration configuration) {
configuration.setMapUnderscoreToCamelCase(true);
}
};
}
}
- Mapper扫描
使用@mapper注解
的类可以被扫描到容器中,但是每个Mapper都要加上这个注解就是一个繁琐的工作,能不能直接扫描某个包下的所有Mapper接口呢,当然可以,在springboot启动类上加上@MapperScan
@MapperScan("cn.clboy.springbootmybatis.mapper")
@SpringBootApplication
public class SpringbootMybatisApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootMybatisApplication.class, args);
}
}
4、整合SpringData JPA
4.1 简介
4.2 整合SpringData JPA
- 导入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
- 编写一个实体类(bean)和数据表进行映射,并且配置好映射关系;
//使用JPA注解配置映射关系
@Entity //告诉JPA这是一个实体类(和数据表映射的类)
@Table(name = "tbl_user") //@Table来指定和哪个数据表对应;如果省略默认表名就是user;
public class User {
@Id //这是一个主键
@GeneratedValue(strategy = GenerationType.IDENTITY)//自增主键
private Integer id;
@Column(name = "last_name",length = 50) //这是和数据表对应的一个列
private String lastName;
@Column //省略默认列名就是属性名
private String email;
- 编写一个Dao接口来操作实体类对应的数据表(Repository)
//继承JpaRepository来完成对数据库的操作
public interface UserRepository extends JpaRepository<User,Integer> {
}
- 基本的配置JpaProperties
spring:
jpa:
hibernate:
# 更新或者创建数据表结构
ddl-auto: update
# 控制台显示SQL
show-sql: true