前言:本文采用springboot集成AOP的方式实现读写分离
1.准备工作,mybaties主从数据库的搭建,不会的同学可以浏览这篇博客https://blog.csdn.net/qq_30374237/article/details/106624263
2.引入依赖
<!--导入AOP依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- 数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.31</version>
</dependency>
3.添加主从库的配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.master.url=jdbc:mysql://192.168.1.156:3306/test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&failOverReadOnly=false&useSSL=false&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true
spring.datasource.master.username=root
spring.datasource.master.password=****
spring.datasource.slave.url=jdbc:mysql://192.168.1.154:3306/test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&failOverReadOnly=false&useSSL=false&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true
spring.datasource.slave.username=root
spring.datasource.slave.password=****
4.定义线程类,用于从库的设置,清空和获取
public class DataSourceThread {
private static final ThreadLocal<String> DATASOURCE_THREAD = new ThreadLocal<>();
public static void set() {
DATASOURCE_THREAD.set("slave");
}
public static String get() {
return DATASOURCE_THREAD.get();
}
public static void clear() {
DATASOURCE_THREAD.remove();
}
5.由于多个数据源,数据库配置需要手动配置
@Configuration
@MapperScan("com.bjiang.datasource.read.write.dao")
public class ReadOrWriteDaraSource {
/**
* 主库配置注入
*/
@Bean
@ConfigurationProperties(prefix = "spring.datasource.master")
public DataSource master() {
//new DruidDataSource();
return DruidDataSourceBuilder.create().build();
}
/**
* 从库配置注入
*/
@Bean
@ConfigurationProperties(prefix = "spring.datasource.slave")
public DataSource slave() {
//new DruidDataSource();
return DruidDataSourceBuilder.create().build();
}
/**
* 主从动态配置
*/
@Bean
public SlaveDataSource dynamic(@Qualifier("master") DataSource masterDataSource,
@Autowired(required = false) @Qualifier("slave") DataSource slaveDataSource) {
SlaveDataSource dynamicDataSource = new SlaveDataSource();
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put("master", masterDataSource);
if (slaveDataSource != null) {
targetDataSources.put("slave", slaveDataSource);
}
dynamicDataSource.setTargetDataSources(targetDataSources);
dynamicDataSource.setDefaultTargetDataSource(masterDataSource);
return dynamicDataSource;
}
/*
* 多个数据源需要配置SqlSessionFactory
* */
@Bean
public SqlSessionFactory sessionFactory(@Qualifier("dynamic") DataSource dynamicDataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setTypeAliasesPackage("com.bjiang.datasource.read.write.dao");
bean.setDataSource(dynamicDataSource);
return bean.getObject();
}
@Bean
public SqlSessionTemplate sqlTemplate(@Qualifier("sessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
@Bean(name = "dataSource")
public DataSourceTransactionManager dataSource(@Qualifier("dynamic") DataSource dynamicDataSource) {
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dynamicDataSource);
return dataSourceTransactionManager;
}
6.重写方法,设置以及获取DataSource
public class SlaveDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceThread.get();
}
}
7.自定义注解实现AOP,用于注解需要使用从库的方法
/**
* 自定义注解实现AOP,用于注解需要使用从库的方法
* */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Slave {
}
8.编写AOP类进行拦截,实现切换数据源
@Aspect
@Order(value = 1)
@Component
public class DataSourceAop {
@Around("@annotation(com.bjiang.datasource.read.write.aop.Slave)")
public Object setDynamicDataSource(ProceedingJoinPoint pjp) throws Throwable {
boolean clear = true;
try {
DataSourceThread.set();
log.info("切换数据源");
return pjp.proceed();
} finally {
if (clear) {
DataSourceThread.clear();
}
}
}
}
9.编写测试方法,需要使用从库时加上注解@Slave
10.测试
显示主库数据已插入
显示查看数据时已切换数据源