SpringBoot:整合Druid、MyBatis


SpringBoot 整合Druid、MyBatis

简介

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

Spring Boot 底层都是采用 Spring Data 的方式进行统一处理各种数据库,Spring Data 也是 Spring 中与 Spring Boot、Spring Cloud 等齐名的知名项目。

Sping Data 官网

数据库相关的启动器 : 可以参考官方文档

JDBC

导入依赖

<!--jdbc-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--web-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--mysql驱动-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

连接数据库

首先我们需要连接数据库,我们直接使用IDEA连接即可

在SpringBoot中,我们需要连接数据库,只需要简单的配置即可

在 application.yaml 中:

spring:
  datasource:
    username: root
    password: root
    # serverTimezone=UTC:MySQL 8+以上使用
    url: jdbc:mysql://localhost:3306/mybatis?useUnicode=ture&characterEncoding=UTF-8&serverTimezone=UTC
     # mysql 8+以上使用  
    driver-class-name: com.mysql.cj.jdbc.Driver    

20200227084116.png

配置完这一些东西后,我们就可以直接去使用了,因为SpringBoot已经默认帮我们进行了自动配置;我们去测试类测试一下

@SpringBootTest
class Springboot03DataApplicationTests {

    @Autowired
    DataSource dataSource;

    @Test
    void contextLoads() throws SQLException {
        // 查看一下默认的数据源
        System.out.println(dataSource.getClass());
        System.out.println("==========");
				// 获得连接
        Connection connection = dataSource.getConnection();
        System.out.println(connection);

        // 归还连接
        connection.close();
    }
}

输出结果:

class com.zaxxer.hikari.HikariDataSource

2020-02-24 16:46:56.963  INFO 19388 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2020-02-24 16:46:59.953  INFO 19388 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
HikariProxyConnection@1336418989 wrapping com.mysql.cj.jdbc.ConnectionImpl@597f0937

从输出结果中可以看出,SpringBoot默认的数据源是:com.zaxxer.hikari.HikariDataSource,我们并没有手动配置。

Spring Boot 2.1.7 默认使用 com.zaxxer.hikari.HikariDataSource 数据源,而以前版本,如 Spring Boot 1.5 默认使用 org.apache.tomcat.jdbc.pool.DataSource 作为数据源;

HikariDataSource 号称 Java WEB 当前速度最快的数据源,相比于传统的 C3P0 、DBCP、Tomcat jdbc 等连接池更加优秀;

CRUD操作

  1. 有了数据源(com.zaxxer.hikari.HikariDataSource),就可以拿到数据库连接(java.sql.Connection),有了连接,就可以使用原生的 JDBC 语句来操作数据库。
  2. 即使不使用第三方的数据库操作框架,如MyBatis等,Spring 本身也对原生的 JDBC 做了轻量级的封装,即:org.springframework.jdbc.core.JdbcTemplate
  3. 数据库操作的所有 CRUD 方法都在 JdbcTemplate 中。
  4. Spring Boot 不仅提供了默认的数据源,同时默认已经配置好了 JdbcTemplate 放在了容器中,程序员只需自己注入即可使用
  5. JdbcTemplate 的自动配置原理是依赖 org.springframework.boot.autoconfigure.jdbc 包下的 org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration

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

  • execute方法:可以用于执行任何SQL语句,一般用于执行DDL语句;
  • update方法及batchUpdate方法:update方法用于执行新增、修改、删除等语句;batchUpdate方法用于执行批处理相关语句;
  • query方法及queryForXXX方法:用于执行查询相关语句;
  • call方法:用于执行存储过程、函数相关语句。

测试:

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

    @GetMapping("/userList")
    public List<Map<String, Object>> userList() {

        String sql = "select id, name, pwd from mybatis.user";

        List<Map<String, Object>> list_maps = jdbcTemplate.queryForList(sql);

        return list_maps;
    }


    @GetMapping("/updUser/{id}")
    public String updateUser(@PathVariable("id") Integer id) {
        String sql = "update mybatis.user set name = ?, pwd = ? where id = " + id;

        // 数据
        Object[] objects = new Object[2];
        objects[0] = "王五";
        objects[1] = "helloworld";

        jdbcTemplate.update(sql, objects);

        return "update-ok";
    }

    @GetMapping("/delUser/{id}")
    public String deleteUser(@PathVariable("id") Integer id) {
        String sql = "delete from mybatis.user where id = ?";

        jdbcTemplate.update(sql, id);
        return "delete-ok";
    }

    @GetMapping("/addUser")
    public String addUser() {
        String sql = "insert into mybatis.user (name, pwd) values (?, ?)";

        // 数据
        Object[] objects = new Object[2];
        objects[0] = "李华";
        objects[1] = "123klajfld";

        jdbcTemplate.update(sql, objects);

        return "insert-ok";
    }
}

