Springboot + MyBatis入门培训 3 多数据源与缓存和数据连接池设置

介绍MyBatis项目中如何配置多个数据源连接数据库,以及设置sql文的二级缓存功能,配置多数据源与数据连接池等功能。为大家开发和平时练习的时候提供参考和查询的工具文章。

代码下载百度网盘下载:https://pan.baidu.com/s/1Q6pbC2SR70HKCeVXgOGUPQ
提取码:1234

本站资源下载

Springboot + MyBatis入门培训 1 项目运行环境配置

Springboot + MyBatis入门培训 2 增改删除与查询 in like foreach操作

MyBatis多数据源设置

在实际的项目开发中通常会遇到业务数据保存在不同的数据库中,而我们需要操作多个数据数据库进行业务操作的情况。在MyBati中是可以同时使用多个数据源连接数据库的,项目中导入dynamic-datasource 插件就可以配置多个数据源的连接,使用起来非常的简单,操作与维护性非常的高。dynamic-datasource可以封装成Spring Starter方式引入,支持Mybatis读写分离,支持通过注解动态切换切换数据源。

pom.xml

<!--多数据源需要-->
<dependency>
   <groupId>com.baomidou</groupId>
   <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
   <version>3.3.6</version>
</dependency>

spring boot application.yml文配置

​ 配置多数据源唯一技术难度就是配置上,配置正确调用起来非常简单。

数据源在yml文件中的结构

  • datasource: 数据源根节点
  • dynamic: 多数据源配置头节点
  • primary : 默认主数据名称
  • datasource: 数据节点
  • master:默认节点
  • 子节点: 自定义节点名称

配置层级

spring:                   spring顶层标记
 datasource:              1级
    dynamic:              2级
      primary: master     3级
      strict: false       3级
      datasource:         3级
        master:           4级
        子节点名称:         4级

找到目录中的application.yml 配置文件,添加如下内容到application.yml 文件中。

  • 数据源配置要在spring节点下建立
  • 默认节点与子数据库节点下配置数据库连接内容

配置2个数据源,在项目工程中可以使用MyBatis访问这两数据库来进行sql文操作。

spring:
  datasource:
    dynamic:
      primary: master
      strict: false
      datasource:
        master:
          url: jdbc:mysql://localhost:3306/db1   #数据库一
          username: root
          password: 123456
		  driver-class-name: com.mysql.jdbc.Driver
         zht:
          url: jdbc:mysql://localhost:3306/db2  #数据库二
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver

支持在项目中同时配置不同数据库的数据连接

  • oracle 数据库
  • mysql数据库
  • postgresql数据库
  • sqlserver数据库
  • h2数据库

多数据库配置

spring:
  datasource:
    dynamic:
      primary: master
      strict: false
      datasource:
        master:
          url: jdbc:mysql://localhost:3306/db1      #mysql
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver
         zht:
          url: jdbc:oracle:thin:@localhost:1521:orcl  #oracle
          username: root
          password: 123456
          driver-class-name: oracle.jdbc.driver.OracleDriver

同时配置两个不同的数据库连接源。

切换数据源 @Mapper 容器操作

在文件目录中找到 UserSql.xml文件,定义两数据库连接的 sql文方法。

  • UserList 方法的中的use表在数据库localhost:3306/db1
  • towlist 方法中的userdb2表在数据库localhost:3306/db2

UserSql.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="cn.core.my.app.dao.UserDao"> 
  <select id="UserList" resultType="map">
        select * from user
  </select>    
  <select id="towlist" resultType="map">
        select * from userdb2
   </select>
</mapper>    

@DS 注解打在要执行的MyBatis 执行方法上。@DS 标注要执行的数据库连接的名称,方法在执行的时候就执行标注的数据库连接。

如果MyBatis 执行方法上没有标注@DS,方法执行默认的数据库连接。

UserDao接口

@Mapper
public interface UserDao {
    //没有定义@DS 表示执行默认数据库
	 List<Map> UserList(Map map);
     //强制方法访问数据库localhost:3306/db2来执行
	 @DS("zht")
	 List<Map> towlist(Map map);
}

MyBatisTest测试类

