SpringBoot2 + Druid + Mybatis 多数据源动态配置
在大数据高并发的应用场景下,为了更快的响应用户请求,读写分离是比较常见的应对方案。读写分离会使用多数据源的使用。下面记录如何搭建SpringBoot2 + Druid + Mybatis 多数据源配置以及在使用过程遇到的问题。
一、先从pom.xml入手(使用springboot 2的版本)
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.17</version>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
</dependencies>
inject是java依赖注入标准。spring默认支持识别。spring自带的@Autowired的缺省情况等价于JSR-330的@Inject注解;@Qualifier的缺省的根据Bean名字注入情况等价于JSR-330的@Named注解。
二、添加读取DB的Mapper
@Mapper
public interface AssetMapper { @Select("select * from Asset where account = #{account}")
Asset queryName(String account);
}
此处使用mybatis的注解功能,因此可以少省去*.xml等配置文件。
三、添加多数据源的配置参数
spring.datasource.druid.write.url=jdbc:mysql://192.168.0.110:3306/master?characterEncoding=utf-8&serverTimezone=Asia/Shanghai
spring.datasource.druid.write.username=root
spring.datasource.druid.write.password=123456
spring.datasource.druid.write.driver-class-name=com.mysql.cj.jdbc.Driver
#
spring.datasource.druid.read.url=jdbc:mysql://192.168.0.110:3306/slave1?characterEncoding=utf-8&serverTimezone=Asia/Shanghai
spring.datasource.druid.read.username=root
spring.datasource.druid.read.password=123456
spring.datasource.druid.read.driver-class-name=com.mysql.cj.jdbc.Driver 新版本mysql的url后面必需要添加serverTimezone=。 不然会报以下异常:
2019-06-05 18:47:24.058 ERROR 17804 --- [-Create-6910184] com.alibaba.druid.pool.DruidDataSource : create connection SQLException, url: jdbc:mysql://localhost:3306/master, errorCode 0, state 01S00 java.sql.SQLException: The server time zone value '�й���ʱ��' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support.
四、配置数据源
@Configuration
public class DataSourceConfig { @Bean(name = "masterDataSource")
@ConfigurationProperties(prefix = "spring.datasource.druid.write")
@Primary
public DataSource masterDataSource() {
return DruidDataSourceBuilder.create().build();
} @Bean(name = "slaveDataSource")
@ConfigurationProperties(prefix = "spring.datasource.druid.read")
public DataSource slaveDataSource() {
return DruidDataSourceBuilder.create().build();
} @Inject
@Named("masterDataSource")
private DataSource masterDataSource; @Inject
@Named("slaveDataSource")
private DataSource slaveDataSource; /**
* 根据数据源创建SqlSessionFactory
*/
@Bean
public SqlSessionFactory sqlSessionFactory(DynamicDataSource dataSource) throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
return sessionFactory.getObject();
}
}
SqlSessionFactory必需要重新创建,若不创建会报循环调用异常
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'masterDataSource': Requested bean is currently in creation: Is there an unresolvable circular reference?
因为SqlSessionFactory还是走默认创建的方式 。
上下文中如何得知使用那个数据源,可使用ThreadLocal来处理。
五、数据源路由
public class DataSourceContextRouting implements AutoCloseable {
static final ThreadLocal<String> dataSourceKeyThreadLocal = new ThreadLocal<>();
public String getDataSourceName(){
String key = dataSourceKeyThreadLocal.get();
return StringUtils.isBlank(key) ?"masterDataSource":key;
}
public DataSourceContextRouting(String key){
dataSourceKeyThreadLocal.set(key);
}
@Override
public void close() throws Exception {
dataSourceKeyThreadLocal.remove();
}
}
spring的提供动态源实现功能。只需要继承AbstractRoutingDataSource,并重写protected Object determineCurrentLookupKey()
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextRouting.getDataSourceName();
}
}
//此为核心代码
@Bean
public DynamicDataSource dataSource() {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put("masterDataSource", masterDataSource);
targetDataSources.put("slaveDataSource", slaveDataSource);
DynamicDataSource dataSource = new DynamicDataSource();
//设置数据源映射
dataSource.setTargetDataSources(targetDataSources);
//设置默认数据源,当无法映射到数据源时会使用默认数据源
dataSource.setDefaultTargetDataSource(slaveDataSource);
dataSource.afterPropertiesSet();
return dataSource;
}
六、controller路由切换
@RequestMapping("master")
public String master(String account){
String key = "masterDataSource";
new DataSourceContextRouting(key);
//TODO .....
}
@RequestMapping("slave")
public String slave(String account){
String key = "slaveDataSource";
new DataSourceContextRouting(key);
//TODO......
}
到此为止,整个多数据源配置完成了。
但这种对代码侵入比较多,可以使用注解的方式来处理。先定义注解标识
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TargetDataSource {
String value();
}
使用注解那需要对此进行解析切入,因此就需要用上spring AOP的功能。
首先添加maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
然后添加对其解析Aspect
@Aspect
@Named
public class DataSourceRoutingAspect {
@Around("@annotation(targetDataSource)")
public Object routingWithDataSource(ProceedingJoinPoint joinPoint, TargetDataSource targetDataSource) throws Throwable {
String key = targetDataSource.value();
try (DataSourceContextRouting ctx = new DataSourceContextRouting(key)) {
return joinPoint.proceed();
}
}
}
@RequestMapping("master")
@TargetDataSource("masterDataSource")
public String master(String account){
TODO:.....
}
@RequestMapping("slave")
@TargetDataSource("slaveDataSource")
public String slave(String account){
TODO:.....
}
SpringBoot2 + Druid + Mybatis 多数据源动态配置的更多相关文章
- Springboot+Mybatis+Pagehelper+Aop动态配置Oracle、Mysql数据源
本文链接:https://blog.csdn.net/wjy511295494/article/details/78825890 Springboot+Mybatis+Pagehelper+Aop ...
- springboot2.0+mybatis多数据源集成
最近在学springboot,把学的记录下来.主要有springboot2.0+mybatis多数据源集成,logback日志集成,springboot单元测试. 一.代码结构如下 二.pom.xml ...
- springboot2.1+redis多数据源的配置
springboot系列学习笔记全部文章请移步值博主专栏**: spring boot 2.X/spring cloud Greenwich. 由于是一系列文章,所以后面的文章可能会使用到前面文 ...
- spring-boot 速成(9) druid+mybatis 多数据源及读写分离的处理
按上节继续学习,稍微复杂的业务系统,一般会将数据库按业务拆开,比如产品系统的数据库放在product db中,订单系统的数据库放在order db中...,然后,如果量大了,可能每个库还要考虑做读.写 ...
- spring+mybatis多数据源动态切换
spring mvc+mybatis+多数据源切换 选取oracle,mysql作为例子切换数据源.oracle为默认数据源,在测试的action中,进行mysql和oracle的动态切换. web. ...
- Spring, MyBatis 多数据源的配置和管理
同一个项目有时会涉及到多个数据库,也就是多数据源.多数据源又可以分为两种情况: 1)两个或多个数据库没有相关性,各自独立,其实这种可以作为两个项目来开发.比如在游戏开发中一个数据库是平台数据库,其它还 ...
- 【转】Spring, MyBatis 多数据源的配置和管理
同一个项目有时会涉及到多个数据库,也就是多数据源.多数据源又可以分为两种情况: 1)两个或多个数据库没有相关性,各自独立,其实这种可以作为两个项目来开发.比如在游戏开发中一个数据库是平台数据库,其它还 ...
- mybatis 多数据源动态切换
笔者主要从事c#开发,近期因为项目需要,搭建了一套spring-cloud微服务框架,集成了eureka服务注册中心. gateway网关过滤.admin服务监控.auth授权体系验证,集成了redi ...
- spring boot druid mybatis多数据源
一.关闭数据源自动配置(很关键) @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }) 如果不关闭会报异常:o ...
随机推荐
- 混乱中的ICO平台,会不会是下一个P2P的重灾区?
当众多巨头和创业者还在为共享打车.共享单车.VR.IP化.互联网金融沉迷时,一种全新的"众筹"正在造就一个又一个暴富神话.其名为ICO,即首次代币众筹,一般指区块链初创项目在众筹平 ...
- 关于struct stat
需要使用struct stat 类型时如果编译不过,修改Makefile: ##CFG_INC := -I$(MPI_DIR)/api/so/##CFG_INC += -I$(BASE_DIR)/pu ...
- Fragment argument
每个Fragment实例都可以附带一个Bundle对象,该bundle包含键值对,可以像附加extra到Activity的intent中那样使用他们.一个键值对即一个argument. 创建frage ...
- AAAI |如何保证人工智能系统的准确性?
|如何保证人工智能系统的准确性?" title="AAAI |如何保证人工智能系统的准确性?"> 注:本文译自AI is getting smarter; ...
- Spring源码阅读笔记03:xml配置读取
前面的文章介绍了IOC的概念,Spring提供的bean容器即是对这一思想的具体实现,在接下来的几篇文章会侧重于探究这一bean容器是如何实现的.在此之前,先用一段话概括一下bean容器的基本工作原理 ...
- 【Art】抗疫路上,温暖相伴
2020年3月. 本应是春暖花开的时节,武汉却是寒冷的,整个中国也是寒冷的. 疫情将人们逼得退无可退,只能待在家里看着电视新闻与手机上一个个数字不断跳动,等待着它们背后前线的无数命悬一线的战士的胜利讯 ...
- 从头认识js-HTML中使用JavaScript
<script>元素 在HTML页面中插入Javascript的主要办法就是使用<script>元素,HTML4.01为<script>定义了下列6个属性. 1.a ...
- IAR软件使用的快捷键配置以及配置cc2530环境
以下是我对IAR软件使用的快捷键配置cc2530以及配置环境的总结,如下图所示 弹出保存窗口 工程生成完毕——生成.c文件 快捷键ctrl+s保存.c文件 选择 ...
- 【前端】这可能是你看过最全的css居中解决方案了~
1.水平居中:行内元素解决方案 适用元素:文字,链接,及其其它inline或者inline-*类型元素(inline-block,inline-table,inline-flex) html部分代码: ...
- leetcode 219
固定长度的滑动窗口+set class Solution { public: bool containsNearbyDuplicate(vector<int>& nums, int ...