原理探究:

org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration 数据源配置类作用 :根据逻辑判断之后,添加数据源;

DataSourceConfiguration DataSourceAutoConfiguration 实际导入的数据源配置类。

tomcat的jdbc连接池:

1582543534506.png

Hikari:

1582543573049.png

dbcp2:

1582543595694.png

自定义数据源:

1582543630501.png

因为SpringBoot 2.x 默认数据源是:com.zaxxer.hikari.HikariDataSource,而其他我们没有导入相应的类,所有会爆红!

SpringBoot默认支持以下数据源:

  • com.zaxxer.hikari.HikariDataSource (Spring Boot 2.0 以上,默认使用此数据源)

  • org.apache.tomcat.jdbc.pool.DataSource

  • org.apache.commons.dbcp2.BasicDataSource

可以使用 spring.datasource.type 指定自定义的数据源类型,值为 要使用的连接池实现的完全限定名。默认情况下,它是从类路径自动检测的。

/**
 * 通用数据源配置
 */
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type")
static class Generic {

   @Bean
   DataSource dataSource(DataSourceProperties properties) {
      return properties.initializeDataSourceBuilder().build();
   }

}

自定义数据源 DruidDataSource

Druid 简介

Druid 是阿里巴巴开源平台上一个数据库连接池实现,结合了 C3P0、DBCP、PROXOOL 等 DB 池的优点,同时加入了日志监控。

Druid 可以很好的监控 DB 池连接和 SQL 的执行情况,天生就是针对监控而生的 DB 连接池。

Spring Boot 2.0 以上默认使用 Hikari 数据源,可以说 Hikari 与 Driud 都是当前 Java Web 上最优秀的数据源,我们来重点介绍 Spring Boot 如何集成 Druid 数据源,如何实现数据库监控。

Druid 的GitHub官网

配置数据源

Druid依赖:

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

现在我们去切换数据源;

之前已经说过 SpringBoot 2.0以上默认使用 com.zaxxer.hikari.HikariDataSource 数据源,但可以通过 spring.datasource.type 指定数据源

20200227083928.png

数据源切换之后,同理可以注入 DataSource,测试类不用变,一测便知!

1582543375247.png

Druid数据库连接池可以配置一些参数:

spring:
  datasource:
    username: root
    password: root
    # serverTimezone=UTC:MySQL 8+以上使用
    url: jdbc:mysql://localhost:3306/mybatis?useUnicode=ture&characterEncoding=UTF-8&serverTimezone=UTC
    # mysql 8+以上使用
    driver-class-name: com.mysql.cj.jdbc.Driver
    # 切换数据源
    type: org.springframework.jdbc.datasource.DriverManagerDataSource

    #Spring Boot 默认是不注入这些属性值的,需要自己绑定
    #druid 数据源专有配置
    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,stat:监控统计、log4j:日志记录、wall:防御sql注入
    #如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority
    #则导入 log4j 依赖即可,Maven 地址: https://mvnrepository.com/artifact/log4j/log4j
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

log4j日志依赖

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

现在需要程序员自己为 com.alibaba.druid.pool.DruidDataSource 绑定到全局配置文件中的参数,再添加到容器中,而不再使用 Spring Boot 的自动生成了;

我们需要 自己添加 DruidDataSource 组件到容器中,并绑定属性;

package com.rainszj.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
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 {

    /*
    将自定义的 Druid数据源添加到容器中,不再让 Spring Boot 自动创建
    绑定全局配置文件中的 druid 数据源属性到 com.alibaba.druid.pool.DruidDataSource从而让它们生效
    @ConfigurationProperties(prefix = "spring.datasource"):作用就是将 全局配置文件中
    前缀为 spring.datasource的属性值注入到 com.alibaba.druid.pool.DruidDataSource 的同名参数中
     */
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource druidDataSource() {

        return new DruidDataSource();
    }

}

去测试类中测试一下;看是否成功!

@SpringBootTest
class Springboot03DataApplicationTests {

    @Autowired
    DataSource dataSource;

    @Test
    void contextLoads() throws SQLException {
        // 查看一下驱动类
        System.out.println(dataSource.getClass());
        System.out.println("==========");

        Connection connection = dataSource.getConnection();
        System.out.println(connection);

        DruidDataSource druidDataSource = (DruidDataSource) this.dataSource;

        System.out.println("最大连接数为:" + druidDataSource.getMaxActive());

        System.out.println("数据源初始化连接数:" + druidDataSource.getInitialSize());

        // 归还连接
        connection.close();
    }
}

