zoukankan      html  css  js  c++  java
  • 第六章:(1)数据访问 之 JDBC

    一、简介

      对于数据访问层,无论是SQL还是NOSQL, Spring Boot默认采用整合Spring Data的方式进行统一处理,添加大量自动配置,屏蔽了很多设置。

      引入各种xxxTemplate, xxxRepository来简化我们对数据访问层的操作。对我们来说只需要进行简单的设置即可。我们将在数据访问章节测试使用SQL相关、NOSQL在缓存、消息、检索等章节测试。

      相关的 starter:

      

     

    二、整合JDBC

      1、添加依赖信息

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jdbc</artifactId>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.11</version>
                <scope>runtime</scope>
            </dependency>

      2、配置数据库信息

    spring:
      datasource:
        username: root
        password: '123456'
        driver-class-name: com.mysql.cj.jdbc.Driver
    #    driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://192.168.1.6:3306/jdbc

        如果没有更新驱动的,使用 com.mysql.jdbc.Driver。

        如果在 Maven 中更新了 mysql 驱动,使用 com.mysql.cj.jdbc.Driver 驱动。

      3、测试

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class SpringBoot06DataJdbcApplicationTests {
    
        @Autowired
        private DataSource dataSource;
    
        @Test
        public void contextLoads() throws SQLException {
            System.out.println(dataSource.getClass());
            Connection connection = dataSource.getConnection();
            System.out.println("connection = " + connection);
        }
    
    }

      4、效果

      (1)默认是用org.apache.tomcat.jdbc.pool.DataSource作为数据源;

      (2)数据源的相关配置都在DataSourceProperties里面;

    三、自动配置原理

      jdbc 自动配置相关类所在包:

    org.springframework.boot.autoconfigure.jdbc
    

      

      1、数据源的自动配置

        参考 DataSourceConfiguration,根据配置创建数据源,默认使用 Tomcat 连接池;

        可以使用 spring.datasource.type 指定自定义的数据源类型;

      2、SpringBoot 默认支持的数据源

    org.apache.tomcat.jdbc.pool.DataSource
    com.zaxxer.hikari.HikariDataSource
    org.apache.commons.dbcp.BasicDataSource
    org.apache.commons.dbcp2.BasicDataSource
    

      

      3、自定义数据源类型

    /**
     * Generic DataSource configuration.
     */
    @ConditionalOnMissingBean(DataSource.class)
    @ConditionalOnProperty(name = "spring.datasource.type")
    static class Generic {
    
        @Bean
        public DataSource dataSource(DataSourceProperties properties) {
            //使用DataSourceBuilder创建数据源,利用反射创建响应type的数据源,并且绑定相关属性
            return properties.initializeDataSourceBuilder().build();
        }
    
    }
    
    public DataSourceBuilder initializeDataSourceBuilder() {
        return DataSourceBuilder.create(getClassLoader()).type(getType())
                .driverClassName(determineDriverClassName()).url(determineUrl())
                .username(determineUsername()).password(determinePassword());
    }
    
    public DataSource build() {
        Class<? extends DataSource> type = getType();
        DataSource result = BeanUtils.instantiate(type);
        maybeGetDriverClassName();
        bind(result);
        return result;
    }
    
    private void bind(DataSource result) {
        MutablePropertyValues properties = new MutablePropertyValues(this.properties);
        new RelaxedDataBinder(result).withAlias("url", "jdbcUrl")
                .withAlias("username", "user").bind(properties);
    }

      

      4、DataSourceInitializer 

        在 DataSourceAutoConfiguration 类中会导入一个 DataSourceInitializer 组件:

        

         DataSourceInitializer 组件:

    /**
     * Bean to handle {@link DataSource} initialization by running {@literal schema-*.sql} on
     * {@link PostConstruct} and {@literal data-*.sql} SQL scripts on a
     * {@link DataSourceInitializedEvent}.
     * 通过在 {@link PostConstruct} 上运行 {@literal schema-.sql} 和在 {@link DataSourceInitializedEvent} 上运行 {@literal data-.sql} SQL 脚本来处理 {@link DataSource} 初始化的 Bean。
    */
    
    class DataSourceInitializer implements ApplicationListener<DataSourceInitializedEvent> {}

        作用:

        (1)runSchemaScripts():运行建表语句

        @PostConstruct
        public void init() {
            if (!this.properties.isInitialize()) {
                logger.debug("Initialization disabled (not running DDL scripts)");
                return;
            }
            if (this.applicationContext.getBeanNamesForType(DataSource.class, false,
                    false).length > 0) {
                this.dataSource = this.applicationContext.getBean(DataSource.class);
            }
            if (this.dataSource == null) {
                logger.debug("No DataSource found so not initializing");
                return;
            }
            runSchemaScripts();
        }
    
        private void runSchemaScripts() {
            List<Resource> scripts = getScripts("spring.datasource.schema",
                    this.properties.getSchema(), "schema");
            if (!scripts.isEmpty()) {
                String username = this.properties.getSchemaUsername();
                String password = this.properties.getSchemaPassword();
                runScripts(scripts, username, password);
                try {
                    this.applicationContext
                            .publishEvent(new DataSourceInitializedEvent(this.dataSource));
                    // The listener might not be registered yet, so don't rely on it.
                    if (!this.initialized) {
                        runDataScripts();
                        this.initialized = true;
                    }
                }
                catch (IllegalStateException ex) {
                    logger.warn("Could not send event to complete DataSource initialization ("
                            + ex.getMessage() + ")");
                }
            }
        }
        private List<Resource> getScripts(String propertyName, List<String> resources,
                String fallback) {
            if (resources != null) {
                return getResources(propertyName, resources, true);
            }
            String platform = this.properties.getPlatform();
            List<String> fallbackResources = new ArrayList<String>();
            fallbackResources.add("classpath*:" + fallback + "-" + platform + ".sql");
            fallbackResources.add("classpath*:" + fallback + ".sql");
            return getResources(propertyName, fallbackResources, false);
        }

        (2)runDataScripts():运行插入数据的 SQL 语句

        @Override
        public void onApplicationEvent(DataSourceInitializedEvent event) {
            if (!this.properties.isInitialize()) {
                logger.debug("Initialization disabled (not running data scripts)");
                return;
            }
            // NOTE the event can happen more than once and
            // the event datasource is not used here
            if (!this.initialized) {
                runDataScripts();
                this.initialized = true;
            }
        }
    
        private void runDataScripts() {
            List<Resource> scripts = getScripts("spring.datasource.data",
                    this.properties.getData(), "data");
            String username = this.properties.getDataUsername();
            String password = this.properties.getDataPassword();
            runScripts(scripts, username, password);
        }
        private List<Resource> getScripts(String propertyName, List<String> resources,
                String fallback) {
            if (resources != null) {
                return getResources(propertyName, resources, true);
            }
            String platform = this.properties.getPlatform();
            List<String> fallbackResources = new ArrayList<String>();
            fallbackResources.add("classpath*:" + fallback + "-" + platform + ".sql");
            fallbackResources.add("classpath*:" + fallback + ".sql");
            return getResources(propertyName, fallbackResources, false);
        }

        如果指定了 resources 资源路径,就加载,如果没有就加载 类路径下面的文件。

        默认只需要将文件命名为:

    schema-*.sql 、data-*.sql

    默认规则(类路径下面):schema.sql,schema-all.sql

    也可以在配置文件中指定位置

    spring:

      schema:

        - classpath:department.sql

      data:

        - classpath: abc.sql

        指定位置

    spring:
      datasource:
        username: root
        password: '123456'
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://192.168.1.6:3306/jdbc
        schema:
          - classpath:department.sql
        data:
          - classpath:abc.sql

      5、操作数据库:自动配置了 JdbcTemplate 操作数据库

        JdbcTemplateAutoConfiguration 类自动注入了 JdbcTemplate:

    @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);
        }
    
    }
  • 相关阅读:
    node.js+mysql接口入门
    input边写边验证?正则表达式写在属性里?小技巧
    创建vue,react项目
    jquery在网页中加载本地json文件
    OpenFeigin服务接口调用
    Ribbon负载均衡服务调用
    Consul服务注册与发现
    Eureka服务注册与发现
    springboot项目在idea实现热部署
    设计模式——单例模式
  • 原文地址:https://www.cnblogs.com/niujifei/p/15705250.html
Copyright © 2011-2022 走看看