2017 年 10 月 20 日
 

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 依赖

点击预览 pom.xml

<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 多数据源的更多相关文章

  1. Spring Boot中使用MyBatis注解配置详解(1)

    之前在Spring Boot中整合MyBatis时,采用了注解的配置方式,相信很多人还是比较喜欢这种优雅的方式的,也收到不少读者朋友的反馈和问题,主要集中于针对各种场景下注解如何使用,下面就对几种常见 ...

  2. Spring Boot中使用Mybatis

    一.步骤 导入依赖:MySQL驱动.Druid依赖.MyBatis与Spring Boot整合依赖.Lombok依赖 在Service接口实现类上添加@Service注解 在Dao接口上添加@Mapp ...

  3. spring boot中使用mybatis的注意点!!!

    1 生成的mapper接口上打上注解 2 在pom.xml中需要导入mysql(根据需要),jdbc和mybatis的依赖 3 在主类上设置扫描 4 com.mysql.cj.exceptions等报 ...

  4. Spring Boot中使用MyBatis注解配置详解

    传参方式 下面通过几种不同传参方式来实现前文中实现的插入操作. 使用@Param 在之前的整合示例中我们已经使用了这种最简单的传参方式,如下: @Insert("INSERT INTO US ...

  5. Spring Boot 学习笔记(六) 整合 RESTful 参数传递

    Spring Boot 学习笔记 源码地址 Spring Boot 学习笔记(一) hello world Spring Boot 学习笔记(二) 整合 log4j2 Spring Boot 学习笔记 ...

  6. Spring Boot中整合Sharding-JDBC单库分表示例

    本文是Sharding-JDBC采用Spring Boot Starter方式配置第二篇,第一篇是读写分离讲解,请参考:<Spring Boot中整合Sharding-JDBC读写分离示例> ...

  7. Spring Boot中MyBatis的使用

    orm框架的本质是简化编程中操作数据库的编码,发展到现在基本上就剩两家了,一个是宣称可以不用写一句SQL的hibernate,一个是可以灵活调试动态sql的mybatis,两者各有特点,在企业级系统开 ...

  8. 【spring boot】【mybatis】spring boot中mybatis打印sql语句

    spring boot中mybatis打印sql语句,怎么打印出来?[参考:https://www.cnblogs.com/sxdcgaq8080/p/9100178.html] 在applicati ...

  9. Spring Boot 中 Druid 的监控页面配置

    Druid的性能相比HikariCp等其他数据库连接池有一定的差距,但是数据库的相关属性的监控,别的连接池可能还追不上,如图: 今天写一下 Spring Boot 中监控页面的配置,我是直接将seat ...

随机推荐

  1. OSG学习:响应键盘鼠标示例

    示例功能:示例里面有两个模型,一个是牛,另一个是飞机.鼠标右键时牛和飞机都隐藏,鼠标左键双击时牛和飞机都显示,按键盘上面的LEFT键,显示牛,按键盘上面的RIGHT键显示飞机.其中显示与隐藏节点使用的 ...

  2. ErrorUnable to tunnel through proxy. Proxy returns HTTP1.1 400 Bad Reques

    导入项目的时候,一般会出现这种错误,因为我们的gradle版本,不对,所以默认AS导入后,回去下载你需要的gradle,所以很慢, 先打开:项目路径底下的\gradle\wrapper\gradle- ...

  3. [STL] vector基本用法

    vector的数据安排以及操作方式,与array非常相似.两者的唯一区别在于空间的运用的灵活性.array是静态空间,一旦配置了就不能改变.vector是动态空间,随着元素的加入,它的内部机制会自行扩 ...

  4. Delphi开发的一些技巧

    [Delphi]Delphi开发的一些技巧 一.提高查询效率先进行准备查询操作: CustomerQuery.Close; if not (CustomerQuery.Prepared) then - ...

  5. matlab edge

    edge在matlab中用来进行边缘检测BW = edge(I) 采用灰度或一个二值化图像I作为它的输入,并返回一个与I相同大小的二值化图像BW,在函数检测到边缘的地方为1,其他地方为0. BW = ...

  6. Codeforces VK Cup 2015 A.And Yet Another Bracket Sequence(后缀数组+平衡树+字符串)

    这题做得比较复杂..应该有更好的做法 题目大意: 有一个括号序列,可以对其进行两种操作: ·        向里面加一个括号,可以在开头,在结尾,在两个括号之间加. ·        对当前括号序列进 ...

  7. WIN7系统插入蓝牙适配器经常断开问题

    WIN7 ACER笔记本一台,蓝牙耳机一个,10块钱的蓝牙适配器一个 目的:可以在笔记本上用适配器与蓝牙耳机匹配 出现问题:1.有2个图标,一会左边感叹号,一会右边感叹号,必须有个存在感叹号 解决:第 ...

  8. Vue推荐资料

    推荐博文(我是看过,才敢说的偶): 基础教学: 菜鸟语法教程:https://cn.vuejs.org/v2/guide/syntax.html  http://www.runoob.com/vue2 ...

  9. Consul入门

    推荐: Consul 原理和使用简介 启动:consul agent -server -bootstrap-expect 1 -data-dir /tmp/consul -node Litao-Mac ...

  10. JavaScript in 操作符

    JavaScript的in操作符可以用来判断一个属性是否属于一个对象,也可以用来变量一个对象的属性 1. 判断属性属于对象 var mycar = {make: "Honda", ...