Spring Boot 中使用 MyBatis 整合 Druid 多数据源
Spring Boot 中使用 MyBatis 整合 Druid 多数据源
本文将讲述 spring boot + mybatis + druid 多数据源配置方案。
环境
CentOs7.3 安装 MySQL 5.7.19 二进制版本
Github 代码
代码我已放到 Github ,导入spring-boot-mybatis 项目
github github.com/souyunku/sp…
添加依赖
在项目中添加 mybatis,druid 依赖
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
省略 更多
基础数据源
@Configuration
@EnableConfigurationProperties(DruidDbProperties.class)
@Import({DruidMonitConfig.class})
public abstract class AbstractDruidDBConfig {
private Logger logger = LoggerFactory.getLogger(AbstractDruidDBConfig.class);
@Resource
private DruidDbProperties druidDbProperties;
public DruidDataSource createDataSource(String url, String username, String password) {
if (StringUtils.isEmpty(url)) {
System.out.println(
"Your database connection pool configuration is incorrect!" + " Please check your Spring profile");
throw new ApplicationContextException("Database connection pool is not configured correctly");
}
DruidDataSource datasource = new DruidDataSource();
datasource.setUrl(url);
datasource.setUsername(username);
datasource.setPassword(password);
// datasource.setDriverClassName(
// StringUtils.isEmpty(driverClassName) ?
// druidDbProperties.getDriverClassName() : driverClassName);
datasource.setInitialSize(druidDbProperties.getInitialSize());
datasource.setMinIdle(druidDbProperties.getMinIdle());
datasource.setMaxActive(druidDbProperties.getMaxActive());
datasource.setMaxWait(druidDbProperties.getMaxWait());
datasource.setTimeBetweenEvictionRunsMillis(druidDbProperties.getTimeBetweenEvictionRunsMillis());
datasource.setMinEvictableIdleTimeMillis(druidDbProperties.getMinEvictableIdleTimeMillis());
datasource.setValidationQuery(druidDbProperties.getValidationQuery());
datasource.setTestWhileIdle(druidDbProperties.isTestWhileIdle());
datasource.setTestOnBorrow(druidDbProperties.isTestOnBorrow());
datasource.setTestOnReturn(druidDbProperties.isTestOnReturn());
try {
datasource.setFilters(druidDbProperties.getFilters());
} catch (SQLException e) {
logger.error("druid configuration initialization filter", e);
}
datasource.setConnectionProperties(druidDbProperties.getConnectionProperties());
return datasource;
}
/**
* 加载默认mybatis xml配置文件,并初始化分页插件
*
* @param dataSource
* @return
* @throws Exception
*/
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
return createSqlSessionFactory(dataSource, "classpath:mybatis/**/*.xml");
}
/**
* 加载mybatis xml配置文件,并初始化分页插件
*
* @param dataSource 数据源
* @param mapperLocations 自定义xml配置路径
* @return
* @throws Exception
*/
public SqlSessionFactory sqlSessionFactory(DataSource dataSource, String mapperLocations) throws Exception {
return createSqlSessionFactory(dataSource, mapperLocations);
}
private SqlSessionFactory createSqlSessionFactory(DataSource dataSource, String mapperLocations) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
// mybatis分页
PageHelper pageHelper = new PageHelper();
Properties props = new Properties();
props.setProperty("dialect", "mysql");
props.setProperty("reasonable", "true");
props.setProperty("supportMethodsArguments", "true");
props.setProperty("returnPageInfo", "check");
props.setProperty("params", "count=countSql");
pageHelper.setProperties(props); // 添加插件
sqlSessionFactoryBean.setPlugins(new Interceptor[]{pageHelper});
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
sqlSessionFactoryBean.setMapperLocations(resolver.getResources(mapperLocations));
return sqlSessionFactoryBean.getObject();
}
}
Druid 监控配置
@EnableConfigurationProperties(DruidDbProperties.class)
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class DruidMonitConfig {
@Resource
private DruidDbProperties druidDbProperties;
@Bean
public ServletRegistrationBean druidServlet() {
ServletRegistrationBean reg = new ServletRegistrationBean();
reg.setServlet(new StatViewServlet());
reg.addUrlMappings("/druid/*");
if (!StringUtils.isEmpty(druidDbProperties.getAllow())) {
reg.addInitParameter("allow", druidDbProperties.getAllow()); // 白名单
}
if (!StringUtils.isEmpty(druidDbProperties.getDeny())) {
reg.addInitParameter("deny", druidDbProperties.getDeny()); // 黑名单
}
reg.addInitParameter("loginUsername", druidDbProperties.getUsername());
reg.addInitParameter("loginPassword", druidDbProperties.getPassword());
return reg;
}
@Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new WebStatFilter());
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
return filterRegistrationBean;
}
/**
* 监听Spring 1.定义拦截器 2.定义切入点 3.定义通知类
*
* @return
*/
@Bean
public DruidStatInterceptor druidStatInterceptor() {
return new DruidStatInterceptor();
}
@Bean
public JdkRegexpMethodPointcut druidStatPointcut() {
JdkRegexpMethodPointcut druidStatPointcut = new JdkRegexpMethodPointcut();
String patterns = "io.ymq.mybatis*";
druidStatPointcut.setPatterns(patterns);
return druidStatPointcut;
}
@Bean
public Advisor druidStatAdvisor() {
return new DefaultPointcutAdvisor(druidStatPointcut(), druidStatInterceptor());
}
}
Druid 监控参数
@ConfigurationProperties(prefix = "druid")
public class DruidDbProperties {
private String driverClassName = "com.mysql.jdbc.Driver";
/**
* 初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时
*/
private int initialSize = 10;
/**
* 最小连接池数量
*/
private int minIdle = 50;
/**
* 最大连接池数量
*/
private int maxActive = 300;
/**
* 获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。
*/
private int maxWait = 60000;
/**
* 有两个含义: 1)
* Destroy线程会检测连接的间隔时间,如果连接空闲时间大于等于minEvictableIdleTimeMillis则关闭物理连接。 2)
* testWhileIdle的判断依据,详细看testWhileIdle属性的说明
*/
private int timeBetweenEvictionRunsMillis = 60000;
/**
* 连接保持空闲而不被驱逐的最长时间
*/
private int minEvictableIdleTimeMillis = 3600000;
/**
* 用来检测连接是否有效的sql,要求是一个查询语句,常用select
* 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会其作用。
*/
private String validationQuery = "SELECT USER()";
/**
* 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
*/
private boolean testWhileIdle = true;
/**
* 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
*/
private boolean testOnBorrow = false;
/**
* 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
*/
private boolean testOnReturn = false;
/**
* 属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有: 监控统计用的filter:stat 日志用的filter:log4j
* 防御sql注入的filter:wall
*/
private String filters = "mergeStat,config,wall";
private String connectionProperties;
/**
* 白名单
*/
private String allow;
/**
* 黑名单
*/
private String deny;
private String username = "admin";
private String password = "admin";
省略 get set
}
配置数据源 one
@Configuration
@EnableTransactionManagement
public class DBOneConfiguration extends AbstractDruidDBConfig {
@Value("${ymq.one.datasource.url}")
private String url;
@Value("${ymq.one.datasource.username}")
private String username;
@Value("${ymq.one.datasource.password}")
private String password;
// 注册 datasourceOne
@Bean(name = "datasourceOne", initMethod = "init", destroyMethod = "close")
public DruidDataSource dataSource() {
return super.createDataSource(url, username, password);
}
@Bean(name = "sqlSessionFactorYmqOne")
public SqlSessionFactory sqlSessionFactory() throws Exception {
return super.sqlSessionFactory(dataSource());
}
@Bean
public PlatformTransactionManager transactionManager() throws SQLException {
return new DataSourceTransactionManager(dataSource());
}
}
配置数据源 two
@Configuration
@EnableTransactionManagement
public class DBOneConfiguration extends AbstractDruidDBConfig {
@Value("${ymq.one.datasource.url}")
private String url;
@Value("${ymq.one.datasource.username}")
private String username;
@Value("${ymq.one.datasource.password}")
private String password;
// 注册 datasourceOne
@Bean(name = "datasourceOne", initMethod = "init", destroyMethod = "close")
public DruidDataSource dataSource() {
return super.createDataSource(url, username, password);
}
@Bean(name = "sqlSessionFactorYmqOne")
public SqlSessionFactory sqlSessionFactory() throws Exception {
return super.sqlSessionFactory(dataSource());
}
@Bean
public PlatformTransactionManager transactionManager() throws SQLException {
return new DataSourceTransactionManager(dataSource());
}
}
BaseDao one
@Repository
public class YmqOneBaseDao extends BaseDao {
@Resource
public void setSqlSessionFactorYmqOne(SqlSessionFactory sqlSessionFactory) {
super.setSqlSessionFactory(sqlSessionFactory);
}
}
BaseDao two
@Repository
public class YmqTwoBaseDao extends BaseDao {
@Resource
public void setSqlSessionFactorYmqTwo(SqlSessionFactory sqlSessionFactory) {
super.setSqlSessionFactory(sqlSessionFactory);
}
}
测试 Controller
@RestController
public class IndexController {
private static final Logger LOG = LoggerFactory.getLogger(IndexController.class);
@Autowired
private YmqOneBaseDao ymqOneBaseDao;
@Autowired
private YmqTwoBaseDao ymqTwoBaseDao;
@RequestMapping("/")
public String index() throws Exception {
List<TestOnePo> testOnePoList = null;
testOnePoList = ymqOneBaseDao.selectList(new TestOnePo());
for (TestOnePo item : testOnePoList) {
LOG.info("数据源 ymqOneBaseDao :查询结果:{}", JSONObject.toJSONString(item));
}
List<TestTwoPo> testTwoPoList = null;
testTwoPoList = ymqTwoBaseDao.selectList(new TestTwoPo());
for (TestTwoPo item : testTwoPoList) {
LOG.info("数据源 ymqTwoBaseDao:查询结果:{}", JSONObject.toJSONString(item));
}
String onePoList = JSONObject.toJSONString(testOnePoList);
String twoPoList = JSONObject.toJSONString(testTwoPoList);
return "数据源 ymqOneBaseDao :查询结果:" + onePoList + "<br/> 数据源 ymqTwoBaseDao :查询结果:" + twoPoList;
}
}
参数配置
application.properties
#############SERVER CONFIG############
spring.application.name=ymq-mybatis-spring-boot
#数据源 one
ymq.one.datasource.url=jdbc:mysql://10.4.82.6:3306/ymq_one?useUnicode=true&characterEncoding=UTF-8
ymq.one.datasource.username=root
ymq.one.datasource.password=123456
#数据源 two
ymq.two.datasource.url=jdbc:mysql://10.4.82.6:3306/ymq_two?useUnicode=true&characterEncoding=UTF-8
ymq.two.datasource.username=root
ymq.two.datasource.password=123456
server.port=80
server.tomcat.max-threads=1000
server.tomcat.max-connections=2000
启动服务
@SpringBootApplication
@ComponentScan(value = {"io.ymq.mybatis"})
public class Startup {
public static void main(String[] args) {
SpringApplication.run(Startup.class, args);
}
}
在页面上输入 http://localhost/ 可以看到 Controller 执行情况:
数据源 ymqOneBaseDao :查询结果:[{"id":1,"name":"测试","remark":"这是测试 ymq_one 数据库"}]
数据源 ymqTwoBaseDao :查询结果:[{"id":1,"name":"测试","remark":"这是测试 ymq_two 数据库"}]
在页面上输入 http://localhost/druid/ 可以看到监控到的sql语句执行情况:

