SpringBoot学习笔记(七)

本文主要介绍SpringBoot整合JDBC、SpringBoot整合Druid和SpringBoot整合Mybatis

一、SpringBoot整合JDBC

对于数据访问层,无论是 SQL(关系型数据库) 还是 NOSQL(非关系型数据库),Spring Boot 底层都是采用 Spring Data 的方式进行统一处理。官网地址连接

image

image

  • 创建测试项目测试数据源

1.新建一个项目测试:springboot-data-jdbc ,引入相关模块:

image

image

2.IDEA自动导入如下启动器:

image

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

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

3.编写yaml或者properties文件,连接数据库(这里有个大坑!!!

image

spring:
  datasource:
    data-username: root
    data-password: root
    url: jdbc:mysql://localhost:3306/springboot?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8
    driver-class-name: com.mysql.cj.jdbc.Driver

4.配置好这些就可以直接使用了(SpringBoot自动装配)

idea 连接数据库

image

去测试类测试:

package com.zhou;

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 SpringbootDataJdbcApplicationTests {
    //DI注入依赖
    @Autowired
    DataSource dataSource;
    @Test
    void contextLoads() {
        //查看默认的数据源
        System.out.println(dataSource.getClass());
        Connection connection=null;
        try {
            //获得连接,并打印
            connection = dataSource.getConnection();
            System.out.println(connection);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            try {
                //关闭连接
                connection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

6.Run

报错:java.sql.SQLException: Access denied for user ''@'localhost' (using password: NO)

image

解决办法:修改application.yml配置文件

记住:username和password 前面不能加 data-

image

7.再次启动,查看到默认的数据源:class com.zaxxer.hikari.HikariDataSource

image

全局搜索,找到数据源相关的自动配置 :DataSourceAutoConfiguration文件:

image

/**
 * {@link EnableAutoConfiguration Auto-configuration} for {@link DataSource}.
 *
 * @author Dave Syer
 * @author Phillip Webb
 * @author Stephane Nicoll
 * @author Kazuki Shimizu
 * @since 1.0.0
 */
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory")
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class })
public class DataSourceAutoConfiguration {

	@Configuration(proxyBeanMethods = false)
	@Conditional(EmbeddedDatabaseCondition.class)
	@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
	@Import(EmbeddedDataSourceConfiguration.class)
	protected static class EmbeddedDatabaseConfiguration {

	}

	@Configuration(proxyBeanMethods = false)
	@Conditional(PooledDataSourceCondition.class)
	@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
	@Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
			DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.OracleUcp.class,
			DataSourceConfiguration.Generic.class, DataSourceJmxConfiguration.class })
	protected static class PooledDataSourceConfiguration {

	}
	//省略部分代码
  • 另外,如 Spring Boot 1.5 默认使用 org.apache.tomcat.jdbc.pool.DataSource 作为数据源。在CSDN 看到一篇文章,介绍SpringBoot为什么选用Hikari作为默认的数据源,感兴趣的同学可以阅读:(我保存一下,嘻嘻~)追逐风的蝴蝶:关于springboot 的默认数据源

HikariCP的性能远高于c3p0、tomcat等连接池,以致后来BoneCP作者都放弃了维护,在Github项目主页推荐大家使用HikariCP。另外,Spring Boot将在2.0版本中把HikariCP作为其默认的JDBC连接池。

  • JDBCTemplate

1.有了数据源(class com.zaxxer.hikari.HikariDataSource),然后可以拿到数据库连接池(java.sql.Connection),有了连接就可以使用JDBC语句来操作数据库了。

2.Spring 本身也对原生的JDBC做了轻量级的封装,即JDBCTemplate,即使不使用第三方数据库操作框架,如Mybatis等。

3.数据库操作的所有 CRUD 方法都在 JdbcTemplate 中。

4.SpringBoot不仅提供了默认的数据源,同时默认已经配置好了 JdbcTemplate 放在了容器中,程序员只需自己注入即可使用。

5.JdbcTemplate 的自动配置是依赖 org.springframework.boot.autoconfigure.jdbc包下的 JdbcTemplateConfiguration

image

6.JdbcTemplateAutoConfiguration 源码:

image

  1. JdbcTemplate类中,可以看到大量的CURD操作:

image

JdbcTemplate主要提供以下几类方法:

execute方法:可以用于执行任何SQL语句,一般用于执行DDL语句;

update方法及batchUpdate方法:update方法用于执行新增、修改、删除等语句;batchUpdate方法用于执行批处理相关语句;

query方法及queryForXXX方法:用于执行查询相关语句;

call方法:用于执行存储过程、函数相关语句。
  • 测试:

编写一个Controller,注入 jdbcTemplate,编写测试方法进行访问测试:

package com.zhou.conroller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/jdbc")
public class JdbcController {
    /**
     * Spring Boot 默认提供了数据源,默认提供了 org.springframework.jdbc.core.JdbcTemplate
     * JdbcTemplate 中会自己注入数据源,用于简化 JDBC操作
     * 还能避免一些常见的错误,使用起来也不用再自己来关闭数据库连接
     */
    @Autowired
    JdbcTemplate jdbcTemplate;

    @GetMapping("/list")
    public List<Map<String, Object>> userList(){
        String sql = "select * from user";
        List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
        return maps;
    }

    //新增
    @GetMapping("/add")
    public String addUser(){
        String sql = "insert into user(id,name,password)value('8','zhouzhou','7880907')";
        jdbcTemplate.update(sql);
        return "addOk";
    }
    
    //修改
    @GetMapping("/update/{id}")
    public String updateUser(@PathVariable("id") int id){
        String sql = "update user set name=?,password=? where id="+id;
        Object[] person = new Object[2];
        person[0] = "被修改的人";
        person[1] = "2343234";
        jdbcTemplate.update(sql,person);

        return "updateOk";
    }
    
    //删除
    @GetMapping("/delete/{id}")
    public String delUser(@PathVariable("id") int id){
        String sql = "delete from user where id=?";
        jdbcTemplate.update(sql,id);
        return "deleteOk";
    }
}
  • Run 测试 OK

list

image

add

image

update

image

delete

image

查询数据库,数据确实被进行 CURD 操作了

image

二、SpringBoot整合Druid

  • Druid是一个JDBC组件,它包括三部分:
  1. DruidDriver 代理Driver,能够提供基于Filter-Chain模式的插件体系。
  2. DruidDataSource 高效可管理的数据库连接池.
  3. SQLParser
  • Druid可以做什么?
  1. 可以监控数据库访问性能;
  2. Druid提供了一个高效、功能强大、可扩展性好的数据库连接池;
  3. 数据库密码加密;
  4. Druid提供了不同的LogFilter(支持Common-Logging、Log4j和JdkLog)
  5. 扩展JDBC(通过Druid提供的Filter-Chain机制,编写JDBC层的扩展插件)

Druid 的 JavaDoc 文档

  • Spring Boot 如何集成 Druid 数据源,如何实现数据库监控

DruidDataSource 参数配置详解

image
image

  • 配置数据源

1、添加上 Druid 数据源依赖:

<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.5</version>
</dependency>

2、切换数据源(SpringBoot 2.0以上默认使用 com.zaxxer.hikari.HikariDataSource 数据源)

通过spring.datasource.type指定数据源:

image

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/springboot?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource #Druid

3、数据源切换之后,在测试类中注入 DataSource,然后测试是否成功切换:

image

4、切换成功后就可以设置数据源连接初始化大小、最大连接数、等待时间、最小连接数 等设置项:

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/springboot?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource #Druid

    #Spring Boot 默认是不注入这些属性值的,需要自己绑定
    #druid 数据源专有配置
    initialSize: 4
    minIdle: 4
    maxActive: 20
    maxWait: 30000
    timeBetweenEvictionRunsMillis: 50000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true

    #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

5.现在要为 DruidDataSource 绑定全局配置文件中的参数,再添加到容器中,而不再使用 Spring Boot 的自动生成了

(需要自己添加 DruidDataSource 组件到容器中,并绑定属性)

package com.zhou.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
public class DruidConfig {

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

6.去测试类中测试:

package com.zhou;

import com.alibaba.druid.pool.DruidDataSource;
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 SpringbootDataJdbcApplicationTests {
    //DI注入依赖
    @Autowired
    DataSource dataSource;
    @Test
    void contextLoads() {
        //查看默认的数据源
        System.out.println(dataSource.getClass());
        Connection connection=null;
        try {
            //获得连接,并打印
            connection = dataSource.getConnection();
            System.out.println(connection);

            DruidDataSource druidDataSource=(DruidDataSource) dataSource;

            System.out.println("druidDataSource 数据源最大连接数:" + druidDataSource.getMaxActive());
            System.out.println("druidDataSource 数据源初始化连接数:" + druidDataSource.getInitialSize());
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            try {
                //关闭连接
                connection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

报错:Caused by: java.lang.ClassNotFoundException: org.apache.log4j.Priority

image

解决:导入Log4j 的依赖

<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

7.再次测试:OK

image

  • 配置Druid数据源监控

Druid 数据源具有监控的功能,并提供了一个 web 界面方便用户查看。

1.需要设置 Druid 的后台管理页面,比如 登录账号、密码 等;配置后台管理:

image

package com.zhou.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class DruidConfig {

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

    /**
     * 配置 Druid 监控管理后台的Servlet
     * SpringBoot内置 Servlet 容器时没有web.xml文件,所以使用 Spring Boot 的注册 Servlet 方式
     * @return
     */
    @Bean
    public ServletRegistrationBean servletRegistrationBean(){
        ServletRegistrationBean bean=new ServletRegistrationBean(new StatViewServlet(), "/druid/*");

        Map<String, String> initParams = new HashMap<>();

        initParams.put("loginUsername","root");
        initParams.put("loginPassword","root");
        //后台允许谁可以访问:
        //initParams.put("allow", "localhost"):表示只有本机可以访问
        //initParams.put("allow", ""):为空或者为null时,表示允许所有访问
        initParams.put("allow","");
        //deny:Druid 后台拒绝谁访问
        //initParams.put("zhouzhou", "192.168.1.20");表示禁止此ip访问

        //设置初始化参数
        bean.setInitParameters(initParams);
        return bean;
    }
}
  • 上面的参数不是瞎写的:可以在com.alibaba.druid.support.http.StatViewServlet的父类

com.alibaba.druid.support.http.ResourceServlet中找到的:

image

com.alibaba.druid.support.http.ResourceServlet类:

image

2.配置完毕,启动

image

3.访问:http://localhost:8081/druid/login.html

image

4.输入用户名和密码后:

image

工作中,按需求进行配置即可,主要用作监控。

三、SpringBoot整合Mybatis

整合MyBatis

官方文档:http://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/

image

开始整合:

1.导入 Mybatis所需要的依赖:

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

2、配置数据库连接信息

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/springboot?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource #Druid

    #Spring Boot 默认是不注入这些属性值的,需要自己绑定
    #druid 数据源专有配置
    initialSize: 4
    minIdle: 4
    maxActive: 20
    maxWait: 30000
    timeBetweenEvictionRunsMillis: 50000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true

    #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
  thymeleaf:
    cache: false

mybatis:
  type-aliases-package: com.zhou.pojo
  mapper-locations: classpath:mapper/*.xml

3、测试数据库是否连接成功

4.创建实体类:User.java

package com.zhou.pojo;

import org.apache.ibatis.type.Alias;

import java.io.Serializable;

public class User implements Serializable {
    private Integer id;
    private String name;

    public User() {
    }

    public User(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

5.创建mapper目录以及对应的 Mapper 接口

image

package com.zhou.mapper;

import com.zhou.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

import java.util.List;

@Mapper
@Repository
public interface UserMapper {
    //获取所有User
    List<User> getUser();
    //通过id查找
    User getUserById(Integer id);
}

6、Mapper映射文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zhou.mapper.UserMapper">
    <select id="getUser" resultType="User">
        select * from user;
    </select>

    <select id="getUserById" resultType="User" parameterType="int">
        select * from user
        where id=#{id}
    </select>
</mapper>

7、编写 UserController 进行测试

package com.zhou.conroller;

import com.zhou.mapper.UserMapper;
import com.zhou.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class UserController {
    @Autowired
    UserMapper userMapper;

    @GetMapping("/getUser")
    public List<User> getUser(){
        return userMapper.getUser();
    }
    @GetMapping("/getUserById/{id}")
    public User getUserById(@PathVariable("id") Integer id){
        return userMapper.getUserById(id);
    }
}

8..Run 测试 访问:http://localhost:8080/getUser

image

接续测试 访问:http://localhost:8080/getUserById/7

image


【注意】可能出现的报错:(上面的代码实例都是解决过的了,这里做为个人记录。)

前端显示:There was an unexpected error (type=Internal Server Error, status=500).

image

后端显示:org.thymeleaf.exceptions.TemplateInputException: Error resolving template [getUser], template might not exist or might not be accessible by any of the configured Template Resolvers

image

解决:

1.Maven 资源过滤问题

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
        <!--Maven 资源过滤问题-->
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.*</include>
                </includes>
                <filtering>false</filtering>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.*</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
    </build>

2.将 UserController类上的注解 @Controller 更改为 @RestController
(这里真的时太大意了,疏忽了)

3.在配置 mybatis 时,使用application.yml或者application.properties 需要注意一下书写格式的不同,这里拿对比图记录一下。

image

还有,在application.yml中配置 mybatis,我自作聪明的操作,不可取!

image

posted @ 2021-03-25 20:23  江河湖泊  阅读(242)  评论(0编辑  收藏  举报