一、添加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. leetcode138. 复制带随机指针的链表

    思路一:哈希 借助哈希保存节点信息. 代码 时间复杂度:O(n)空间复杂度:O(n) class Solution{ public: Node* copyRandomList(Node* head) ...

  2. 洛谷P5437/5442 约定(概率期望,拉格朗日插值,自然数幂)

    题目大意:$n$ 个点的完全图,点 $i$ 和点 $j$ 的边权为 $(i+j)^k$.随机一个生成树,问这个生成树边权和的期望对 $998244353$ 取模的值. 对于P5437:$1\le n\ ...

  3. [LeetCode] 907. Sum of Subarray Minimums 子数组最小值之和

    Given an array of integers A, find the sum of min(B), where B ranges over every (contiguous) subarra ...

  4. [LeetCode] 674. Longest Continuous Increasing Subsequence 最长连续递增序列

    Given an unsorted array of integers, find the length of longest continuous increasing subsequence. E ...

  5. wpf “{DependencyProperty.UnsetValue}”不是属性“Background”的有效值。异常

    , 在wpf模板中, 有一个Background绑定的值不存在导致的异常, 我的是有这个没有导致的错误,  自己添加之后就没有了

  6. 第02组 Alpha事后诸葛亮

    目录 1. 组长博客(2分) 2. 总结思考(27分) 2.1. 设想和目标(2分) 2.2. 计划(5分) 2.3. 资源(3分) 2.4. 变更管理(4分) 2.5. 设计/实现(4分) 2.6. ...

  7. ZJOI 2009 多米诺骨牌(状态压缩+轮廓线+容斥)

    题意 https://www.lydsy.com/JudgeOnline/problem.php?id=1435 思路 一道很好的状压/容斥题,涵盖了很多比较重要的知识点. 我们称每两行间均有纵跨.每 ...

  8. 用友U8合同执行单保存报错,提示“语法错误或违反访问规则”

    问题描述 用户参照合同录入第一阶段的执行单,保存时提示“语法错误或违反访问规则”,其他合同均正常,只有这张合同出现这个问题. 解决过程 语法错误或违反访问规则是SQL Server常见的报错,但其他合 ...

  9. Django-orm高级

    ORM字段 orm常见字段 https://www.cnblogs.com/liuqingzheng/articles/9627915.html choice字段注释与数据渲染 性别 sex_choi ...

  10. 解决 警告: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'source' to 'org.eclipse.jst.jee.server:reyo' did not find a matching property.

    解决办法是:关闭tomcat,双击eclipse下tomcat服务器,在出来的Tomcat server at localhost页面中找到server options选项,选中其中的选项”Publi ...