(8)Spring Boot 与数据访问


简介

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

      引入各种 xxxTemplate,xxxRepository 来简化我们对数据访问层的操作,对我们来说,只需要进行简单的设置即可。


整合基本的JDBC与数据源

  1. 引入启动器

    Spring Boot 有许多的场景启动器,这里就提供了 spring-boot-starter-jdbc

            <!--引入 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. 配置 application.yml

    然后在配置文件里面,告诉 Spring Boot 数据库地址、用户名、密码

    	# 配置数据库
    spring:
      datasource:
        username: root
        password: Myis03571
        url: jdbc:mysql:///cms?charset=utf-8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
        driver-class-name: com.mysql.cj.jdbc.Driver
    

    测试下数据源:

       @Autowired
        private DataSource dataSource;
        @Test
        public void contextLoads() throws SQLException {
            Connection connection = dataSource.getConnection();
            System.out.println(" ----  "+dataSource.getClass());
            System.out.println(" ----  "+connection);
            connection.close();
    
        }
    

    打印结果:

     ----  class com.zaxxer.hikari.HikariDataSource
     ----  HikariProxyConnection@668754554 wrapping com.mysql.cj.jdbc.ConnectionImpl@570ba13
    

    Spring Boot 2.0 版本以后,默认选择的数据源是 HikariDataSource ,也可以在配置文件里面制定自定义的数据源类型 :spring.datasource.type,指定数据源类型;

  3. 初始化数据库

    可以将 sql 语句放在类路径下面,其中默认的命名规则:建表语句文件起名叫 schema.sql,插入语句文件起名叫 data.sql

    也可以设置后缀,比如你想在项目启动的时候,执行 schema-mysql.sql ,则需要在配置文件里面进行配置:spring.datasource.platform = mysql ,指定下;

    或者也可以完全自定义这些规则,在配置文件里面配置,指定位置及文件名称 :

    spring:
      datasource:
        schema: 
          - classpath:xxx.sql
    

    需要注意的事:每次应用重新启动,都会执行一次这些 sql 语句,也就是表会被重建,这样里面数据会丢失;

  4. 自动配置了 JdbcTemplate

    我们可以直接使用注入,获取到它,然后操控数据库;

    可以向下面这样使用:

    
        @Autowired
        private JdbcTemplate jdbcTemplate ;
    
        @ResponseBody
        @GetMapping("/users")
        public List<Map<String, Object>> getUser(){
            List<Map<String, Object>> mapList = jdbcTemplate.queryForList("select * from DEPARTMENT");
            return mapList;
        }
    
  5. 坑点

    如果这时候你启动项目,你会发现,你的 sql 语句死活都得不到执行,数据库没有任何表生成,控制台也看不到任何 sql 的日志,调试了半天;

    博主也只是个搬运工啊,看的视频,然后自己写的教程,视频老师使用 Spring Boot的版本是 2.0 ↓ ,最后一路查到官网(2.0 ↑),发现有下面一段话:在这里插入图片描述

    大概意思就是说:Spring Boot 能够自动的执行 schema 文件,根据配置的数据源,这种自动的行为,可以通过 spring.datasource.initialization-mode 控制,然后重点的一句话:比如你可以使用 spring.datasource.initialization-mode=always 控制 Spring Boot 永远的执行上述操作,而不管其具体类型;

    这句话的潜台词,可能是想告诉我,Spring Boot 在某些情况下,会不执行 schema 文件,好像我们遇到了这种情况,但是啥情况它也没说,或者说了我没看见,甭管,直接配置下属性 spring.datasource.initialization-mode=always 再说:

    启动,然后控制台,我还是没找到对应的日志,真的迷,我都打开了终极日志输出了:

    logging.level.* = trace
    debug=true
    

    好在,数据库里面表已经创建出来了;

    总结:记得配上 spring.datasource.initialization-mode=always ,如果你使用的是 2.0 ↑


整合 druid 数据源

虽然 Spring Boot 默认使用 HikariDataSource ,可能这也是它推荐 HikariDataSource 的一种手段,但是我们由于一些原因,不接受它的推荐;