@RunWith(SpringRunner.class)
@SpringBootTest(classes=OnApp.class)
public class MyBatisTest {
	@Test
	public void TestAddDB(){
		//第一个数据库连接表测试  user表
		userdao.UserList(new HashMap());
		//第二个数据库连接表测试 userdb2表
		userdao.towlist(new HashMap());
	}
}

在测试类中定义对应的测试方法。

运行结果

-----------主数据库user表  -----------------
==>  Preparing: select * from user WHERE id in (?) and user like '%%' 
==> Parameters: null
<==      Total: 0
-----------子数据库sys_user表-----------------
==>  Preparing: select * from sys_user 
==> Parameters: 
<==  Columns: id, acc, paw, u_name, u_post, u_edu, birthday, notes, deptid, isamdin

不同数据库操作同表 @Service容器操作

如果两个数据库中有同一张表,在UserSql.xml中定义同一张表的sql文业务操作,我们要怎么做呢?我们需要定义一个spring @Service容器,在容器中使用**@DS** 注解来区分不同数据库的操作。

UserSql.xml

<select id="addlist" resultType="map">
     select * from user
</select> 

在数据库一和数据库二中同时创建一个表user,在UserSql.xml中定义个 select * from user 业务的sql文方法。

UserDao接口

@Mapper
public interface UserDao {
	//所有数据库共同使用一张表
	List<Map> addlist(Map map);
}

UserDao接口中定义这个表查询的MyBatis 执行方法

UserServer 业务类

在@Service容器类中定义两个执行方法,一个没有**@DS** 注解的方法执行查询默认数据库中user表,别一个定义@DS(“zht”)查询数据库二中的user表信息。

@Service
public class UserServer {
	@Autowired
	UserDao user;
	public List getOne(Map map){
		return user.addlist(map);
	}
	@DS("zht")
	public List getTow(Map map){
		return user.addlist(map);
	}
}

MyBatisTest测试类

@RunWith(SpringRunner.class)
@SpringBootTest(classes=OnApp.class)
public class MyBatisTest {
  @Autowired
  UserServer us;//业务容器引入
  @Test
  public void AddDB(){
	//第一个数据库连接user表
	us.getOne(new HashMap());
	//第二个数据库连接user表
	us.getTow(new HashMap());
  }
}

运行结果

-----------主数据库查询  -----------------
==>  Preparing: select * from user 
==> Parameters: 
<==    Columns: id, user
<==        Row: 1, username
<==        Row: 2, zht
<==      Total: 2
-----------子数据库查询  -----------------
==>  Preparing: select * from user 
==> Parameters: 
<==    Columns: id, name
<==        Row: 1, 数据库2
<==      Total: 1

MyBatis缓存 ehcache设置

MyBatis为了提高数据库的使用效率,我们通常会使用到二级缓存,通过二级缓存来操作常用的业务数来达到减轻数据库压力提高效率。java中现在有大量的缓存框架,我们选择ehcache是应为它非常的成熟,和MyBatis结合的度是最好的,最最最重要的是它操作特别简单,基本可以一看就会很容易上手,实际项目使用起来非常方便。

pom.xml

  <dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.2.1</version>
  </dependency>

在需要使用缓存的 MyBatis业务sql.xml 中写入 ehcache 缓存配置xml元素。缓存分为两种,1普通缓存EhcacheCache,2阻塞缓存 EhBlockingCache。

  • org.mybatis.caches.ehcache.EhcacheCache 普通缓存

  • org.mybatis.caches.ehcache.EhBlockingCache 阻塞缓存

UserSql.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="cn.core.my.app.dao.UserDao">
 <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
  <select id="addlist" resultType="map">
     select * from user
  </select>           
</mapper>

MyBatis业务sql.xml 中默认设置, 这样就可以简单的声明缓存了。

缓存应用于每个语句

  • 一旦在 xml 中声明了缓存,缓存将应用于 xml 中的所有sql语句。
  • 如果不想使用缓存,在语句上添加 useCache=“false” 作为元素属性。
<!-- 如果不想使用缓存,简单的设置一下 useCache="false" --> 
<select id="addlist" resultType="map" useCache="false">
     select * from user
 </select>