Spring Boot 中使用 MyBatis 整合 Druid 多数据源的更多相关文章
- Spring Boot中使用MyBatis注解配置详解(1)
之前在Spring Boot中整合MyBatis时,采用了注解的配置方式,相信很多人还是比较喜欢这种优雅的方式的,也收到不少读者朋友的反馈和问题,主要集中于针对各种场景下注解如何使用,下面就对几种常见 ...
- Spring Boot中使用Mybatis
一.步骤 导入依赖:MySQL驱动.Druid依赖.MyBatis与Spring Boot整合依赖.Lombok依赖 在Service接口实现类上添加@Service注解 在Dao接口上添加@Mapp ...
- spring boot中使用mybatis的注意点!!!
1 生成的mapper接口上打上注解 2 在pom.xml中需要导入mysql(根据需要),jdbc和mybatis的依赖 3 在主类上设置扫描 4 com.mysql.cj.exceptions等报 ...
- Spring Boot中使用MyBatis注解配置详解
传参方式 下面通过几种不同传参方式来实现前文中实现的插入操作. 使用@Param 在之前的整合示例中我们已经使用了这种最简单的传参方式,如下: @Insert("INSERT INTO US ...
- Spring Boot 学习笔记(六) 整合 RESTful 参数传递
Spring Boot 学习笔记 源码地址 Spring Boot 学习笔记(一) hello world Spring Boot 学习笔记(二) 整合 log4j2 Spring Boot 学习笔记 ...
- Spring Boot中整合Sharding-JDBC单库分表示例
本文是Sharding-JDBC采用Spring Boot Starter方式配置第二篇,第一篇是读写分离讲解,请参考:<Spring Boot中整合Sharding-JDBC读写分离示例> ...
- Spring Boot中MyBatis的使用
orm框架的本质是简化编程中操作数据库的编码,发展到现在基本上就剩两家了,一个是宣称可以不用写一句SQL的hibernate,一个是可以灵活调试动态sql的mybatis,两者各有特点,在企业级系统开 ...
- 【spring boot】【mybatis】spring boot中mybatis打印sql语句
spring boot中mybatis打印sql语句,怎么打印出来?[参考:https://www.cnblogs.com/sxdcgaq8080/p/9100178.html] 在applicati ...
- Spring Boot 中 Druid 的监控页面配置
Druid的性能相比HikariCp等其他数据库连接池有一定的差距,但是数据库的相关属性的监控,别的连接池可能还追不上,如图: 今天写一下 Spring Boot 中监控页面的配置,我是直接将seat ...
随机推荐
- Java容器之List接口
List 接口: 1. List 接口是 Collection 的子接口,实现 List 接口的容器类中的元素是有顺序的,而且可以重复: 2. List 容器中的元素都对应一个整数型的序号记载其在容器 ...
- bootstrap控件点击之后没有反应的原因
引用的jquery.js文件要放到bootstrap.js的前面 jquery.js文件版本太低. 这些问题可以通过firebug或者谷歌调试器发现. 问题很简单,简单记录下,以免以后遗忘.
- C# Find()和First()与FirstOrDefault(
1. Find方法只能在List<T>上使用,而后者能更广泛应用在IEnemerable<T>上. Find最终是建立在Array的查找之上,而在IEnemerable上的Fi ...
- [STAThread] 作用
[STAThread]是一种线程模型,用在程序的入口方法上(在C#和VB.NET里是Main()方法),来指定当前线程的ApartmentState 是STA. [STAThread]是声明开始线程用 ...
- docker使用记录
1.安装(开始前要注意系统内核版本是否合适,建议用7以上的系统吧,少点坑) //安装docker yum -y install docker-io //启动 service docker start ...
- SpringBoot Web(SpringMVC)
入门工程: package com.example.demo.controller; import com.example.demo.entity.User; import org.springfra ...
- 【bzoj1036】[ZJOI2008]树的统计Count 树链剖分+线段树
题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v ...
- [WC2005]双面棋盘
description 洛谷 给出一个\(n\times n\)的黑白棋盘. \(m\)次操作,每次将一个格子进行颜色翻转,求每次操作后的黑白四连通块数. data range \[n\le 200, ...
- BZOJ1858:[SCOI2010]序列操作——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=1858 lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于 ...
- HDOJ.1070 Milk(贪心)
Milk 点我挑战题目 题意分析 每组测试数据给出一系列牛奶商品,分别是牛奶的品牌,价格,以及体积.在读取数据的时候,体积在200以下的牛奶直接忽略掉.并且每天要喝200ML的牛奶.但是无论牛奶体积有 ...