Spring Boot核心技术系统学习总结(七)Spring Boot Data
SpringBoot_数据访问
JDBC&自动配置原理
整合Druid&配置数据源监控
整合MyBatis
整合JPA
一、SpringBoot_数据访问
1.JDBC默认配置
2.自动配置原理(源码分析)
1)DataSourceConfiguration类中 定义了默认支持的 Tomcat, Hikari, Dbcp, Dbcp2 数据源
2)DataSourceConfiguration类中,默认使用的Tomcat数据源(SpringBOOT v1.5.17)
/**
* Tomcat Pool DataSource configuration.
*/
@ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)
@ConditionalOnMissingBean(DataSource.class)
//matchIfMissing = true 即默认数据源=org.apache.tomcat.jdbc.pool.DataSource.class
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.tomcat.jdbc.pool.DataSource", matchIfMissing = true)
static class Tomcat {
@Bean
//spring.datasource.tomcat 开头的配置,可以优化数据源
@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;
}
}
3)绑定数据源配置
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type")
static class Generic {
@Bean
public DataSource dataSource(DataSourceProperties properties) {
return properties.initializeDataSourceBuilder().build();
}
}
4)自动配置项:
@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 实现了 ApplicationListener<DataSourceInitializedEvent>
// @PostConstruct
// public void init() 方法会调用:runSchemaScripts()、runDataScripts()方法,实现自动运行建表语句、插入数据语句
// fallbackResources.add("classpath*:data-all.sql"); 默认执行的省sql
// fallbackResources.add("classpath*:data.sql");
// 还可以通过配置在配置文件中添加制定的sql文件:
// schema:
// ‐ classpath:department.sql
}
}
二、整合Druid&配置数据源监控
1.引入Druid数据源
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.18</version>
</dependency>
application.yaml中的数据源配置(以下配置用于对DruidAbstractDataSource类中的属性进行绑定赋值):
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://localhost:33306/test
driver-class-name: com.mysql.jdbc.Driver
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
数据源配置类:
@Configuration
public class DruidConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource druid(){
return new DruidDataSource();
}
}
测试数据源:
@RunWith(SpringRunner.class)
@SpringBootTest
public class DatasourceApplicationTests {
@Autowired
DataSource dataSource;
@Test
public void contextLoads() {
//SpringBoot2默认使用的数据源:class com.zaxxer.hikari.HikariDataSource
//SpringBoot1.5.17:class org.apache.tomcat.jdbc.pool.DataSource
System.out.println(dataSource.getClass());
}
}
2.配置druid数据源监控
@Configuration
public class DruidConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource druid(){
return new DruidDataSource();
}
//配置Druid的监控
//1、配置一个管理后台的Servlet
@Bean
public ServletRegistrationBean statViewServlet(){
//访问到druid监控后台的url与处理请求的servlet注册
ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
Map<String,String> initParams = new HashMap<>();
//druid监控后台的参数设置:
// public abstract class ResourceServlet extends HttpServlet {
// private final static Log LOG = LogFactory.getLog(ResourceServlet.class);
//
// public static final String SESSION_USER_KEY = "druid-user";
// public static final String PARAM_NAME_USERNAME = "loginUsername";
// public static final String PARAM_NAME_PASSWORD = "loginPassword";
// public static final String PARAM_NAME_ALLOW = "allow";
// public static final String PARAM_NAME_DENY = "deny";
// public static final String PARAM_REMOTE_ADDR = "remoteAddress";
initParams.put("loginUsername","admin");
initParams.put("loginPassword","123456");
initParams.put("allow","");//默认就是允许所有访问
initParams.put("deny","192.168.248.121");
bean.setInitParameters(initParams);
return bean;
}
//2、配置一个web监控的filter
@Bean
public FilterRegistrationBean webStatFilter(){
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new WebStatFilter());
Map<String,String> initParams = new HashMap<>();
initParams.put("exclusions","*.js,*.css,/druid/*");
bean.setInitParameters(initParams);
bean.setUrlPatterns(Arrays.asList("/*"));
return bean;
}
}
测试效果:
三、整合MyBatis
1.引入mybatis依赖:
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
mybatis依赖树
2.建立实体类:
@Data
public class Department implements Serializable {
private Integer id;
private String name;
}
3.注解版的mybatis
可以添加mybatis的定制器,实现表字段下划线转驼峰形式
import org.apache.ibatis.session.Configuration;
import org.mybatis.spring.boot.autoconfigure.ConfigurationCustomizer;
import org.springframework.context.annotation.Bean;
@org.springframework.context.annotation.Configuration
public class MyBatisConfig {
@Bean //添加定制器,实现表字段下划线转驼峰形式
public ConfigurationCustomizer configurationCustomizer(){
return new ConfigurationCustomizer(){
@Override
public void customize(Configuration configuration) {
configuration.setMapUnderscoreToCamelCase(true);
}
};
}
}
|- 编写mapper,也可以在启动类上加@MapperScan(value = "mapper所在的包名"):
@Mapper
public interface DeptMapper {
@Select("select * from department t where t.id = #{id}")
Department selectDept(int id);
@Delete("delete from department where id = #{id}")
int deleteDept(@Param("id") int id);
@Update("update department t set t.department_name = #{name} where t.id = #{id}")
int updateDeptNameById(@Param("id") int id, @Param("name") String name);
//设置主键为id,自增
@Options(keyProperty = "id", useGeneratedKeys = true)
@Insert("insert into department (department_name) values (#{departmentName})")
int insertDept(Department department);
}
测试类:
@SpringBootTest
@RunWith(SpringRunner.class)
public class DeptMapperTest {
@Autowired
DeptMapper deptMapper;
@Test
public void selectDept() {
int id = 1;
Department department = deptMapper.selectDept(id);
Assert.assertEquals("AA", department.getDepartmentName());
}
@Test
public void deleteDept() {
int id = 1;
int i = deptMapper.deleteDept(id);
Assert.assertEquals(1, i);
}
@Test
public void updateDeptNameById() {
int id = 2;
String name = "beijing office";
int i = deptMapper.updateDeptNameById(id, name);
Assert.assertEquals(1, i);
}
@Test
public void insertDept() {
Department department = new Department();
department.setDepartmentName("BB");
deptMapper.insertDept(department);
}
}
4.xml版的mybatis
xml方式的mybatis配置文件目录:
|- mybatis全局配置文件: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>
<!-- mybatis的全局配置文件 -->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
</configuration>
|- DeptMapper配置文件:
<?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.datasource.mapper.DeptMapper">
<!-- public Employee getEmpById(Integer id);
public void insertEmp(Employee employee);-->
<select id="selectDept" resultType="com.datasource.entity.Department">
SELECT * FROM department WHERE id=#{id}
</select>
<insert id="insertDept" parameterType="com.datasource.entity.Department">
INSERT INTO department(department_name) VALUES (#{departmentName})
</insert>
</mapper>
|- Mapper类:
@Mapper
public interface DeptMapper {
//@Select("select * from department t where t.id = #{id}")
Department selectDept(int id);
//@Delete("delete from department where id = #{id}")
int deleteDept(@Param("id") int id);
//@Update("update department t set t.department_name = #{name} where t.id = #{id}")
int updateDeptNameById(@Param("id") int id, @Param("name") String name);
//设置主键为id,自增
//@Options(keyProperty = "id", useGeneratedKeys = true)
//@Insert("insert into department (department_name) values (#{departmentName})")
int insertDept(Department department);
}
|- 配置文件application.yaml新增:
mybatis:
config-location: classpath:mybatis/mybatis-config.xml
mapper-locations: classpath:mybatis/mapper/*.xml
测试类:同上
四、整合JPA
1.SpringData
SpringData为我们提供使用统一的API来对数据访问层进行操作;这主要是Spring Data Commons项目来实现的。Spring Data Commons让我们在使用关系型或者非关系型数据访问技术时都基于Spring提供的统一标准,标准包含了CRUD(创建、获取、更新、删除)、查询、排序和分页的相关操作。
2.统一的Repository接口Repository<T, ID extends Serializable>:
RevisionRepository<T, ID extends Serializable, N extends Number & Comparable<N>>:基于乐观锁机制
CrudRepository<T, ID extends Serializable>:基本CRUD操作
PagingAndSortingRepository<T, ID extends Serializable>:基本CRUD及分页
3、提供数据访问模板类 xxxTemplate;如:MongoTemplate、RedisTemplate等
4、JPA与Spring Data
1)、JpaRepository基本功能编写接口继承JpaRepository既有crud及分页等基本功能
2)、定义符合规范的方法命名,在接口中只需要声明符合规范的方法,即拥有对应的功能
3)、@Query自定义查询,定制查询SQL
4)、Specifications查询(Spring Data JPA支持JPA2.0的Criteria查询)
--- 整合JPA实践 ---
1、引入spring-boot-starter-data-jpa
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
2、配置文件打印SQL语句
spring:
jpa:
show-sql: true
hibernate:
ddl-auto: update
3、创建Entity标注JPA注解
@Entity
@Data
@Table(name = "t_users")
public class User implements Serializable {
@Id //标记主键
@GeneratedValue(strategy = GenerationType.IDENTITY) //设置主键自增
private Integer uid;
@Column(name = "user_name", length = 64) //关联的列名,字段长度
private String userName;
@Column
private Integer age;
}
4、创建Repository接口继承JpaRepository
// 创建repository,关联实体类与主键类型
public interface UserRepository extends JpaRepository<User, Integer> {
}
5、测试方法
@SpringBootTest
@RunWith(SpringRunner.class)
public class UserRepositoryTest {
@Autowired
UserRepository userRepository;
@Test
public void testInsert(){
User user = new User();
user.setUserName("小明");
user.setAge(15);
User savedUser = userRepository.save(user);
System.out.println(savedUser);
}
@Test
public void testSelect(){
int id = 1;
User user = userRepository.findOne(id);
System.out.println(user);
}
}