<!-- 不设置useCache="false" 操作的数据信息将保持在缓存中 -->
<insert id="saveuser">
INSERT INTO user(id, user)
    VALUES(#{id}, #{name})
</insert>

ehcache 缓存池大小设置

<!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.core.my.app.dao.UserDao">
 <cache type="org.mybatis.caches.ehcache.EhcacheCache">
    <property name="timeToIdleSeconds" value="3600"/>
    <property name="timeToLiveSeconds" value="3600"/>
    <property name="maxEntriesLocalHeap" value="10000"/>
    <property name="maxEntriesLocalDisk" value="10000000"/>
    <property name="memoryStoreEvictionPolicy" value="LRU"/>
  </cache>

一般在中小型项目中以上的缓存池配置基本可以满足业务需求,在常用的业务 sql.xml中加入以下配置就可以了。

参数列表

名称 内容
timeToIdleSeconds 设定允许对象处于空闲状态的最长时间
timeToLiveSeconds 设定对象允许存在于缓存中的最长时间
maxEntriesLocalHeap 缓存可以在本地堆内存中使用的最大缓存条目
maxEntriesLocalDisk 独立缓存可以在本地磁盘上使用的最大缓存条目
memoryStoreEvictionPolicy 当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)

数据连接池设置

我们使用阿里的druid作为数据连接池,阿里的东西不用说做的真的很强,易用性非常的好,而且功能强大我用过那么多的数据池,它的综合性价比是最高的,而且上手成本非常的低,只要yml文件配对了数据池就可用,它的学习和维护成本就在怎么配置yml中的对应参数。

pom.xml

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

数据池 application.yml 中的层级

  • 全局数据池设置,与datasource下的dynamic元素同级为全局数据池
  • 独立的数据库连接池设置,在多数据源的数据库连接下面设置自己独立的数据连接池,这个池只能这个个对应的数据自己使用

全局池层级关系

spring:
  datasource:
    dynamic:
    type: com.alibaba.druid.pool.DruidDataSource
    druid://与dynamic同级别 表示是全局数据池所有数据源使用

独立池层级关系

spring:
  datasource:
    dynamic:
      primary: master
      strict: false
      datasource:
        主数据库:
            type: com.alibaba.druid.pool.DruidDataSource
            druid://单独的数据连接池设置
        子数据库:
            type: com.alibaba.druid.pool.DruidDataSource
    		druid://单独的数据连接池设置

数据池 application.yml 中的设置

全局池例子

server:
  port: 8888
spring:
  datasource:
    dynamic:
      primary: master
      strict: false
      datasource:
        master:
          url: jdbc:mysql://localhost:3306/systext?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver 
        zht:
          url: jdbc:mysql://localhost:3306/zhtsys?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver 
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
        initial-size: 10
        max-active: 100
        min-idle: 10
        max-wait: 60000
        pool-prepared-statements: true
        max-pool-prepared-statement-per-connection-size: 20
        time-between-eviction-runs-millis: 60000
        min-evictable-idle-time-millis: 300000           
