【Spring Boot】Spring Boot之使用AOP实现数据库多数据源自动切换
一、添加maven坐标
<!-- aop -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- jdbc -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.</version>
</dependency>
二、加入Mybtis配置类(方便测试)
/**
* @author zhangboqing
* @date 2018/8/3
*
* Mybatis配置
*/
@Configuration
@MapperScan(basePackages = {"com.zbq.springbootdemo.dao"}, sqlSessionFactoryRef = "sqlSessionFactory")
//或者直接在Mapper类上面添加注解@Mapper,建议使用上面那种,不然每个mapper加个注解也挺麻烦的
public class MyBatisConfig { }
三、加入多数据源配置
1)修改application.yml添加数据库配置属性
spring:
datasource:
primary:
hikari:
connection-test-query: SELECT FROM DUAL
connection-timeout:
maximum-pool-size:
max-lifetime:
minimum-idle:
validation-timeout:
idle-timeout:
connection-init-sql: SET NAMES utf8mb4
jdbc-url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull
username: root
password:
driver-class-name: com.mysql.jdbc.Driver
secondary:
hikari:
connection-test-query: SELECT FROM DUAL
connection-timeout:
maximum-pool-size:
max-lifetime:
minimum-idle:
validation-timeout:
idle-timeout:
connection-init-sql: SET NAMES utf8mb4
jdbc-url: jdbc:mysql://localhost:3326/test?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull
username: root
password:
driver-class-name: com.mysql.jdbc.Driver
2)添加DataSourceConfig配置类(自定义DataSource数据源)
/**
* @author zhangboqing
* @date 2019-11-17
*/
@Configuration
// 自定义数据源一定要排除SpringBoot自动配置数据源,不然会出现循环引用的问题,The dependencies of some of the beans in the application context form a cycle
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
public class DataSourceConfig { @Bean(name = "primary")
@ConfigurationProperties(prefix = "spring.datasource.primary.hikari")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
} @Bean(name = "secondary")
@ConfigurationProperties(prefix = "spring.datasource.secondary.hikari")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
} /**
* 动态数据源
* 通过AOP+注解实现动态切换
*
* @return
*/
@Primary
@Bean(name = "dynamicDataSource")
public DataSource dataSource() {
DynamicDataSourceRouter dynamicDataSource = new DynamicDataSourceRouter();
// 默认数据源
dynamicDataSource.setDefaultTargetDataSource(primaryDataSource());
// 配置多数据源
Map<Object, Object> dataSourceMap = new HashMap();
dataSourceMap.put("primary", primaryDataSource());
dataSourceMap.put("secondary", secondaryDataSource());
dynamicDataSource.setTargetDataSources(dataSourceMap);
return dynamicDataSource;
} /**
* 配置@Transactional注解事物
*
* @return
*/
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
} }
/**
* @author zhangboqing
* @date 2019-11-17
*/
public class DynamicDataSourceRouter extends AbstractRoutingDataSource{
@Override
protected Object determineCurrentLookupKey() {
return DataSourceNameContextHolder.getDataSourceName();
} @Override
public void setLogWriter(PrintWriter pw) throws SQLException {
super.setLogWriter(pw);
}
}
3)定义 @DataSourceName注解(用于指定sql对应的数据源)
/**
* @author zhangboqing
* @date 2019-11-17
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface DataSourceName { /**
* 指定数据源名称
* @return dataSourceName
*/
String value() default "primary";
}
4)定义DataSourceNameContextHolder类(使用ThreadLocal存放当前线程持有的数据源名称)
/**
* @author zhangboqing
* @date 2019-11-17
*/
@Slf4j
public class DataSourceNameContextHolder { private static final ThreadLocal<String> dataSourceNameContextHolder = new NamedThreadLocal<>("DataSourceContext"); /** 默认数据源名称 */
public static final String DEFAULT_DATASOURCE_NAME = "primary"; public static void setDataSourceName(String dataSourceName) {
log.info("切换到[{}]数据源", dataSourceName);
dataSourceNameContextHolder.set(dataSourceName);
} public static String getDataSourceName() { return dataSourceNameContextHolder.get() != null ? dataSourceNameContextHolder.get() : DEFAULT_DATASOURCE_NAME;
} public static void resetDataSourceName() {
dataSourceNameContextHolder.remove();
}
}
5)定义DynamicDataSourceAspect切面类(通过AOP的方式拦截指定注解实现数据源切换)
/**
* @author zhangboqing
* @date 2019-11-17
*/
@Aspect
@Component
public class DynamicDataSourceAspect { @Before("@annotation(dataSourceName)")
public void beforeSwitchDataSource(DataSourceName dataSourceName){
// 切换数据源
DataSourceNameContextHolder.setDataSourceName(dataSourceName.value());
} @After("@annotation(com.zbq.springbootdemo.config.multidatasource.DataSourceName)")
public void afterSwitchDataSource(){
DataSourceNameContextHolder.resetDataSourceName();
}
}
四、添加测试
1)在Mybtis配置类指定的包下定义一个Dao类并使用注解指定数据源
/**
* @author zhangboqing
* @date 2019-11-21
*/
@Repository
public interface UserDao { @DataSourceName("secondary")
@Select("select * from user order by create_time desc limit 1 ")
public User getNewstOne(); // 默认是primary,所以可以不指定
// @DataSourceName("primary")
@Select("select * from user order by create_time desc limit 1 ")
public User getNewstOne2();
}
2)定义测试类执行
/**
* @author zhangboqing
* @date 2019-11-21
*/
@SpringBootTest
@Slf4j
class UserServiceImplTest { @Autowired
private UserDao userDao; @Test
void getNewestOne() {
User newestOne = userDao.getNewstOne();
User newestOne2 = userDao.getNewstOne2();
log.info(newestOne.toString());
log.info(newestOne2.toString());
}
}
3)执行结果可知多数据源生效,同样的sql查询结果分别来自于两个库
-- ::51.124 INFO --- [ main] c.z.s.service.UserServiceImplTest : User(uid=, phone=, createTime=null, updateTime=null)
-- ::51.124 INFO --- [ main] c.z.s.service.UserServiceImplTest : User(uid=, phone=, createTime=null, updateTime=null)
【Spring Boot】Spring Boot之使用AOP实现数据库多数据源自动切换的更多相关文章
- 四、Spring Boot 多数据源 自动切换
实现案例场景: 某系统除了需要从自己的主要数据库上读取和管理数据外,还有一部分业务涉及到其他多个数据库,要求可以在任何方法上可以灵活指定具体要操作的数据库.为了在开发中以最简单的方法使用,本文基于注解 ...
- Spring Boot 多数据源自动切换
在Spring Boot中使用单数据源的配置很简单,我们简单回忆下:只需要在application.properties进行基本的连接配置,在pom.xml引入基本的依赖即可. 那么多数据源的原理呢? ...
- 43. Spring Boot动态数据源(多数据源自动切换)【从零开始学Spring Boot】
[视频&交流平台] àSpringBoot视频 http://study.163.com/course/introduction.htm?courseId=1004329008&utm ...
- (43). Spring Boot动态数据源(多数据源自动切换)【从零开始学Spring Boot】
在上一篇我们介绍了多数据源,但是我们会发现在实际中我们很少直接获取数据源对象进行操作,我们常用的是jdbcTemplate或者是jpa进行操作数据库.那么这一节我们将要介绍怎么进行多数据源动态切换.添 ...
- Spring标签@Aspect-实现面向方向编程(@Aspect的多数据源自动加载)——SKY
从Spring 2.0开始,可以使用基于schema及@AspectJ的方式来实现AOP.由于@Aspect是基于注解的,因此要求支持注解的5.0版本以上的JDK. 环境要求: 1. mybit ...
- Spring Boot 动态数据源(多数据源自动切换)
本文实现案例场景: 某系统除了需要从自己的主要数据库上读取和管理数据外,还有一部分业务涉及到其他多个数据库,要求可以在任何方法上可以灵活指定具体要操作的数据库. 为了在开发中以最简单的方法使用,本文基 ...
- 22. Spring Boot 动态数据源(多数据源自动切换)
转自:https://blog.csdn.net/catoop/article/details/50575038
- Spring Boot -- Spring AOP原理及简单实现
一.AOP基本概念 什么是AOP,AOP英语全名就是Aspect oriented programming,字面意思就是面向切面编程.面向切面的编程是对面向对象编程的补充,面向对象的编程核心模块是类, ...
- 【Spring】关于Boot应用中集成Spring Security你必须了解的那些事
Spring Security Spring Security是Spring社区的一个顶级项目,也是Spring Boot官方推荐使用的Security框架.除了常规的Authentication和A ...
随机推荐
- luoguP3327 [SDOI2015]约数个数和
题意 首先有个结论: \(d(i,j)=\sum\limits_{x|i}\sum\limits_{y|j}[gcd(x,y)=1]\) 证明: 假设\(i=p_1^{a_1}*p_2^{a_2}*. ...
- C++面向对象程序设计学习笔记(3)
类与对象(1) 结构体与类 结构体的扩充 C++对结构体进行了扩充,它不仅可以含有不同类型的数据,还可以含有函数,结构体的函数可以像访问结构体中的数据一样进行访问. 类的声明 声明类的方法与声明结构体 ...
- RaxML使用
1.下载 https://github.com/stamatak/standard-RAxML 2.How many Threads shall I use? 重要的是要知道,RAxML PThrea ...
- MySQL实战45讲学习笔记:第二十三讲
一.本节概要 今天这篇文章,我会继续和你介绍在业务高峰期临时提升性能的方法.从文章标题“MySQL 是怎么保证数据不丢的?”,你就可以看出来,今天我和你介绍的方法,跟数据的可靠性有关. 在专栏前面文章 ...
- [LeetCode] 1123. Lowest Common Ancestor of Deepest Leaves 最深叶结点的最小公共父节点
Given a rooted binary tree, return the lowest common ancestor of its deepest leaves. Recall that: Th ...
- [LeetCode] 215. Kth Largest Element in an Array 数组中第k大的数字
Find the kth largest element in an unsorted array. Note that it is the kth largest element in the so ...
- ASP.NET MVC 下使用支付宝支付接口 以及 ASP.NET Core 下相关改造支付
通过nuget首先引用AopSdk.dll 包 下面写的是 Asp.Net MVC 下相关的支付接口 APP支付 配置客户端相关的参数,配置成自己的代码就可以了 private string APPI ...
- java ssh免密登录
package com.meituan.stabletest.sshtest; import java.io.InputStream; import com.jcraft.jsch.Channel; ...
- 实验一 Linux基础与Java开发环境
实验一 (一)实验内容 基于命令行和IDE(Intellj IDEA 简易教程http://www.cnblogs.com/rocedu/p/4421202.html)进行简单的Java程序编辑.编译 ...
- Salesforce学习之路(二)Profile
如上篇文章所述,针对User来讲,最重要的概念便是Profile和Role,因为Profile于Security息息相关,这是一个合格的产品中十分重要的一环. 何为Profile? 前文所讲--就是一 ...