打印结果:

1582544191550.png

配置 Druid 数据源监控

Druid 数据源具有监控的功能,并提供了一个 web 界面方便用户查看,类似安装 路由器 时,人家也提供了一个默认的 web 页面。

所以第一步需要设置 Druid 的后台管理页面,比如 登录账号、密码 等;配置后台管理

需要在 DruidConfig 中配置如下内容:

// 配置 Druid 监控管理后台的Servlet;
// 内置 Servler 容器时没有web.xml文件,所以使用 SpringBoot的注册 Servlet 方式
@Bean
public ServletRegistrationBean statViewServlet() {
  			// 创建Servlet注册实体
  			// /druid/*:后台访问的路径
        ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");

        Map<String, String> initParams = new HashMap<>();
        initParams.put("loginUsername", "admin"); //后台管理界面的登录账号
        initParams.put("loginPassword", "123456"); //后台管理界面的登录密码

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

        //设置初始化参数
        bean.setInitParameters(initParams);
        return bean;
    }

这些参数可以在 com.alibaba.druid.support.http.StatViewServlet 的父类 com.alibaba.druid.support.http.ResourceServlet 中找到

1582545305207.png

配置完毕后,我们可以选择访问 : http://localhost:8080/druid/login.html

登录界面:

1582545508418.png

首页:

1582545554152.png

配置 Druid web 监控 filter

这个过滤器的作用就是统计 web 应用请求中所有的数据库信息,比如 发出的 sql 语句,sql 执行的时间、请求次数、请求的 url 地址、以及seesion 监控、数据库表的访问次数 等等

需要在 DruidConfig 中配置如下内容:

//配置 Druid 监控 之  web 监控的 filter
//WebStatFilter:用于配置Web和Druid数据源之间的管理关联监控统计
@Bean
public FilterRegistrationBean filterRegistrationBean() {

    FilterRegistrationBean bean = new FilterRegistrationBean(new WebStatFilter());

    // 设置过滤器的过滤路径
    bean.addUrlPatterns("/*");
    // bean.setUrlPatterns(Arrays.asList("/*"));

    Map<String, String> initParameters = new HashMap<String, String>();
    // 过滤这些东西不进行统计
    initParameters.put("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");

    bean.setInitParameters(initParameters);

    return bean;
}

这些参数在 WebStatFilter类中

1582546547783.png

整合MyBatis

Maven仓库

1582548052252.png

版本要求:

1582722712885.png

第一步:导入Spring Boot 整合 MyBatis的 依赖:

<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.1</version>
</dependency>

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

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

第二步:配置数据库连接信息

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

加载类 com.mysql.jdbc.Driver。不推荐使用。新的驱动程序类为 com.mysql.cj.jdbc.Driver。通过SPI自动注册驱动程序,通常不需要手动加载驱动程序类。

这里使用默认的数据源,测试数据库连接是否成功:

@SpringBootTest
class Springboot03DataApplicationTests {

    @Autowired
    DataSource dataSource;

    @Test
    void contextLoads() throws SQLException {
        // 查看一下驱动类
        System.out.println(dataSource.getClass());
        System.out.println("==========");

        Connection connection = dataSource.getConnection();
        System.out.println(connection);
        System.out.println(connection.getMetaData().getURL());

        // 归还连接
        connection.close();
    }
}

连接成功,OK!

1582548052252.png

第三步:创建实体类:

package com.rainszj.pojo;


public class User {

    private int id;
    private String name;
    private String pwd;


    public User() {
    }

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

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

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
}

第四步:配置Mapper接口,也就是dao层:

package com.rainszj.mapper;

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

import java.util.List;


/**
 * @Mapper:标记这个类是MyBatis的Mapper,等价于Spring整合MyBatis时的Mapper接口
 */
@Mapper
/**
 * @Rpository:将这个接口添加进Spring容器中,和 @Component等价
 */
@Repository
public interface UserMapper {

    // 查询所有用户
    List<User> selectAllUsers();

    // 根据id查找用户
    User findUserById(@Param("uid")Integer id);

    // 修改用户
    int updateUser(User user);

    // 添加用户
    int addUser(User user);

    // 删除用户
    int deleteUser(Integer id);

}

第五步:在application.yaml中添加MyBatis的配置

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

