前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一文读懂SpringBoot持久层开发原理

一文读懂SpringBoot持久层开发原理

作者头像
石的三次方
发布2021-01-05 22:35:21
8760
发布2021-01-05 22:35:21
举报
文章被收录于专栏:石的三次方石的三次方

SpingBoot持久层开发原理

1. JDBC

“SpringBoot关于数据库的配置都存在于org.springframework.boot.autoconfigure.jdbc

  • 关于数据库的相关配置存放于DataSourceProperties
代码语言:javascript
复制
@ConfigurationProperties(
    prefix = "spring.datasource"
)
public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {
    private String name;
    private String driverClassName;
    private String url;
    private String username;
    private String password;
    private List<String> schema;
    private String schemaUsername;
    private String schemaPassword;
    private List<String> data;
    private String dataUsername;
    private String dataPassword;
  • 在实际使用的时候可以通过spring.datasource修改内部的属性
代码语言:javascript
复制
spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://192.168.1.113:3308/jdbc
    driver-class-name: com.mysql.jdbc.Driver
  • SpringBoot通过DataSourceConfiguration创建数据源,默认使用Hikari连接池。可以通过spring.datasource.type指定使用的数据源类型
    • 支持以下这四种数据源
代码语言:javascript
复制
通过spring.datasource.dbcp2
    spring.datasource.hikari
    spring.datasource.tomcat
    	来修改springboot提供的数据源的配置

2. 数据源自动配置原理

  • 自动配置通过DataSourceAutoConfigration来完成对数据源的自动配置
  • 通过内部类PooledDataSourceConfiguration类来实现自动配置
    • 导入了各个数据源。Hikari.classTomcat.class……
    • 每一个数据源刚好对应于DataSourceConfiguration类中的数据源对象
代码语言:javascript
复制
@Configuration(
        proxyBeanMethods = false
    )
    @Conditional({DataSourceAutoConfiguration.PooledDataSourceCondition.class})
    @ConditionalOnMissingBean({DataSource.class, XADataSource.class})
    @Import({Hikari.class, Tomcat.class, Dbcp2.class, Generic.class, DataSourceJmxConfiguration.class})
    protected static class PooledDataSourceConfiguration {
        protected PooledDataSourceConfiguration() {
        }
    }
代码语言:javascript
复制
 static class Hikari {
        Hikari() {
        }

        @Bean
        @ConfigurationProperties(
            prefix = "spring.datasource.hikari"
        )
        HikariDataSource dataSource(DataSourceProperties properties) {
            HikariDataSource dataSource = (HikariDataSource)DataSourceConfiguration.createDataSource(properties, HikariDataSource.class);
            if (StringUtils.hasText(properties.getName())) {
                dataSource.setPoolName(properties.getName());
            }

            return dataSource;
        }
    }

3. 创建表

  • SpringBoot支持直接运行建表语句和插入数据的SQL。通过DataSourceInitializer类的完成
    • 通过runSchemaScripts()运行建表语句
    • 通过runDataScripts()运行插入数据的SQL语句
  • 默认可以通过在资源文件下添加SQL语句在服务器启动之时,运行建表语句和插入数据的语句
代码语言:javascript
复制
spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://192.168.1.113:3308/jdbc
    driver-class-name: com.mysql.cj.jdbc.Driver
    initialization-mode: always //springBoot2.0以上需要添加
    schema:
        - classpath:employee.sql
        - classpath:department.sql
  • SpringBoot默认配置了JdbcTemplate
代码语言:javascript
复制
 class JdbcTemplateConfiguration {	
	@Bean
    @Primary
    JdbcTemplate jdbcTemplate(DataSource dataSource, JdbcProperties properties) {
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        Template template = properties.getTemplate();
        jdbcTemplate.setFetchSize(template.getFetchSize());
        jdbcTemplate.setMaxRows(template.getMaxRows());
        if (template.getQueryTimeout() != null) {
            jdbcTemplate.setQueryTimeout((int)template.getQueryTimeout().getSeconds());
        }

        return jdbcTemplate;
    }

4. 整合Druid

代码语言:javascript
复制
		<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.21</version>
        </dependency>
  • 通过spring.datasource.typedruid。并且配置druid连接源的参数
代码语言:javascript
复制
spring:
	datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        #  数据源其他配置
        initialSize: 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,slf4j
        maxPoolPreparedStatementPerConnectionSize: 20
        useGlobalDataSourceStat: true
        connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
  • Druid常用配置

配置

缺省值

说明

name

配置这个属性的意义在于,如果存在多个数据源,监控的时候可以通过名字来区分开来。 如果没有配置,将会生成一个名字,格式是:"DataSource-" + System.identityHashCode(this)

initialSize

0

初始化建立物理连接的个数,发生在init方法或者getConnection

maxActive

8

最大连接池的数量

maxIdle

8

已经废弃

maxWait

连接最大等待时间

poolPreparedStatements

false

是否缓存prepaerdStatement,也就是PSCache。游标使用

testOnBorrow

true

申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。

testOnReturn

false

归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能

testWhileIdle

false

建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。

validationQuery

用来检测连接是否有效的sql,要求是一个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会其作用。

maxOpenPreparedStatements

-1

要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100

timeBetweenEvictionRunsMillis

有两个含义:1) Destroy线程会检测连接的间隔时间2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明

4.1 SpringBoot中使用Druid

“SpringBoot默认不支持Druid所以需要将数据源添加到容器中

  • 将DruidDataSource数据源添加到容器中,并且导入yml中的相关配置
代码语言:javascript
复制
//导入配置文件中的druid数据库的相关配置
    @ConfigurationProperties(prefix = "spring.datasource")
    @Bean
    public DataSource druid(){
        return new DruidDataSource();
    }
4.2 SpringBoot使用Druid提供的数据库监控系统
  • 创建访问该系统的Servlet。Druid提供了StatViewServlet作为该系统的Servlet。通过Springboot提供的自定义Servlet创建
代码语言:javascript
复制
 @Bean
    public ServletRegistrationBean statViewServlet(){
        ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(),"/druid/*");
        Map<String,String> initParams = new HashMap<>();
        initParams.put("loginUsername","admin");
        initParams.put("loginPassword","123456");
        initParams.put("allow","");//允许谁访问,默认是所有的用户
//        initParams.put("deny","192.168");//不允许谁访问
        bean.setInitParameters(initParams);
        return bean ;
    }
  • 添加一个过滤器作为监控器