mybatis:
  mapperLocations: classpath*:/mapper/*.xml
  configuration: 
   log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  • type 元素表示连接的数据池驱动,如果是其他池下面的标签就换成对应池的元素标签

个数据库的独立池例子

server:
  port: 8888
spring:
  datasource:
    dynamic:
      primary: master
      strict: false
      datasource:
        master:
          url: jdbc:mysql://localhost:3306/systext?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver 
          type: com.alibaba.druid.pool.DruidDataSource
          druid:
            initial-size: 10
            max-active: 100
            min-idle: 10
            max-wait: 60000
            pool-prepared-statements: true
            max-pool-prepared-statement-per-connection-size: 20
            time-between-eviction-runs-millis: 60000
            min-evictable-idle-time-millis: 300000  
        zht:
          url: jdbc:mysql://localhost:3306/zhtsys?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver 
          type: com.alibaba.druid.pool.DruidDataSource
          druid:
            initial-size: 10
            max-active: 100
            min-idle: 10
            max-wait: 60000
            pool-prepared-statements: true
            max-pool-prepared-statement-per-connection-size: 20
            time-between-eviction-runs-millis: 60000
            min-evictable-idle-time-millis: 300000           
mybatis:
  mapperLocations: classpath*:/mapper/*.xml
  configuration: 
   log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

druid 配置参数

属性 说明 备注
initialSize 启动程序时,在连接池中初始化多少个连接 100
maxActive 连接池中最多支持多少个活动会话
maxWait 程序向连接池中请求连接时,超过maxWait的值后,认为本次请求失败,即连接池没有可用连接,单位毫秒,设置-1时表示无限等待 100
minEvictableIdleTimeMillis 池中某个连接的空闲时长达到 N 毫秒后, 连接池在下次检查空闲连接时,将回收该连接,要小于防火墙超时设置net.netfilter.nf_conntrack_tcp_timeout_established的设置
timeBetweenEvictionRunsMillis 检查空闲连接的频率,单位毫秒, 非正整数时表示不进行检查
keepAlive 程序没有close连接且空闲时长超过 minEvictableIdleTimeMillis,则会执行validationQuery指定的SQL,以保证该程序连接不会池kill掉,其范围不超过minIdle指定的连接个数。 true
minIdle 回收空闲连接时,将保证至少有minIdle个连接. 与initialSize相同
removeAbandoned 要求程序从池中get到连接后, N 秒后必须close,否则druid 会强制回收该连接,不管该连接中是活动还是空闲, 以防止进程不会进行close而霸占连接。 当发现程序有未正常close连接时设置为true
removeAbandonedTimeout 设置druid 强制回收连接的时限,当程序从池中get到连接开始算起,超过此值后,druid将强制回收该连接,单位秒。 应大于业务运行最长时间
logAbandoned 当druid强制回收连接后,是否将stack trace 记录到日志中 true
testWhileIdle 当程序请求连接,池在分配连接时,是否先检查该连接是否有效。(高效) true
validationQuery 检查池中的连接是否仍可用的 SQL 语句,drui会连接到数据库执行该SQL, 如果
testOnBorrow 程序 申请 连接时,进行连接有效性检查(低效,影响性能) false
testOnReturn 程序 返还 连接时,进行连接有效性检查(低效,影响性能) false
poolPreparedStatements 缓存通过以下两个方法发起的SQL
maxPoolPrepareStatementPerConnectionSize 每个连接最多缓存多少个SQL 20
connectProperties 连接属性。比如设置一些连接池统计方面的配置。

druid 是个功能很强大的数据池,提供很多其他功能如果有需要加入其他功能的可以参考一下,下面中的配置内容。

server:
  port: 8888
spring:
  datasource:
    dynamic:
      primary: master
      strict: false
      datasource:
        master:
          url: jdbc:mysql://localhost:3306/systext?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver 
        zht:
          url: jdbc:mysql://localhost:3306/zhtsys?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver 
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      # 连接池的配置信息
      # 初始化大小,最小,最大
      initial-size: 5
      min-idle: 5
      maxActive: 20
      # 配置获取连接等待超时的时间
      maxWait: 60000
      # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
      timeBetweenEvictionRunsMillis: 60000
      # 配置一个连接在池中最小生存的时间,单位是毫秒
      minEvictableIdleTimeMillis: 300000
      validationQuery: SELECT 1
      testWhileIdle: true
      testOnBorrow: false
      testOnReturn: false
      # 打开PSCache,并且指定每个连接上PSCache的大小
      poolPreparedStatements: true
      maxPoolPreparedStatementPerConnectionSize: 20
      # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
      filters: stat,wall,slf4j
      # 通过connectProperties属性来打开mergeSql功能;慢SQL记录
      connectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000
      # 配置DruidStatFilter
      web-stat-filter:
        url-pattern: "/*"
        exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"
      # 配置DruidStatViewServlet
      stat-view-servlet:
        enabled: true
        url-pattern: "/druid/*"
        # IP白名单(没有配置或者为空,则允许所有访问)
        allow: 127.0.0.1,192.168.3.25
        # IP黑名单 (存在共同时,deny优先于allow)
        #        deny: localhost
        #  禁用HTML页面上的“Reset All”功能
        reset-enable: false
        # 登录名
        login-username: admin
        # 登录密码
        login-password: 123456         
mybatis:
  mapperLocations: classpath*:/mapper/*.xml
  configuration: 
   log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
上一篇:Apache Druid 简介


下一篇:sharding+druid连接dm8方式说明