本文主要涉及对技术mybatis和spring基础开源框架的使用
核心逻辑:实现拦截器,利用MappedStatement去判断sql类型,通determineCurrentLookupKey判断使用的数据源id,进行数据源的选择
配置文件(application.properties)
datasource.write.driver-class-name=com.mysql.jdbc.Driver
datasource.write.url=jdbc:mysql://172.198.16.10:3306/test
datasource.write.username=root
datasource.write.password=123456
datasource.read.driver-class-name=com.mysql.jdbc.Driver
datasource.read.url=jdbc:mysql://172.198.16.11:3306/test
datasource.read.username=root
datasource.read.password=123456
threadlocal基本方法封装
package com.iqc.manydatasource;
/**
* @author qb
*/
public class DataSourceHolder {
public static final String WRITE_DATASOURCE = "write";
public static final String READ_DATASOURCE = "read";
private static final ThreadLocal<String> local = new ThreadLocal<>();
public static void putDataSource(String dataSource) {
local.set(dataSource);
}
public static String getDataSource() {
return local.get();
}
}
configuration配置
package com.iqc.manydatasource;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
/**
* @author qb
*/
@Configuration
public class DataSourcePropertiesConfig {
@Primary
@Bean("writeDataSourceProperties")
@ConfigurationProperties("datasource.write")
public DataSourceProperties writeDataSourceProperties() {
return new DataSourceProperties();
}
@Bean("readDataSourceProperties")
@ConfigurationProperties("datasource.read")
public DataSourceProperties readDataSourceProperties() {
return new DataSourceProperties();
}
}
determineCurrentLookupKey配置
package com.iqc.manydatasource;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
import static com.iqc.manydatasource.DataSourceHolder.READ_DATASOURCE;
import static com.iqc.manydatasource.DataSourceHolder.WRITE_DATASOURCE;
/**
* @author qb
*/
@Component
public class MultipleDataSource extends AbstractRoutingDataSource {
@Resource(name = "writeDataSourceProperties")
private DataSourceProperties writeProperties;
@Resource(name = "readDataSourceProperties")
private DataSourceProperties readProperties;
/**
* 配置dataSourceMap资源
*/
@Override
public void afterPropertiesSet() {
DataSource writeDataSource =
writeProperties.initializeDataSourceBuilder().type(DruidDataSource.class).build();
DataSource readDataSource =
readProperties.initializeDataSourceBuilder().type(DruidDataSource.class).build();
setDefaultTargetDataSource(writeDataSource);
Map<Object, Object> dataSourceMap = new HashMap<>();
dataSourceMap.put(WRITE_DATASOURCE, writeDataSource);
dataSourceMap.put(READ_DATASOURCE, readDataSource);
setTargetDataSources(dataSourceMap);
super.afterPropertiesSet();
}
/**
* AbstractRoutingDataSource执行determineCurrentLookupKey(),
* 以便从一组可用的DataSource中找到合适的dataSource
* AbstractRoutingDataSource返回该数据源的JDBC连接。
*/
@Override
protected Object determineCurrentLookupKey() {
String key = DataSourceHolder.getDataSource();
//进行置空操作,避免出现select后update导致进入下方if判断
DataSourceHolder.putDataSource(null);
if (key == null) {
// default datasource
return WRITE_DATASOURCE;
}
return key;
}
}
sql拦截器配置
package com.iqc.manydatasource;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import java.util.Properties;
/**
* @author qb
*/
@Component
@Intercepts({
@Signature(type = Executor.class, method = "update",
args = {MappedStatement.class, Object.class}),
@Signature(type = Executor.class, method = "query",
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
public class MybatisDataSourceInterceptor implements Interceptor {
/**
* 进行sql拦截,根据增删改查关键字去进行数据源选择
*/
@Override
public Object intercept(Invocation invocation) throws Throwable {
boolean synchronizationActive = TransactionSynchronizationManager.isSynchronizationActive();
if(!synchronizationActive) {
Object[] objects = invocation.getArgs();
MappedStatement ms = (MappedStatement) objects[0];
//进行sql拦截判断是UNKNOWN, INSERT, UPDATE, DELETE, SELECT, FLUSH中的哪个。
// select进读库,其余进写库,这里可以增加判断条件去走不同库
if (ms.getSqlCommandType().equals(SqlCommandType.SELECT)) {
DataSourceHolder.putDataSource(DataSourceHolder.READ_DATASOURCE);
}
}
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
}
本文转载自: https://blog.csdn.net/zcxzfeqe/article/details/125378037
版权归原作者 鱼当然得是摸的才行 所有, 如有侵权,请联系我们删除。
版权归原作者 鱼当然得是摸的才行 所有, 如有侵权,请联系我们删除。