介绍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