1 简介
- 对于数据访问层,无论是SQL还是NOSQL,SpringBoot默认采用整合SpringData的方式进行统一处理,添加大量自动配置,屏蔽了很多细节设置。引入了各种xxxTemplate,xxxRepository来简化我们对数据访问层的操作。
2 整合基本JDBC和数据源
2.1 JDBC
2.1.1 导入依赖的jar包
<!-- SpringBoot的web模块 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- SpringBoot的web模块 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
2.1.2 application.yml配置
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
url: jdbc:mysql://47.103.20.129:3306/jdbc
2.1.3 测试
package com.sunxiaping.restful;
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.test.context.junit4.SpringRunner;
import javax.sql.DataSource;
import java.sql.SQLException;
@RunWith(SpringRunner.class)
@SpringBootTest
public class RestfulApplicationTest {
@Autowired
private DataSource dataSource;
@Test
public void test() throws SQLException {
System.out.println(dataSource.getClass()); //org.apache.tomcat.jdbc.pool.DataSource
System.out.println(dataSource.getConnection());
}
}
- 效果:
- 默认是用org.apache.tomcat.jdbc.pool.DataSource作为数据源的。
- 数据源的相关配置都是在DataSourceProperties里面。
- 自动配置原理:
- ①参考DataSourceConfiguration,根据配置创建数据源,默认使用的是Tomcat的连接池,当然可以使用spring.datasource.type指定自定义的数据源类型。其源码如下:
package org.springframework.boot.autoconfigure.jdbc;
abstract class DataSourceConfiguration {
/**
* Tomcat Pool DataSource configuration.
*/
@ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.tomcat.jdbc.pool.DataSource", matchIfMissing = true)
static class Tomcat extends DataSourceConfiguration {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.tomcat")
public org.apache.tomcat.jdbc.pool.DataSource dataSource(
DataSourceProperties properties) {
org.apache.tomcat.jdbc.pool.DataSource dataSource = createDataSource(
properties, org.apache.tomcat.jdbc.pool.DataSource.class);
DatabaseDriver databaseDriver = DatabaseDriver
.fromJdbcUrl(properties.determineUrl());
String validationQuery = databaseDriver.getValidationQuery();
if (validationQuery != null) {
dataSource.setTestOnBorrow(true);
dataSource.setValidationQuery(validationQuery);
}
return dataSource;
}
}
}
org.apache.tomcat.jdbc.pool.DataSource、HikariDataSource、org.apache.commons.dbcp.BasicDataSource
package org.springframework.boot.autoconfigure.jdbc;
abstract class DataSourceConfiguration {
/**
* Generic DataSource configuration.
*/
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type")
static class Generic {
@Bean
public DataSource dataSource(DataSourceProperties properties) {
//使用DataSourceProperties创建数据源,利用反射创建相应type类型的数据源,并绑定相关属性
return properties.initializeDataSourceBuilder().build();
}
}
}
- ④在DataSourceAutoConfiguration注册了DataSourceInitializer这个组件,其源码如下:
package org.springframework.boot.autoconfigure.jdbc;
@Configuration
@ConditionalOnClass({DataSource.class, EmbeddedDatabaseType.class})
@EnableConfigurationProperties({DataSourceProperties.class})
@Import({Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class})
public class DataSourceAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public DataSourceInitializer dataSourceInitializer(DataSourceProperties properties, ApplicationContext applicationContext) {
return new DataSourceInitializer(properties, applicationContext);
}
}
- 而DataSourceInitializer的源码如下:
package org.springframework.boot.autoconfigure.jdbc;
/**
* Bean to handle {@link DataSource} initialization by running {@literal schema-*.sql} on
* {@link PostConstruct} and {@literal data-*.sql} SQL scripts on a
* {@link DataSourceInitializedEvent}.
*
* @author Dave Syer
* @author Phillip Webb
* @author Eddú Meléndez
* @author Stephane Nicoll
* @author Kazuki Shimizu
* @since 1.1.0
* @see DataSourceAutoConfiguration
*/
class DataSourceInitializer implements ApplicationListener<DataSourceInitializedEvent> {
}
- 从中我们可以知道DataSourceInitializer就是ApplicationListener,其作用:
- 1. runSchemaScripts();运行建表语句。
- 2. runDataScripts();运行插入数据语句。
schema‐*.sql、data‐*.sql
默认规则:schema.sql,schema‐all.sql;
spring:
datasource:
# 建表语句
schema:
- classpath:employee.sql
- classpath:department.sql
# 插入数据语句
data:
- classpath:schema-employee-data.sql
- ⑤SpringBoot默认自动配置了JdbcTemplate来操作数据库。
package org.springframework.boot.autoconfigure.jdbc;
@Configuration
@ConditionalOnClass({DataSource.class, JdbcTemplate.class})
@ConditionalOnSingleCandidate(DataSource.class)
@AutoConfigureAfter({DataSourceAutoConfiguration.class})
public class JdbcTemplateAutoConfiguration {
private final DataSource dataSource;
public JdbcTemplateAutoConfiguration(DataSource dataSource) {
this.dataSource = dataSource;
}
@Bean
@Primary
@ConditionalOnMissingBean({JdbcOperations.class})
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(this.dataSource);
}
@Bean
@Primary
@ConditionalOnMissingBean({NamedParameterJdbcOperations.class})
public NamedParameterJdbcTemplate namedParameterJdbcTemplate() {
return new NamedParameterJdbcTemplate(this.dataSource);
}
}
2.2 整合Druid数据源
2.2.1 导入依赖的jar包
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
2.2.2 配置application.yml
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
url: jdbc:mysql://47.103.20.129:3306/jdbc?characterEncoding=utf-8&useSSL=false
#指定Druid数据源
type: com.alibaba.druid.pool.DruidDataSource
# 数据源其他配置
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall,log4j
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
2.2.3 DruidConfig.java
package com.sunxiaping.restful.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class DruidConfig {
@ConfigurationProperties(prefix = "spring.dataSource")
@Bean
public DataSource dataSource(){
return new DruidDataSource();
}
//配置Druid的监控
//1.配置一个管理后台的Servlet
@Bean
public ServletRegistrationBean servletRegistrationBean(){
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(),"/druid/*");
Map<String,String> map = new HashMap<>();
map.put("loginUsername", "admin");
map.put("loginPassword", "123456");
map.put("allow", "");//默认就是允许所有访问
// map.put("deny", "192.168.15.21"); 拒绝谁访问
servletRegistrationBean.setInitParameters(map);
return servletRegistrationBean;
}
//2.配置一个监控的filter
@Bean
public FilterRegistrationBean filterRegistrationBean(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new WebStatFilter());
Map<String,String> initParams = new HashMap<>();
initParams.put("exclusions","*.js,*.css,/druid/*");
filterRegistrationBean.setInitParameters(initParams);
filterRegistrationBean.setUrlPatterns(Arrays.asList("/*"));
return filterRegistrationBean;
}
}
3 SpringBoot整合Mybatis
3.1 基础环境搭建
<!-- SpringBoot的web模块 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
url: jdbc:mysql://47.103.20.129:3306/jdbc?characterEncoding=utf-8&useSSL=false
#指定Druid数据源
type: com.alibaba.druid.pool.DruidDataSource
# 数据源其他配置
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall,log4j
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
View Code
package com.sunxiaping.restful.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class DruidConfig {
@ConfigurationProperties(prefix = "spring.dataSource")
@Bean
public DataSource dataSource(){
return new DruidDataSource();
}
//配置Druid的监控
//1.配置一个管理后台的Servlet
@Bean
public ServletRegistrationBean servletRegistrationBean(){
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(),"/druid/*");
Map<String,String> map = new HashMap<>();
map.put("loginUsername", "admin");
map.put("loginPassword", "123456");
map.put("allow", "");//默认就是允许所有访问
// map.put("deny", "192.168.15.21"); 拒绝谁访问
servletRegistrationBean.setInitParameters(map);
return servletRegistrationBean;
}
//2.配置一个监控的filter
@Bean
public FilterRegistrationBean filterRegistrationBean(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new WebStatFilter());
Map<String,String> initParams = new HashMap<>();
initParams.put("exclusions","*.js,*.css,/druid/*");
filterRegistrationBean.setInitParameters(initParams);
filterRegistrationBean.setUrlPatterns(Arrays.asList("/*"));
return filterRegistrationBean;
}
}
View Code
/*
Navicat MySQL Data Transfer
Source Server : 本地
Source Server Version : 50528
Source Host : 127.0.0.1:3306
Source Database : restful_crud
Target Server Type : MYSQL
Target Server Version : 50528
File Encoding : 65001
Date: 2018-03-05 10:41:40
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for department
-- ----------------------------
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;
View Code
/*
Navicat MySQL Data Transfer
Source Server : 本地
Source Server Version : 50528
Source Host : 127.0.0.1:3306
Source Database : restful_crud
Target Server Type : MYSQL
Target Server Version : 50528
File Encoding : 65001
Date: 2018-03-05 10:41:58
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for employee
-- ----------------------------
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;
View Code
- 创建JavaBean:
- Employee.java
package com.sunxiaping.restful.bean;
public class Employee {
private Integer id;
private String lastName;
private Integer gender;
private String email;
private Integer dId;
public void setId(Integer id) {
this.id = id;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public void setGender(Integer gender) {
this.gender = gender;
}
public void setEmail(String email) {
this.email = email;
}
public void setdId(Integer dId) {
this.dId = dId;
}
public Integer getId() {
return id;
}
public String getLastName() {
return lastName;
}
public Integer getGender() {
return gender;
}
public String getEmail() {
return email;
}
public Integer getdId() {
return dId;
}
}
View Code
package com.sunxiaping.restful.bean;
public class Department {
private Integer id;
private String departmentName;
public void setId(Integer id) {
this.id = id;
}
public void setDepartmentName(String departmentName) {
this.departmentName = departmentName;
}
public Integer getId() {
return id;
}
public String getDepartmentName() {
return departmentName;
}
}
View Code
3.2 注解版
package com.sunxiaping.restful.mapper;
import com.sunxiaping.restful.entities.Department;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Select;
@Mapper //指定这是一个操作数据库的Mapper
public interface DepartmentMapper {
@Select("select * from department where id = #{id}")
Department getDeptById(Integer id);
@Options(useGeneratedKeys = true,keyProperty = "id")
@Insert("insert into department(departmentName) values (#{departmentName)")
int insertDept(Department department);
}
- 如果需要自定义Mybatis配置规则,则需要给容器中添加一个ConfigurationCustomizer的组件:
package com.sunxiaping.restful.config;
import org.mybatis.spring.boot.autoconfigure.ConfigurationCustomizer;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MybatisConfig {
public ConfigurationCustomizer configurationCustomizer(){
return new ConfigurationCustomizer() {
@Override
public void customize(org.apache.ibatis.session.Configuration configuration) {
//开启驼峰命名
configuration.setMapUnderscoreToCamelCase(true);
}
};
}
}
- 如果不想在Mapper接口上加@Mapper接口,那么可以在配置类上加上@MapperScan注解即可。
package com.sunxiaping.restful;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//使用@MapperScan批量扫描所有的Mapper接口
@MapperScan(value = "com.sunxiaping.restful.mapper")
@SpringBootApplication
public class RestfulApplication {
public static void main(String[] args) {
SpringApplication.run(RestfulApplication.class, args);
}
}
3.3 配置版
- 在classpath:下新建mybatis-config.xml和EmployeeMapper.xml文件:
- mybatis-config.xml
<?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>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
</configuration>
View Code
<?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.sunxiaping.restful.mapper.EmployeeMapper">
<!-- public Employee getEmpById(Integer id);
public void insertEmp(Employee employee);-->
<select id="getEmpById" resultType="com.sunxiaping.restful.bean.Employee">
SELECT * FROM employee WHERE id=#{id}
</select>
</mapper>
View Code
mybatis:
#指定全局配置文件的位置
config-location: classpath:com/sunxiaping/restful/mybatis-config.xml
#指定SQL映射问加你的位置
mapper-locations: classpath:com/sunxiaping/restful/mapper/*.xml
4 SpringBoot整合SpringData JPA
4.1 基础环境搭建
<!-- SpringBoot的web模块 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
View Code
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
url: jdbc:mysql://47.103.20.129:3306/jdbc?characterEncoding=utf-8&useSSL=false
#指定Druid数据源
type: com.alibaba.druid.pool.DruidDataSource
# 数据源其他配置
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall,log4j
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
# jpa
jpa:
hibernate:
# ddl
ddl-auto: update
# 显示sql
show-sql: true
View Code
package com.sunxiaping.restful.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class DruidConfig {
@ConfigurationProperties(prefix = "spring.dataSource")
@Bean
public DataSource dataSource(){
return new DruidDataSource();
}
//配置Druid的监控
//1.配置一个管理后台的Servlet
@Bean
public ServletRegistrationBean servletRegistrationBean(){
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(),"/druid/*");
Map<String,String> map = new HashMap<>();
map.put("loginUsername", "admin");
map.put("loginPassword", "123456");
map.put("allow", "");//默认就是允许所有访问
// map.put("deny", "192.168.15.21"); 拒绝谁访问
servletRegistrationBean.setInitParameters(map);
return servletRegistrationBean;
}
//2.配置一个监控的filter
@Bean
public FilterRegistrationBean filterRegistrationBean(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new WebStatFilter());
Map<String,String> initParams = new HashMap<>();
initParams.put("exclusions","*.js,*.css,/druid/*");
filterRegistrationBean.setInitParameters(initParams);
filterRegistrationBean.setUrlPatterns(Arrays.asList("/*"));
return filterRegistrationBean;
}
}
View Code
4.2 编写实体类和映射关系
package com.sunxiaping.restful.entity;
import javax.persistence.*;
import java.io.Serializable;
@Entity
@Table(name = "`user`")
public class User implements Serializable {
private Integer id;
private String lastName;
private String email;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name = "`last_name`")
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@Column(name = "`email`")
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
4.3 编写一个Dao接口来操作实体类对应的数据表
package com.sunxiaping.restful.repository;
import com.sunxiaping.restful.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Integer> {
}