一、添加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实现数据库多数据源自动切换的更多相关文章

  1. 四、Spring Boot 多数据源 自动切换

    实现案例场景: 某系统除了需要从自己的主要数据库上读取和管理数据外,还有一部分业务涉及到其他多个数据库,要求可以在任何方法上可以灵活指定具体要操作的数据库.为了在开发中以最简单的方法使用,本文基于注解 ...

  2. Spring Boot 多数据源自动切换

    在Spring Boot中使用单数据源的配置很简单,我们简单回忆下:只需要在application.properties进行基本的连接配置,在pom.xml引入基本的依赖即可. 那么多数据源的原理呢? ...

  3. 43. Spring Boot动态数据源(多数据源自动切换)【从零开始学Spring Boot】

    [视频&交流平台] àSpringBoot视频 http://study.163.com/course/introduction.htm?courseId=1004329008&utm ...

  4. (43). Spring Boot动态数据源(多数据源自动切换)【从零开始学Spring Boot】

    在上一篇我们介绍了多数据源,但是我们会发现在实际中我们很少直接获取数据源对象进行操作,我们常用的是jdbcTemplate或者是jpa进行操作数据库.那么这一节我们将要介绍怎么进行多数据源动态切换.添 ...

  5. Spring标签@Aspect-实现面向方向编程(@Aspect的多数据源自动加载)——SKY

    从Spring 2.0开始,可以使用基于schema及@AspectJ的方式来实现AOP.由于@Aspect是基于注解的,因此要求支持注解的5.0版本以上的JDK. 环境要求:    1. mybit ...

  6. Spring Boot 动态数据源(多数据源自动切换)

    本文实现案例场景: 某系统除了需要从自己的主要数据库上读取和管理数据外,还有一部分业务涉及到其他多个数据库,要求可以在任何方法上可以灵活指定具体要操作的数据库. 为了在开发中以最简单的方法使用,本文基 ...

  7. 22. Spring Boot 动态数据源(多数据源自动切换)

    转自:https://blog.csdn.net/catoop/article/details/50575038

  8. Spring Boot -- Spring AOP原理及简单实现

    一.AOP基本概念 什么是AOP,AOP英语全名就是Aspect oriented programming,字面意思就是面向切面编程.面向切面的编程是对面向对象编程的补充,面向对象的编程核心模块是类, ...

  9. 【Spring】关于Boot应用中集成Spring Security你必须了解的那些事

    Spring Security Spring Security是Spring社区的一个顶级项目,也是Spring Boot官方推荐使用的Security框架.除了常规的Authentication和A ...

随机推荐

  1. zz开源 MNN:淘宝在移动 AI 上的实践

    开源 MNN:淘宝在移动 AI 上的实践   陈以鎏(离青) 阅读数:40612019 年 6 月 28 日   随着深度学习的快速发展和端侧设备算力的不断提升,原本在云端执行的推理预测工作正在部分迁 ...

  2. reactjs中配置代理跨域

    第一步,下载依赖 http-proxy-middleware yarn add http-proxy-middleware 第二步,在src下建立setupProxy.js const proxy = ...

  3. 6.Vue的Axios异步通信

    1.什么是Axios Axios 是一个开源的可以用在浏览器端和 NodeJS 的异步通信框架,主要作用就是实现 AJAX 异步通信,其功能特点如下: 从浏览器中创建 XMLHttpRequests ...

  4. nginx配置代理时参数说明

  5. MySQL实战45讲学习笔记:第二十一讲

    一.引子 在上一篇文章中,我和你介绍了间隙锁和 next-key lock 的概念,但是并没有说明加锁规则.间隙锁的概念理解起来确实有点儿难,尤其在配合上行锁以后,很容易在判断是否会出现锁等待的问题上 ...

  6. [原创]App崩溃率统计工具推荐

    [原创]App崩溃率统计工具推荐 1 友盟(推荐) 友盟是一款比较成熟的工具,同时也可以展示留存,日活,事件等. 2 Bugly   腾讯的bugly统计数据也算是比较早的,可惜后续维护比较弱,功能与 ...

  7. Visual Studio 2019(VS2019)下载极慢的问题

    今天给新电脑安装 vs2019,下载速度只有 TMD 10kb/s,实在忍无可忍,在经过了一系列的百度之后,找到解决方法. 具体方法很简单: 用站长工具查询了一下 download.visualstu ...

  8. 100教程-100jc.cn

    个人编程笔记网站(持续更新) http://100jc.cn

  9. Qt Quick 多媒体 - 播放音乐和视频

    MediaPlayer 是 QML 提供的核心多媒体类,可以播放音频.视频.要使用 MediaPlayer,需要引入 QtMultimedia 模块,在 QML 文档的开始加入 "impor ...

  10. jQuery学习路线&review

    学习途径:http://www.w3school.com.cn/jquery/index.asp 路线图 转载自:https://www.cnblogs.com/lanren2017/p/723720 ...