Spring Boot学习笔记(十二)MyBatis Druid 多数据源 、Spring Boot 集成 Druid—— 概念与实战

MyBatis Druid 多数据源 、Spring Boot 集成 Druid—— 概念与实战

  • Druid介绍
    • Druid 是阿里巴巴开源平台上的一个项目,整个项目由数据库连接池、插件框架和 SQL 解析器组成
    • 该项目主要是为了扩展 JDBC 的一些限制,可以让程序员实现一些特殊的需求,比如向密钥服务请求凭证、统计SQL 信息、SQL 性能收集、SQL 注入检查、SQL 翻译等,程序员可以通过定制来实现自己需要的功能。
    • Druid 不仅是一个数据库连接池,它还包含一个 ProxyDriver,一系列内置的 JDBC 组件库,一个 SQL Parser。在 Javad 的世界中 Druid 是目前最好的数据库连接池,在功能、性能、扩展性上都超过其他数据库连接池,包括 DBCP、C3P0、BoneCP、Proxool、JBoss、DataSource。
  • 用途
    • 替换其他 Java 连接池,Druid 提供了一个高效、功能强大、可扩展性好的数据库连接池。可以监控数据库访问性能,Druid 内置提供了一个功能强大的 StatFilter 插件,能够详细统计 SQL 的执
      行性能,这对于线上分析数据库访问性能有帮助。
    • 数据库密码加密。直接把数据库密码写在配置文件中,容易导致安全问题。DruidDruiver 和 DruidDataSource 都支持 PasswordCallback。
    • SQL 执行日志,Druid 提供了不同的 LogFilter,能够支持 Common-Logging、Log4j 和JdkLog,可以按需要选择相应的 LogFilter,监控应⽤用的数据库访问情况。
    • 扩展 JDBC,如果对 JDBC 层有编程的需求,可以通过 Druid 提供的 Filter 机制,很方便编写JDBC 层的扩展插件。
  • 初始化Spring Boot项目

    Spring Boot学习笔记(十二)MyBatis Druid 多数据源 、Spring Boot 集成 Druid—— 概念与实战_第1张图片

  • 解压之后用IDEA打开 —— 项目目录总览(pom.xml文件未显示)

    Spring Boot学习笔记(十二)MyBatis Druid 多数据源 、Spring Boot 集成 Druid—— 概念与实战_第2张图片

  • pom.xml:
    
    
        4.0.0
        
            org.springframework.boot
            spring-boot-starter-parent
            2.1.8.RELEASE
             
        
        wen
        druid
        0.0.1-SNAPSHOT
        druid
        Demo project for Spring Boot
    
        
            1.8
        
    
        
            
                org.springframework.boot
                spring-boot-starter
            
    
            
                org.springframework.boot
                spring-boot-starter-test
                test
            
    
            
                org.springframework.boot
                spring-boot-starter-web
            
    
            
                org.mybatis.spring.boot
                mybatis-spring-boot-starter
                1.2.0
            
    
            
                com.alibaba
                druid
                1.0.18
            
    
            
                mysql
                mysql-connector-java
            
    
            
                log4j
                log4j
                1.2.17
            
        
    
        
            
                
                    org.springframework.boot
                    spring-boot-maven-plugin
                
            
        
    
    
    
    

    值得一提的是:pom文件有个log4j文件包,这个必须要添加,因为后面的druid配置文件内有个log4j的值,不加上的话会导致配置文件出错而连不上druid

  • application.properties:
    # 主数据源,默认的
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone = GMT
    spring.datasource.username=root
    spring.datasource.password=
    spring.datasource.filters=stat,wall,log4j
    # 更多数据源
    custom.datasource.names=ds1,ds2
    custom.datasource.ds1.driver-class-name=com.mysql.cj.jdbc.Driver
    custom.datasource.ds1.url=jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone = GMT
    custom.datasource.ds1.username=root
    custom.datasource.ds1.password=
    custom.datasource.ds1.filters=stat,wall,log4j
    custom.datasource.ds2.driver-class-name=com.mysql.cj.jdbc.Driver
    custom.datasource.ds2.url=jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone = GMT
    custom.datasource.ds2.username=root
    custom.datasource.ds2.password=
    spring.http.encoding.charset=utf-8
    # 下面为连接池的补充设置,应用到上面所有数据源中
    # 初始化大小,最小,最大
    spring.datasource.initialSize=5
    spring.datasource.minIdle=5
    spring.datasource.maxActive=20
    # 配置获取连接等待超时的时间
    spring.datasource.maxWait=60000
    # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
    spring.datasource.timeBetweenEvictionRunsMillis=60000
    # 配置一个连接在池中最小生存的时间,单位是毫秒
    spring.datasource.minEvictableIdleTimeMillis=300000
    spring.datasource.validationQuery=SELECT 1 FROM DUAL
    spring.datasource.testWhileIdle=true
    spring.datasource.testOnBorrow=false
    spring.datasource.testOnReturn=false
    # 打开PSCache,并且指定每个连接上PSCache的大小
    spring.datasource.poolPreparedStatements=true
    spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
    # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
    # 通过connectProperties属性来打开mergeSql功能;慢SQL记录
    spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
    

    数据库连接的url账户密码根据自己的情况作出修改

  • 数据库设计

    数据库设计为一个主表,两个从表,设定为都包含test表
    Spring Boot学习笔记(十二)MyBatis Druid 多数据源 、Spring Boot 集成 Druid—— 概念与实战_第3张图片
    建表语句:

    CREATE TABLE `test` (
      `id` int(11) unsigned zerofill NOT NULL AUTO_INCREMENT,
      `name` varchar(36) NOT NULL,
      `age` int(2) NOT NULL,
      `gender` varchar(2) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
    
  • 实体类

    entity包内的MasterUser.java 和 CustomUser.java:

    package wen.druid.entity;
    
    public class MasterUser {
    
        private Integer id;
    
        private String name;
    
        private Integer age;
    
        private String gender;
    
        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 == null ? null : name.trim();
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public String getGender() {
            return gender;
        }
    
        public void setGender(String gender) {
            this.gender = gender == null ? null : gender.trim();
        }
    
    }
    
    
    package wen.druid.entity;
    
    public class CustomUser {
    
        private Integer id;
    
        private String name;
    
        private Integer age;
    
        private String gender;
    
        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 == null ? null : name.trim();
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public String getGender() {
            return gender;
        }
    
        public void setGender(String gender) {
            this.gender = gender == null ? null : gender.trim();
        }
    
    }
    
  • 底层xml文件

    MasterUserMapper.xml

    
    
    
    
        
            
            
            
            
        
    
        
            id, name,age,gender
        
    
        
            insert into test (id, name, age, gender)
            values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR},
            #{age,jdbcType=INTEGER}, #{gender,jdbcType=VARCHAR})
        
    
        
            insert into test
            
                
                    id,
                
                
                    name,
                
                
                    age,
                
                
                    gender,
                
            
            
                
                    #{id,jdbcType=INTEGER},
                
                
                    #{name,jdbcType=VARCHAR},
                
                
                    #{age,jdbcType=INTEGER},
                
                
                    #{gender,jdbcType=VARCHAR},
                
            
        
    
        
            delete from test
            where id = #{id,jdbcType=INTEGER}
        
    
        
            update test
            
                
                    name = #{name,jdbcType=VARCHAR},
                
                
                    age = #{age,jdbcType=INTEGER},
                
                
                    gender = #{gender,jdbcType=VARCHAR},
                
            
            where id = #{id,jdbcType=INTEGER}
        
    
        
            update test
            set name = #{name,jdbcType=VARCHAR},
              age = #{age,jdbcType=INTEGER},
              gender = #{gender,jdbcType=VARCHAR}
            where id = #{id,jdbcType=INTEGER}
        
    
        
    
    
    

    CustomUserMapper.xml

    
    
    
    
        
            
            
            
            
        
    
        
            id, name,age,gender
        
    
        
            insert into test
            (id, name, age, gender)
            values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR},
            #{age,jdbcType=INTEGER}, #{gender,jdbcType=VARCHAR})
        
    
        
            insert into test
            
                
                    id,
                
                
                    name,
                
                
                    age,
                
                
                    gender,
                
            
            
                
                    #{id,jdbcType=INTEGER},
                
                
                    #{name,jdbcType=VARCHAR},
                
                
                    #{age,jdbcType=INTEGER},
                
                
                    #{gender,jdbcType=VARCHAR},
                
            
        
    
        
            delete from test
            where id = #{id,jdbcType=INTEGER}
        
    
        
            update test
            
                
                    name = #{name,jdbcType=VARCHAR},
                
                
                    age = #{age,jdbcType=INTEGER},
                
                
                    gender = #{gender,jdbcType=VARCHAR},
                
            
            where id = #{id,jdbcType=INTEGER}
        
    
        
            update test
            set name = #{name,jdbcType=VARCHAR},
              age = #{age,jdbcType=INTEGER},
              gender = #{gender,jdbcType=VARCHAR}
            where id = #{id,jdbcType=INTEGER}
        
    
        
    
    
    
  • mapper层
    package wen.druid.mapper;
    
    import wen.druid.entity.CustomUser;
    
    public interface CustomUserMapper {
    
        int deleteByPrimaryKey(Integer id);
    
        int insert(CustomUser customUser);
    
        int insertSelective(CustomUser customUser);
    
        CustomUser selectByPrimaryKey(Integer id);
    
        int updateByPrimaryKeySelective(CustomUser customUser);
    
        int updateByPrimaryKey(CustomUser customUser);
    
    }
    
    
    package wen.druid.mapper;
    
    import wen.druid.entity.MasterUser;
    
    public interface MasterUserMapper {
    
        int deleteByPrimaryKey(Integer id);
    
        int insert(MasterUser masterUser);
    
        int insertSelective(MasterUser masterUser);
    
        MasterUser selectByPrimaryKey(Integer id);
    
        int updateByPrimaryKeySelective(MasterUser masterUser);
    
        int updateByPrimaryKey(MasterUser masterUser);
    
    }
    
    
  • service层
    package wen.druid.service;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import wen.druid.entity.MasterUser;
    import wen.druid.mapper.MasterUserMapper;
    
    @Service
    public class MasterUserService {
    
        @Autowired
        private MasterUserMapper masterUserMapper;
    
        public MasterUser getMasterUser(Integer id) {
            return masterUserMapper.selectByPrimaryKey(id);
        }
    
        public int insert() {
    
            MasterUser masterUser = new MasterUser();
            masterUser.setName("your papa");
            masterUser.setAge(48);
            masterUser.setGender("M");
    
            return masterUserMapper.insert(masterUser);
        }
    }
    
    
    package wen.druid.service;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import wen.druid.entity.CustomUser;
    import wen.druid.mapper.CustomUserMapper;
    
    @Service
    public class CustomUserService {
    
        @Autowired
        private CustomUserMapper customUserMapper;
    
        public CustomUser getCustomUser(Integer id) {
            return customUserMapper.selectByPrimaryKey(id);
        }
    
        public int insert() {
    
            CustomUser customUser = new CustomUser();
            customUser.setName("mama");
            customUser.setAge(49);
            customUser.setGender("F");
    
            return customUserMapper.insert(customUser);
        }
    }
    
    
  • config配置层文件

    主数据源配置,需要加 @Primary:

    MasterDataSourceConfig.java

    package wen.druid.config;
    
    import com.alibaba.druid.pool.DruidDataSource;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    
    import javax.sql.DataSource;
    
    @Configuration
    @MapperScan(basePackages = MasterDataSourceConfig.PACKAGES, sqlSessionFactoryRef = "masterSqlSessionFactory")
    public class MasterDataSourceConfig {
    
        static final String PACKAGES = "wen.druid.mapper";
    
        private static final String MAPPER_LOCAL = "classpath:mapper/*.xml";
    
        @Primary
        @Bean(name = "masterDataSource")
        @ConfigurationProperties("spring.datasource")
        public DruidDataSource druidDataSource() {
            return new DruidDataSource();
        }
    
    
        @Primary
        @Bean(name = "masterTransactionManager")
        public DataSourceTransactionManager masterTransactionManager() {
            return new DataSourceTransactionManager(druidDataSource());
        }
    
        @Primary
        @Bean(name = "masterSqlSessionFactory")
        public SqlSessionFactory masterSqlSessionFactory(@Qualifier("masterDataSource") DataSource dataSource) throws Exception {
            final SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
            sessionFactoryBean.setDataSource(dataSource);
            sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MAPPER_LOCAL));
            return sessionFactoryBean.getObject();
        }
    
    }
    

    CustomDataSourceConfig.java

    从数据源配置 不需要加@Primary:

    package wen.druid.config;
    
    import com.alibaba.druid.pool.DruidDataSource;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    
    @Configuration
    @MapperScan(basePackages = CustomDataSourceConfig.PACKAGES, sqlSessionFactoryRef = "customSqlSessionFactory")
    public class CustomDataSourceConfig {
    
        static final String PACKAGES = "wen.druid.mapper";
    
        private static final String MAPPER_LOCAL = "classpath:mapper/*.xml";
    
        @Bean(name = "customDataSource")
        @ConfigurationProperties("custom.datasource.ds1")
        public DruidDataSource druidDataSource() {
            return new DruidDataSource();
        }
    
        @Bean(name = "customTransactionManager")
        public DataSourceTransactionManager customTransactionManager() {
            return new DataSourceTransactionManager(druidDataSource());
        }
    
    
        @Bean(name = "customSqlSessionFactory")
        public SqlSessionFactory customSqlSessionFactory(@Qualifier("customDataSource") DruidDataSource dataSource) throws Exception {
            final SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
            sessionFactoryBean.setDataSource(dataSource);
            sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MAPPER_LOCAL));
            return sessionFactoryBean.getObject();
        }
    
    }
    
    
  • servlet插件

    DruidStatViewServlet.java

    package wen.druid.config;
    
    import com.alibaba.druid.support.http.StatViewServlet;
    
    import javax.servlet.annotation.WebInitParam;
    import javax.servlet.annotation.WebServlet;
    
    @SuppressWarnings("serial")
    @WebServlet(urlPatterns = "/druid/*",
            initParams = {
                    @WebInitParam(name = "allow", value = "192.168.16.110,127.0.0.1"),// IP白名单 (没有配置或者为空,则允许所有访问)
                    @WebInitParam(name = "deny", value = "192.168.16.111"),// IP黑名单 (存在共同时,deny优先于allow)
                    @WebInitParam(name = "loginUsername", value = "Stephanie"),// 用户名
                    @WebInitParam(name = "loginPassword", value = "admin"),// 密码
                    @WebInitParam(name = "resetEnable", value = "false")// 禁用HTML页面上的“Reset All”功能
            })
    public class DruidStatViewServlet extends StatViewServlet {
    
    }
    

    上文中的druid控制端用户名为:Stephanie,密码为admin

  • 过滤器DruidStatFilter.java
    package wen.druid.config;
    
    import com.alibaba.druid.support.http.WebStatFilter;
    
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.annotation.WebInitParam;
    
    @WebFilter(filterName = "druidWebStatFilter", urlPatterns = "/*",
            initParams = {
                    @WebInitParam(name = "exclusions", value = "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*")// 忽略资源
            })
    public class DruidStatFilter extends WebStatFilter {
    
    }
    
  • 启动类文件,需要加一个@ServletComponentScan,进行组件扫描
    package wen.druid;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.web.servlet.ServletComponentScan;
    
    @SpringBootApplication
    @ServletComponentScan
    public class DruidApplication {
    
    	public static void main(String[] args) {
    		SpringApplication.run(DruidApplication.class, args);
    	}
    
    }	
    
  • 运行调试
    • 开启启动类之后浏览器访问 http://localhost:8080/master/insert
    • 由于insert方法返回是整数,所以运行成功如下图
      Spring Boot学习笔记(十二)MyBatis Druid 多数据源 、Spring Boot 集成 Druid—— 概念与实战_第4张图片
    • 查询id = 9的用户信息,以JSON数据返回 Spring Boot学习笔记(十二)MyBatis Druid 多数据源 、Spring Boot 集成 Druid—— 概念与实战_第5张图片
    • 访问 http://localhost:8080/druid/login.html,输入DruidStatViewServlet.java提供的方法,进入到druid monitor界面
      Spring Boot学习笔记(十二)MyBatis Druid 多数据源 、Spring Boot 集成 Druid—— 概念与实战_第6张图片Spring Boot学习笔记(十二)MyBatis Druid 多数据源 、Spring Boot 集成 Druid—— 概念与实战_第7张图片
    • 点击导航栏的SQL 监控,可以看到我刚刚操作过的SQL轨迹
      Spring Boot学习笔记(十二)MyBatis Druid 多数据源 、Spring Boot 集成 Druid—— 概念与实战_第8张图片
      项目地址:https://github.com/StephaineWYT/druid
      下一篇:Spring Boot学习笔记(十三)Spring Boot Redis 入门、详解、概念、实战

你可能感兴趣的:(Java,后端,Spring,Boot学习笔记)