HikariDataSource 性能是要优于 druid 的,但是 druid 有一整套的方案,可以监控许多东西,还有后台管理界面;

  1. 引入 Druid

    	  <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.8</version>
            </dependency>
    

    我靠,IDEA 莫名其妙,引入以后,pom文件也没爆红,然后 jar 包也下载到本地,但是 IDEA 依赖里面找不到,重启下才找到。

  2. 修改依赖的数据源

    # 配置数据库
    spring:
      datasource:
        username: root
        password: Myis03571
        url: jdbc:mysql:///any?charset=utf-8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
        driver-class-name: com.mysql.cj.jdbc.Driver
        schema:
         - classpath:ssasa.sql
         # 修改数据源,改为 马云 家 的 
        type: com.alibaba.druid.pool.DruidDataSource
    

    启动之前的测试,这次打印出的数据源是:

     ----  class com.alibaba.druid.pool.DruidDataSource
    
  3. 配置数据源

    Druid 配置讲解 ,这篇写的不错,可以看下,主要看他,那些配置项的意思;

    # 配置数据库
    spring:
      datasource:
        username: root
        password: Myis03571
        url: jdbc:mysql:///any?charset=utf-8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
        driver-class-name: com.mysql.cj.jdbc.Driver
        schema:
    #      - 可以写多个,是个列表
    #     - classpath:ssasa.sql
        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
    
    

    然后,在配置里面,加载下 spring.datasource 下面的属性,进行属性的绑定:

        @ConfigurationProperties(prefix = "spring.datasource")
        @Bean
        public DataSource dataSource(){
            return new DruidDataSource();
        }
    

    然后运行,哐!报错:

    Caused by: java.lang.NoClassDefFoundError: org/apache/log4j/Priority
    	at java.lang.Class.forName0(Native Method)
    	at java.lang.Class.forName(Class.java:264)
    	at com.alibaba.druid.util.Utils.loadClass(Utils.java:203)
    	at com.alibaba.druid.filter.FilterManager.loadFilter(FilterManager.java:104)
    	at com.alibaba.druid.pool.DruidAbstractDataSource.addFilters(DruidAbstractDataSource.java:1286)
    	at com.alibaba.druid.pool.DruidAbstractDataSource.setFilters(DruidAbstractDataSource.java:1275)
    	... 107 more
    Caused by: java.lang.ClassNotFoundException: org.apache.log4j.Priority
    	at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
    	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
    	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    	... 113 more
    
    

    一通搜索以后,找到原因所在: 由于 Spring Boot 2.xxx 版本,底层将日志框架的组件换了个小零件,log4j-over-slf4j 被换成了 log4j-to-slf4j,但是 logback + sl4j 这套组合又需要 log4j-over-slf4j ,不然就报错,因此添加下 log4j-over-slf4j,它是个中间层,承上启下,上承 log4j ,然后做个转换,换成 logback

    切忌,不要直接添加 log4j 包,那样就打破了整个系统使用同一套日志的机制):

       <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>log4j-over-slf4j</artifactId>
                <version>1.7.24</version>
            </dependency>
    

    打断点,再次运行,看下数据源:
    在这里插入图片描述
    属性已经注入到其中;

  4. 配置监控

    
        /**
         * 配置 Druid 的监控
         * 1、先配置一个管理后台的 servlet
         * 2、配置一个监控后台的 filter
         *
         * 备注,方法名字,不可随意写,spring Boot 是根据这些去覆盖某些bean的
         * @return
         */
        @Bean
        public ServletRegistrationBean statViewServlet() {
            // 后面的参数,设置进入管理页面的url,可以随便写,但是最好写成 /druid/* 
            // 因为,当没有登陆以后,访问其他监控页面的时候,会自动的跳转到 ,/druid/login.html
            // 如果你这里配置成其他的,则跳转发生错误了
            ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
    
            // 配置 StatViewServlet 的属性
            Map<String, String> initParameters = new HashMap<>();
            // 配置后台登陆的用户名和密码
            initParameters.put("loginUsername", "admin");
            initParameters.put("loginPassword", "123456");
            // 配置允许谁登陆,默认允许任何人使用配置的用户名和密码登陆,配置成localhost,就仅仅本机能登陆了
            initParameters.put("allow", "");
            // 配置拒绝谁访问
            initParameters.put("deny", "192.168.111.1");
    
            bean.setInitParameters(initParameters);
    
            return bean;
        }
        @Bean
        public FilterRegistrationBean webStatFilter() {
            FilterRegistrationBean bean = new FilterRegistrationBean();
            bean.setFilter(new WebStatFilter());
    
            // 同样可以配置初始化参数
            Map<String, String> initParas = new HashMap<>();
            // 配置排除项,排除哪些资源,排除静态资源
            initParas.put("exclusions","*.js,*.css,/druid/*");
    
            bean.setInitParameters(initParas);
    
            // 配置拦截的 url
            bean.setUrlPatterns(Arrays.asList("/*"));
            return bean ;
        }
    

    然后在浏览器里面,输入你配置的进入监控页面的路径:

    在这里插入图片描述
    输入配置的用户名和密码,来到管理页面:

    在这里插入图片描述

    感觉可以拿去充当毕业设计了,后台管理系统,哈哈哈。。阿里给力啊;页面广告被 ABP 插件屏蔽了,不然每个页面都是阿里云的广告;


