前言:本文采用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.測試
顯示主庫數據已插入
顯示查看數據時已切換數據源