zoukankan      html  css  js  c++  java
  • SpringBoot

    一、JDBC是什么?

    JDBC API 属于Java APIJDBC用于以下几种功能:连接到数据库、执行SQL语句

    二、Spring Boot中如何使用JDBC

    2.1 创建 Spring Boot Project 时引入 JDBC API 依赖和 MySQL Driver依赖,以及Spring Web依赖(测试时用到)


    可以在POM中找到引入的JDBC依赖和mysql依赖:
    JDBC 依赖:

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    

    MySql 驱动依赖:

    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <scope>runtime</scope>
    </dependency>
    

    2.2 配置数据库连接

    新增配置文件:src/main/resources/application.yml

    spring:
      datasource:
        username: root
        password: root
        url: jdbc:mysql://localhost:3306/study-spring-boot?serverTimezone=UTC&useUnicode=true&zeroDateTimeBehavior=convertToNull&autoReconnect=true&characterEncoding=utf-8
        driverClassName: com.mysql.cj.jdbc.Driver
    

    注意:com.mysq.jdbc.Driver 被废弃了,需要使用com.mysql.cj.jdbc.Driver

    2.3 查看使用的数据源和数据库连接

    package com.jackson0714.springboot;
    
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    
    import javax.sql.DataSource;
    import java.sql.Connection;
    import java.sql.SQLException;
    
    
    @SpringBootTest
    class Springboot05DataJdbcApplicationTests {
    
    	@Autowired
    	DataSource dataSource; //自动配置数据源,使用yml配置
    
    	@Test
    	void contextLoads() throws SQLException {
    		System.out.println("数据源:" + dataSource.getClass());
    
    		Connection connection = dataSource.getConnection();
    		System.out.println("数据库连接:" + connection);
    		connection.close();
    	}
    
    }
    
    

    默认数据源:class com.zaxxer.hikari.HikariDataSource

    数据库连接:HikariProxyConnection@1335157064 wrapping com.mysql.cj.jdbc.ConnectionImpl@7ff8a9dc

    三、自动配置原理

    自动配置文件路径:org.springframework.boot.autoconfigure.jdbc

    DataSourceConfiguration用来自动导入数据源(根据各种判断)

    /**
    	 * Tomcat Pool DataSource configuration.
    	 */
    	@Configuration(proxyBeanMethods = false)
    	@ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)
    	@ConditionalOnMissingBean(DataSource.class)
    	@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.tomcat.jdbc.pool.DataSource",
    			matchIfMissing = true)
    	static class Tomcat {
    
    		@Bean
    		@ConfigurationProperties(prefix = "spring.datasource.tomcat")
    

    3.1 自动选择数据源

    如果导入了org.apache.tomcat.jdbc.pool.DataSource数据源,并且配置的spring.datasource.type配置的是org.apache.tomcat.jdbc.pool.DataSource,或没配置type也使用tomcat数据源

    3.2 HikariDataSource数据源也类似这样判断。

    3.3 默认使用tomcat数据源

    3.4 默认支持以下数据源

    org.apache.tomcat.jdbc.pool、HikariDataSource、org.apache.commons.dbcp2
    

    3.5 支持自定义数据源

    使用DataSourceBuilder创建数据源,利用反射创建响应type的数据源,并且绑定相关属性

    	/**
    	 * Generic DataSource configuration.
    	 */
    	@Configuration(proxyBeanMethods = false)
    	@ConditionalOnMissingBean(DataSource.class)
    	@ConditionalOnProperty(name = "spring.datasource.type")
    	static class Generic {
    
    		@Bean
    		DataSource dataSource(DataSourceProperties properties) {
              //使用DataSourceBuilder创建数据源,利用反射创建响应type的数据源,并且绑定相关属性
    			return properties.initializeDataSourceBuilder().build();
    		}
    
    	}
    

    3.6 DataSourceInitializerInvoker 运行脚本

    /**
     * Bean to handle {@link DataSource} initialization by running {@literal schema-*.sql} on
     * {@link InitializingBean#afterPropertiesSet()} and {@literal data-*.sql} SQL scripts on
     * a {@link DataSourceSchemaCreatedEvent}.
     *
     * @author Stephane Nicoll
     * @see DataSourceAutoConfiguration
     */
    class DataSourceInitializerInvoker implements ApplicationListener<DataSourceSchemaCreatedEvent>, InitializingBean {
    
    createSchema() 创建表 (文件名规则 schema-*.sql)
    initSchema() 执行数据脚本 (文件名规则 data-*.sql)
    

    getScripts() 来获取需要执行的脚本

    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<>();
      fallbackResources.add("classpath*:" + fallback + "-" + platform + ".sql");
      fallbackResources.add("classpath*:" + fallback + ".sql");
      return getResources(propertyName, fallbackResources, false);
    }
    
    1. fallback = "schema", platform="all",会自动执行根目录下:schema-all.sql 或schema.sql 文件

    2. fallback = "data", platform="all",会自动执行根目录下:data-all.sql 或data.sql 文件

    isEnabled() 方法判断是否开启了自动执行脚本

    有三种模式:NEVER,EMBEDDED(默认),Always

    疑问:用EMBEDDED模式返回false,开关关闭,不执行脚本,这是为啥呢?

    用Always模式则每次启动spring boot重复执行脚本(创建表脚本都是先判断有没有表,有则删除后重建)

    private boolean isEnabled() {
      DataSourceInitializationMode mode = this.properties.getInitializationMode();
      if (mode == DataSourceInitializationMode.NEVER) {
        return false;
      }
      if (mode == DataSourceInitializationMode.EMBEDDED && !isEmbedded()) {
        return false;
      }
      return true;
    }
    

    3.7 通过配置文件指定需要执行脚本

    schema:
      - classpath:department.sql
    

    创建出的 department

    四、JdbcTemplate

    JdbcTemplateAutoConfiguration.java 文件 自动注入了JdbcTemplate。(JdbcTemplate用来操作数据库)

    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass({ DataSource.class, JdbcTemplate.class })
    @ConditionalOnSingleCandidate(DataSource.class)
    @AutoConfigureAfter(DataSourceAutoConfiguration.class)
    @EnableConfigurationProperties(JdbcProperties.class)
    @Import({ JdbcTemplateConfiguration.class, NamedParameterJdbcTemplateConfiguration.class })
    public class JdbcTemplateAutoConfiguration {
    
    }
    

    我们用Swagger的方式来测试

    五、配置Swagger用来测试

    5.1 pom.xml文件 添加swagger依赖

    <!-- swagger -->
    <dependency>
      <groupId>io.springfox</groupId>
      <artifactId>springfox-swagger2</artifactId>
      <version>2.9.2</version>
    </dependency>
    <dependency>
      <groupId>io.springfox</groupId>
      <artifactId>springfox-swagger-ui</artifactId>
      <version>2.9.2</version>
    </dependency>
    

    5.2 添加SwaggerConfig.java文件

    package com.jackson0714.springboot.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import springfox.documentation.builders.ApiInfoBuilder;
    import springfox.documentation.builders.PathSelectors;
    import springfox.documentation.builders.RequestHandlerSelectors;
    import springfox.documentation.service.ApiInfo;
    import springfox.documentation.spi.DocumentationType;
    import springfox.documentation.spring.web.plugins.Docket;
    import springfox.documentation.swagger2.annotations.EnableSwagger2;
    
    @Configuration
    @EnableSwagger2
    public class SwaggerConfig {
    
        @Bean
        public Docket createRestApi(){
            return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
                    .select()
                    .apis(RequestHandlerSelectors.any())
                    .paths(PathSelectors.any()).build();
        }
    
        private ApiInfo apiInfo(){
            return new ApiInfoBuilder()
                    .title("玩转Spring Boot 接口文档")
                    .description("This is a restful api document of Spring Boot.")
                    .version("1.0")
                    .build();
        }
    
    }
    

    5.3 访问Swagger文档

    http://localhost:8081/swagger-ui.html

    六、测试

    6.1 新增部门

    @ApiOperation(value = "1.新增部门")
    @ApiImplicitParams({
      @ApiImplicitParam(name = "name", value = "部门名称")
    })
    @PostMapping("/create")
    public int createDepartment(@RequestParam String name) {
      String sql = String.format("insert into department(departmentName) value('%s')", name);
      int result = jdbcTemplate.update(sql);
      return result;
    }
    


    表记录

    6.2 查询所有部门

    @ApiOperation(value = "2.查询所有部门")
    @GetMapping("/getAllDepartment")
    public List<Map<String, Object>> getAllDepartment() {
      List<Map<String, Object>> list = jdbcTemplate.queryForList("select * from department");
      return list;
    }
    

    6.3 根据id查询某个部门

    @ApiOperation(value = "3.根据id查询某个部门")
    @ApiImplicitParams({
      @ApiImplicitParam(name = "id", value = "需要查询的部门id")
    })
    @GetMapping("/{id}")
    public Map<String, Object> getDepartmentById(@PathVariable Long id) {
      String sql = "select * from department where id = " + id;
      List<Map<String, Object>> list = jdbcTemplate.queryForList(sql);
      return list.get(0);
    }
    

    6.4 根据id更新部门名称

    @ApiOperation(value = "根据id更新部门名称")
    @ApiImplicitParams({
      @ApiImplicitParam(name = "id", value = "需要更新的部门id"),
      @ApiImplicitParam(name = "name", value = "需要更新的部门名称")
    })
    @PostMapping("/update")
    public int updateDepartmentById(@RequestParam Long id, @RequestParam String name) {
      String sql = String.format("update department set departmentName = '%s' where id = %d", name, id);
      int result = jdbcTemplate.update(sql);
      return result;
    }
    

    6.5 根据id删除部门

    @ApiOperation(value = "根据id删除部门")
    @ApiImplicitParams({
      @ApiImplicitParam(name = "id", value = "需要删除的部门id")
    })
    @PostMapping("/delete")
    public int deleteDepartment(@RequestParam Long id) {
      String sql = String.format("delete from department where id = %d", id);
      int result = jdbcTemplate.update(sql);
      return result;
    }
    

    七、报错和解决方案:

    7.1 问题1

    java.sql.SQLException:null, message from server: "Host 'Siri' is not allowed to connect to this MySQL server"

    解决方案:
    执行命令:

    use mysql;
    select host from user;
    update user set host = '%' where user = 'root'
    

    执行结果:

    Query OK, 1 row affected
    

    如下图所示:

    7.2 问题2

    Caused by: com.mysql.cj.exceptions.InvalidConnectionAttributeException: The server time zone value '�й���׼ʱ��' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the 'serverTimezone' configuration property) to use a more specifc time zone value if you want to utilize time zone support.

    解决方案:
    配置spring.datasource.url 时,增加参数:serverTimezone=UTC

    关注公众号:悟空聊架构,回复pmp,领取pmp资料!回复悟空,领取架构师资料!

    悟空聊架构

    关注我,带你每天进步一点点!

  • 相关阅读:
    Node.js+express 4.x 入门笔记
    排序系列 之 堆排序算法 —— Java实现
    排序系列 之 归并排序算法 —— Java实现
    javascript必须知道的知识要点(二)
    XGBoost安装
    ubuntu16.04查看哪些软件可更新
    禁止ubuntu更新内核
    ubuntu安装nvidia显卡驱动问题
    禁用ubuntu16.04的guest账户
    远程登录jupyter notebook
  • 原文地址:https://www.cnblogs.com/jackson0714/p/spring-boot-05-jdbc.html
Copyright © 2011-2022 走看看