SpringBoot多数据源动态切换+统⼀事务配置+动态分页⽅⾔SpringBoot多数据源动态切换+统⼀事务配置+动态分页⽅⾔
需求驱动技术发展
最近有公司项⽬有⼀个动态切换数据源的需求,但是⽹上到的多半不能⽤或者是功能不全,⾃⼰摸索出了最终配置,在此记录下,帮助下有同样需求的⼈。
不墨迹直接贴代码
我的项⽬是分层项⽬,我选择在Service层写动态切换,因为可以在业务层随意切换数据源,很⽅便
⾸先定义AbstractRoutingDataSource,这个类是Spring为我们提供的⽤来动态切换数据源的路由基类,我们只需要实现它并且重写determineCurrentLookupKey⽅法即可,⽬的是在Spring选择数据源的时候由我们来动态的指定数据源的Key。
DynamicDataSource :
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* AbstractRoutingDataSource 类为Spring提供的多数据源路由的基类
* 继承此类实现determineCurrentLookupKey⽅法返回⼀个数据源的Key即可动态的切换数据源
*
* @author wangjie-pc
*/
public class DynamicDataSource extends AbstractRoutingDataSource implements InitializingBean {
/**
* 取得当前使⽤哪个数据源
*
* @return
*/
@Override
protected Object determineCurrentLookupKey(){
DbType();
}
}
然后创建 DbContextHolder 数据源切换器,数据源切换器的⽬的是使⽤ThreadLocal来存储我们当前线程的数据源,实现不同线程不⼲扰,这点很重要,并且在切换数据源的时候动态的切换分页⽅⾔,因为项⽬使⽤的Mybatis-plus,可能切换⽅式有所不同,各位⾃⾏查询⾃⼰使⽤的持久层框架如何切换吧
DbContextHolder:
import com.alibaba.druid.pool.DruidDataSource;
import sion.plugins.PaginationInterceptor;
ums.DBTypeEnum;
ies.prepaid.service.SpringContextBeanService;
slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import flect.Method;
/**
* 切换数据源Holder
*
* @author wangjie-pc
*/
@Slf4j
public class DbContextHolder {
private static final ThreadLocal<String> CONTEXT_HOLDER =new ThreadLocal<>();
/**
* 设置数据源
*
* @param dbTypeEnum
*/
public static void setDbType(DBTypeEnum dbTypeEnum){
//切换数据源
CONTEXT_HOLDER.Value());
//切换分页插件⽅⾔
try{
DynamicDataSource dynamicDataSource = Bean(DynamicDataSource.class);
Method determineTargetDataSourceMethod = BeanUtils.findDeclaredMethod(AbstractRoutingDataSource.class,"determineTargetDataSource"); determineTargetDataSourceMethod.setAccessible(true);
String type =((DruidDataSource) determineTargetDataSourceMethod.invoke(dynamicDataSource)).getDbType();
//切换分页⽅⾔
}catch(Exception e){
<("Dialect Switching Failed!", e);
}
}
/**
* 取得当前数据源
*
* @return
*/
public static String getDbType(){
return ();
}
/
**
* 清除上下⽂数据
*/
public static void clearDbType(){
ve();
}
}
接下来是重头戏MybatisPlusConfig,在这个类⾥⾯我们会配置数据源、多数据源管理器、事务
MybatisPlusConfig:
import com.alibaba.druid.pool.DruidDataSource;
import sion.plugins.PaginationInterceptor;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Qualifier;
import org.t.properties.ConfigurationProperties; import t.annotation.Bean;
import t.annotation.Configuration;
import t.annotation.Primary;
import org.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager; import ansaction.PlatformTransactionManager;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
/**
* Mp配置
*
* @author wangjie-pc
* @since 2019/2/18 18:08
*/
@Configuration
public class MybatisPlusConfig {
springboot aop/**
* mybatis-plus分页插件默认⽅⾔为Oracle
*
* @return
*/
@Bean
public PaginationInterceptor paginationInterceptor(){
PaginationInterceptor page =new PaginationInterceptor();
page.setDialectType("oracle");
return page;
}
/**
* 数据源1
*
* @return
* @throws SQLException
*/
@ConfigurationProperties(prefix ="datasource.prepaid")
@Bean(name ="prepaidDatasource")
public DruidDataSource prepaidDatasource(){
DruidDataSource druidDataSource =new DruidDataSource();
druidDataSource.setDefaultAutoCommit(false);
return druidDataSource;
}
/**
* 数据源2
*
* @return
* @throws SQLException
*/
@ConfigurationProperties(prefix ="datasource.maint")
@Bean(name ="maintDatasource")
public DruidDataSource maintDatasource(){
DruidDataSource druidDataSource =new DruidDataSource();
druidDataSource.setDefaultAutoCommit(false);
return druidDataSource;
}
/**
* 配置动态数据源
*
* @param prepaidDatasource
* @param maintDatasource
* @param maintDatasource
* @return
*/
@Bean
@Primary
public DynamicDataSource dynamicDataSource(@Qualifier(value ="prepaidDatasource") DruidDataSource prepaidDatasource, @Qualifier(value ="maintDatasource") DruidDataSource maintDatasource){
DynamicDataSource bean =new DynamicDataSource();
Map<Object, Object> targetDataSources =new HashMap<>(16);
targetDataSources.put("prepaidDatasource", prepaidDatasource);
targetDataSources.put("maintDatasource", maintDatasource);
bean.setTargetDataSources(targetDataSources);
bean.setDefaultTargetDataSource(prepaidDatasource);
return bean;
}
@Bean
public PlatformTransactionManager transactionManager(DynamicDataSource dynamicDataSource){
return new DataSourceTransactionManager(dynamicDataSource);
}
@Bean
public JdbcTemplate jdbcTemplate(DynamicDataSource dynamicDataSource){
return new JdbcTemplate(dynamicDataSource);
}
}
最后⼀步,成功在即,配置AOP,实现⽅法、类动态切换数据源,请⾃⾏修改包名
DataSourceInterceptor:
ies.prepaid.annotation.TargetDataSource;
ums.DBTypeEnum;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.flect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import annotation.Order;
import org.springframework.stereotype.Component;
import flect.Method;
/**
* 切换数据源AOP
*
* @author wangjie-pc
*/
@Order(1)
@Aspect
@Component
public class DataSourceInterceptor {
Logger logger = Logger(DataSourceInterceptor.class);
@Pointcut("execution( * ies.prepaid.service..*.*(..)) && !execution(* ies.fig..*.*(..))")
private void aspect(){
private void aspect(){
}
@Around("aspect()")
public Object validationPoint(ProceedingJoinPoint pjp)throws Throwable {
<("检测数据源{}.......................","");
Signature s = Signature();
MethodSignature ms =(MethodSignature) s;
Method method = ms.getMethod();
TargetDataSource targetDataSource = Annotation(TargetDataSource.class);
//基于⽅法的注解
if(null != targetDataSource){
<("⽅法:{}数据源切换到{}.......................", Name(), targetDataSource.name()); DbContextHolder.setDbType(targetDataSource.name());
return pjp.Args());
}
//基于类的注解
String actualClassName = This().getClass().getName();
actualClassName = actualClassName.substring(0, actualClassName.indexOf("$"));
Class<?> serviceClass = Class.forName(actualClassName);
targetDataSource = DeclaredAnnotation(TargetDataSource.class);
if(targetDataSource != null){
DbContextHolder.setDbType(targetDataSource.name());
<("类:{}数据源切换到{}.......................", Name(), targetDataSource.name());
return pjp.Args());
}
return pjp.Args());
}
@After("aspect()")
public void resetDefaultDataSource(){
<("切换回默认数据源{}.......................", DBTypeEnum.defaultDateSource);
DbContextHolder.setDbType(DBTypeEnum.defaultDateSource);
}
}
获取Spring上下⽂⼯具类
SpringContextBeanService:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论