zoukankan      html  css  js  c++  java
  • (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
        
        
  • 相关阅读:
    Foundations of Machine Learning: The PAC Learning Framework(2)
    Foundations of Machine Learning: The PAC Learning Framework(1)
    图形渲染流水线
    如何用python的装饰器定义一个像C++一样的强类型函数
    Python 装饰器学习心得
    PAT 1087 All Roads Lead to Rome
    PAT 1086 Tree Traversals Again
    PAT 1085 Perfect Sequence
    PAT 1084 Broken Keyboard
    LeetCode: Sort Colors
  • 原文地址:https://www.cnblogs.com/young-youth/p/11665577.html
Copyright © 2011-2022 走看看