整合 mybatis

引入 mybatis 依赖:

		<dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.0.0</version>
        </dependency>

可以看到是由 mybatis 打头的,它是由 mybatis 官方开发的,来支持 Spring 的,也就是其实 Spring 官方根本没看上 Mybatis,其实也就是国内在大规模使用 mybatis ,国外反而使用 hibernate 为主流;其实 hibernate 也没有那么不堪,你逃不过的,如果想要玩 JPAhibernate 就是绕不过去的一关 ;

  1. 使用 mybatis 基于注解

    • 创建一个 mapper 接口,然后在接口方法上使用注解,直接写 sql

      
      	@Mapper
      	public interface DepartmentMapper {
      	
      	    @Options(useGeneratedKeys = true,keyProperty = "id")
      	    @Insert("insert into DEPARTMENT(name) values(#{name})")
      	    public int insertDepartment(Department department);
      	
      	    @Select("select * from DEPARTMENT where id = #{id}")
      	    public Department getDeptById(Integer id);
      	
      	    @Update("update DEPARTMENT set name = #{name} where id = #{id}")
      	    public int updateDeptById(Department department);
      	
      	    @Delete("delete from DEPARTMENT where id = #{id}")
      	    public int deleteDeptById(Integer id);
      	}
      
      
    • 然后,控制层代码,restful 风格:

      
      	@RestController
      	public class DepartmentController {
      	
      	    @Autowired
      	    private DepartmentMapper departmentMapper;
      	
      	    @GetMapping("/dept/{id}")
      	    public Department getDeptById(@PathVariable("id") Integer id) {
      	        return departmentMapper.getDeptById(id);
      	    }
      	
      	    @GetMapping("/dept")
      	    public Department insertDept(Department department) {
      	        departmentMapper.insertDepartment(department);
      	        return department;
      	    }
      	}
      
      
      
    • 在配置类里面,进行自定义 mybatis 配置,比如开启驼峰命名法:

       /**
           * 自定义mybatis的配置
           *
           * @return
           */
          @Bean
          public ConfigurationCustomizer configurationCustomizer() {
              return new ConfigurationCustomizer() {
                  @Override
                  public void customize(org.apache.ibatis.session.Configuration configuration) {
                      // 开启驼峰命名法
                      configuration.setMapUnderscoreToCamelCase(true);
                  }
              };
          }
      

      也可以使用@MapperScan(value = "cn.hyc.demo.mapper")注解批量扫描 mapper 接口 ;

  2. 使用配置文件版本

    跟以前学的时候,没啥差别;

    这里,仅仅记录下不一样的地方;

    • 在类路径下面创建一个 mybatis 的全局配置文件,内容如下(暂时没做任何配置):

      <?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>
      
      </configuration>
      
    • spring Boot 配置文件配置下 mybatis 的相关配置,让 mybatis 知道 mapper 文件在哪

      # 配置 mybatis 的相关配置
      mybatis:
        config-location: classpath:mybatis/mybatis-config.xml
        mapper-locations: classpath:mybatis/mapper/*.xml
      
      
原文地址:https://www.cnblogs.com/young-youth/p/11665577.html