代码语言:javascript
复制
@Bean
    public FilterRegistrationBean webStatFilter(){
        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 ;
    }
4.3 测试
  • 访问一个JDBC请求
  • 访问Druid管理后台,里面显示了执行的SQL语句

5. 整合Mybatis

代码语言:javascript
复制
		<dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.1</version>
        </dependency>
5.1 基于注解
  • 通过@Mapper注解声明属于mybatis
代码语言:javascript
复制
@Mapper
@Repository("departmentMapper")
public interface IDepartmentMapper {

    @Select("select * from department")
    List<Department> findAll();

    @Select("select * from department where id = #{id}")
    Department findDepartById(Integer id );

    @Options(useGeneratedKeys = true , keyColumn = "id" )
    @Insert("insert into department(departmentName) values(#{departmentName})")
    int insertDepart(Department department);

    @Delete("delete from department where id = #{id}")
    int deleteDepart(Integer id);

    @Update("update department set departmentName = #{departmentName} where id = #{id}")
    int updateDepart(Department department);

}
  • 自定义MyBatis的配置规则;通过ConfigurationCustomizer来修改
代码语言:javascript
复制
@Configuration
public class MyBatisConfigurer {

    @Bean
    public ConfigurationCustomizer configurationCustomizer(){
        return configuration->configuration.setMapUnderscoreToCamelCase(true);//设置驼峰命名
    }
}
  • @MapperScan指定需要扫描哪几个包,添加以后将相当于给包中的类添加了@Mapper
代码语言:javascript
复制
public @interface MapperScan {
    String[] value() default {};

    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};
  • 在运行的时候可会出现这样的警告。出现的原因是由于JDK版本太高了,需要1.8或者以下
5.2 基于配置文件
  • 在资源文件下书写主配置文件
代码语言:javascript
复制
<?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"/>
        开启自动驼峰命名规则(camel case)映射
    </settings>
</configuration>
  • 书写接口映射文件
代码语言:javascript
复制
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bywlstudio.springboot02.mapper.IDepartmentMapperXml">
    <select id="findAll" resultType="com.bywlstudio.springboot02.bean.Department">
        select * from department ;
    </select>
    <insert id="insertDepart" parameterType="com.bywlstudio.springboot02.bean.Department" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
        insert into department(departmentName) values(#{departmentName})
    </insert>
</mapper>
  • yml配置文件中配置
代码语言:javascript
复制
mybatis:
  config-location: classpath:mapper/mapper.xml # 配置主配置文件
  mapper-locations: classpath:mapper/deparment/DepartmentMapperXml.xml # 配置映射文件
  • 项目结构
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-03-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 石的三次方 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • SpingBoot持久层开发原理
    • 1. JDBC
      • 2. 数据源自动配置原理
        • 3. 创建表
          • 4. 整合Druid
            • 4.1 SpringBoot中使用Druid
            • 4.2 SpringBoot使用Druid提供的数据库监控系统
            • 4.3 测试
          • 5. 整合Mybatis
            • 5.1 基于注解
            • 5.2 基于配置文件
        相关产品与服务
        容器服务
        腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档