# 整合MyBatis
mybatis:
  # 配置别名
  type-aliases-package: com.rainszj.pojo
  # 绑定Mapper配置文件
  # 注意:这里的 classpath代指:resources目录
  mapper-locations: classpath:mybatis/mapper/*.xml

1582722125809.png

spring boot 官方并没有提供 myBaits 的启动器,是 myBatis 官方提供的开发包来适配的 spring boot,从 pom.xml 文件中的依赖包名也能看出来,并非是以 spring-boot 开头的;

同理上面全局配置文件中的这两行配置也是以 mybatis 开头 而非 spring 开头也充分说明这些都是 myBatis 官方提供的

可以从 org.mybatis.spring.boot.autoconfigure.MybatisProperties 中查看所有配置项

也可以看:mybatis-spring-boot官网

/**
 * Configuration properties for MyBatis.
 *
 * @author Eddú Meléndez
 * @author Kazuki Shimizu
 */
@ConfigurationProperties(prefix = MybatisProperties.MYBATIS_PREFIX)
public class MybatisProperties {

  public static final String MYBATIS_PREFIX = "mybatis";

  private static final ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();

  /**
   * Location of MyBatis xml config file.
   */
  private String configLocation;

  /**
   * Locations of MyBatis mapper files.
   */
  private String[] mapperLocations;

  /**
   * Packages to search type aliases. (Package delimiters are ",; \t\n")
   */
  private String typeAliasesPackage;

  /**
   * The super class for filtering type alias. If this not specifies, the MyBatis deal as type alias all classes that
   * searched from typeAliasesPackage.
   */
  private Class<?> typeAliasesSuperType;

  /**
   * Packages to search for type handlers. (Package delimiters are ",; \t\n")
   */
  private String typeHandlersPackage;

  /**
   * Indicates whether perform presence check of the MyBatis xml config file.
   */
  private boolean checkConfigLocation = false;

  /**
   * Execution mode for {@link org.mybatis.spring.SqlSessionTemplate}.
   */
  private ExecutorType executorType;

  /**
   * The default scripting language driver class. (Available when use together with mybatis-spring 2.0.2+)
   */
  private Class<? extends LanguageDriver> defaultScriptingLanguageDriver;

  /**
   * Externalized properties for MyBatis configuration.
   */
  private Properties configurationProperties;

  /**
   * A Configuration object for customize default settings. If {@link #configLocation} is specified, this property is
   * not used.
   */
  @NestedConfigurationProperty
  private Configuration configuration;
}

第六步:编写对应的Mapper.xml配置文件

<?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.rainszj.mapper.UserMapper">

    <select id="selectAllUsers" resultType="user">
        select * from mybatis.user
    </select>
    
    <select id="findUserById" resultType="user">
        select * from mybatis.user where id = #{uid}
    </select>
    
    <update id="updateUser" parameterType="user">
        update mybatis.user 
        set name = #{name},
            pwd = #{pwd}
        where id = #{id}
    </update>


    <update id="addUser" parameterType="user">
        insert into mybatis.user values (#{id},#{name},#{pwd})
    </update>

    <delete id="deleteUser">
        delete from mybatis.user where id = #{id}
    </delete>



</mapper>

第七步:service层:

package com.rainszj.service;

import com.rainszj.mapper.UserMapper;
import com.rainszj.pojo.User;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public List<User> selectAllUsers() {
        return userMapper.selectAllUsers();
    }

    // 根据id查找用户
    public User findUserById(Integer id) {
        return userMapper.findUserById(id);
    }

    // 修改用户
    public int updateUser(User user) {
        return userMapper.updateUser(user);
    }

    // 添加用户
    public int addUser(User user) {
        return userMapper.addUser(user);
    }

    // 删除用户
    public int deleteUser(Integer id) {
        return userMapper.deleteUser(id);
    }


}

第八步:controller层:

package com.rainszj.controller;

import com.rainszj.pojo.User;
import com.rainszj.service.UserService;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class UserController {

    @Autowired
    private UserService userService;


    @GetMapping("/selectAllUsers")
    public List<User> selectAllUsers() {

        return userService.selectAllUsers();
    }


    @GetMapping("/findUserById/{id}")
    public String findUserById(@PathVariable Integer id) {
        User user = userService.findUserById(id);
        System.out.println(user);

        return "ok";
    }

    @GetMapping("/addUser")
    public String addUser() {
        userService.addUser(new User(4, "张三", "123"));
        return "ok";
    }


    @GetMapping("/updateUser")
    public String updateUser() {
        userService.updateUser(new User(4, "李四", "123"));

        return "ok";
    }

    @GetMapping("/deleteUser")
    public String deleteUser(@RequestParam("uid") Integer id) {
        userService.deleteUser(id);
        return "ok";
    }

}

测试一下就搞定 OK!


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM