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. .net Mvc4 View—布局页与分部页

    ▲      一.Layout属性     1.1.@RenderPage():渲染制定的页面到占位符.     注意:@RenderPage()可以使用多次,这点与@RenderBody()不同   ...

  2. lol人物模型提取(三)

      提取出来的lol人物模型能让你知道一些有趣的信息,比如说给英雄量个身高啥的.   经测量,佐伊的身高应大于1m60,比想象中的着实高不少啊.   然后还应该把这个模型镜像对称一下,在3dsmax里 ...

  3. .NET环境下,通过LINQ操作SQLite数据库

    //对应数据库中的某个表 [Table(Name = "main.Student")]    public class Student    {        [Column(Na ...

  4. QT分析之消息事件机制

    原文地址:http://blog.163.com/net_worm/blog/static/127702419201001432028526/ 上回我们分析到QPushButton的初始化,知道了Wi ...

  5. android eclipse 添加libs文件夹

    导入一个项目发现没有libs文件夹,后来z自己新建了个lib文件夹,但是总是不行,后来发现错了,应该是libs文件夹.建完了之后,系统会自动在build path中把这个文件夹添加进来的:个人无须操作

  6. 【.Net】Visual Studio的调试技巧

    这是我写的关于VS2010和.Net4发布的博客系列的第26篇. 今天的博文包含了一些有用的能用于VS的调试技巧. 我的朋友Scott Cate(他写了很多很好的关于VS使用技巧和窍门的博客)最近向我 ...

  7. Activiti5工作流笔记一

    介绍工作流 网上工作流的定义一大堆,这里就不去复制了,通俗的理解,工作流就是类似OA系统中请假审批.报销审批等一系列流程,下级提交的申请只有直系领导才能审批,其他人是没有权限的,而只有直系领导审批通过 ...

  8. 【bzoj1616】[Usaco2008 Mar]Cow Travelling游荡的奶牛 bfs

    题目描述 奶牛们在被划分成N行M列(2 <= N <= 100; 2 <= M <= 100)的草地上游走,试图找到整块草地中最美味的牧草.Farmer John在某个时刻看见 ...

  9. BZOJ4850/BZOJ2216 JSOI2016灯塔/Poi2011Lightning Conductor(决策单调性)

    即对每个i最大化hj-hi+sqrt(|i-j|).先把绝对值去掉,正反各做一次即可.注意到当x>y时,sqrt(x+1)-sqrt(x)<sqrt(y+1)-sqrt(y),所以若对于i ...

  10. lalala

    <script type="text/javascript"> var a_idx = 0; var b_idx = 0; var a = new Array(&quo ...