当前位置:   article > 正文

java框架 动态切换数据库_Springboot动态切换数据库

datasourcechange

很多情况下,希望应用程序搭建一套,为每个用户建立一个私有的数据库,所有程序使用一套.

开动吧:

一、 首先继承AbstractRoutingDataSource,从名称上看为抽象路由数据源,就是spring为提供动态数据库而设定的。在这个类中,需要重写determineCurrentLookupKey这个方法,这个方法就是动态从

private Map targetDataSources(AbstractRoutingDataSource类里面的属性)里面获取对应的数据源import com.alibaba.druid.pool.DruidDataSource;

import org.springframework.context.annotation.Configuration;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import javax.sql.DataSource;

import java.sql.SQLException;

import java.util.Map;

import java.util.concurrent.ConcurrentHashMap;

@Configuration

public class DynamicDataSource extends AbstractRoutingDataSource {

/**

* 每次请求动态请求哪一个数据源

* @return

*/

@Override

protected Object determineCurrentLookupKey() {

return DataSourceHolder.getDataSource();

}

public DynamicDataSource(){

Map dataSources=new ConcurrentHashMap<>();

for(int i=1;i<=4;i++){

DataSource dataSource = druidDataSource(i);

dataSources.put(String.valueOf(i),dataSource);

if(i==1){

super.setDefaultTargetDataSource(dataSource);

}

}

super.setTargetDataSources(dataSources);

}

/**

* 此处数据库信配置,可以来源于redis等,然后再初始化所有数据源

* 重点说明:一个DruidDataSource数据源,它里面本身就是线程池了,

* 所以我们不需要考虑线程池的问题

* @param no

* @return

*/

public DataSource druidDataSource(int no) {

DruidDataSource datasource = new DruidDataSource();

datasource.setUrl("jdbc:mysql://localhost:3306/ds0"+no);

datasource.setUsername("root");

datasource.setPassword("123456");

datasource.setDriverClassName("com.mysql.jdbc.Driver");

datasource.setInitialSize(5);

datasource.setMinIdle(5);

datasource.setMaxActive(20);

//datasource.setDbType("com.alibaba.druid.pool.DruidDataSource");

datasource.setMaxWait(60000);

datasource.setTimeBetweenEvictionRunsMillis(60000);

datasource.setMinEvictableIdleTimeMillis(300000);

datasource.setValidationQuery("SELECT 1 FROM DUAL");

datasource.setTestWhileIdle(true);

datasource.setTestOnBorrow(false);

datasource.setTestOnReturn(false);

try {

datasource.setFilters("stat,wall,log4j");

} catch (SQLException e) {

e.printStackTrace();

}

return datasource;

}

}

二、新建DataSourceHolder:public class DataSourceHolder {

//线程本地环境

private static final ThreadLocal dataSources = new ThreadLocal();

//设置数据源,动态切换,就是调用这个setDataSource方法

public static void setDataSource(String customerType) {

dataSources.set(customerType);

}

//获取数据源

public static String getDataSource() {

return (String) dataSources.get();

}

//清除数据源

public static void clearDataSource() {

dataSources.remove();

}

}

三、在controller层的每个方法前切换数据源,用到AOP

重点说明:每多人会有疑问,springcloud的controller是单例,这样在多用户的情况下,会不会窜请求,线程不安全

原因解答:(1)请看上面,其实我们使用了ThreadLocal,如果不理解的,请去补ThreadLocal知识了

用多线程测试:我用多个线程,调用同一个查询方法,但每个请求的header中的dsNo都不一样,这样就真实模拟生产环境,多用户查的情况,看是否有有窜请求,线程不安全的情况,实际测试并没有这种情况出现

(1)AOP动态切换数据库:import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.aspectj.lang.annotation.Pointcut;

import org.springframework.context.annotation.Configuration;

import org.springframework.core.annotation.Order;

import org.springframework.util.StringUtils;

import org.springframework.web.context.request.RequestContextHolder;

import org.springframework.web.context.request.ServletRequestAttributes;

@Aspect

@Order(1)

@Configuration

public class DataSourceAspect {

private static final String dsNo="dsNo";//数据库编号 从header中取

/**

* 切入点,放在controller的每个方法上进行切入,更新数据源

*/

@Pointcut("execution(* com.eck.auto.controller..*.*(..))")

private void anyMethod(){}//定义一个切入点

@Before("anyMethod()")

public void dataSourceChange()

{

//请求头head中获取对应数据库编号

String no = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getHeader(dsNo);

System.out.print("当前数据源编号:"+no);

if(StringUtils.isEmpty(no)){

//TODO 根据业务抛异常

}

DataSourceHolder.setDataSource(no);

/*这里数据库项目编号来更改对应的数据源*/

}

}

四、相信很多人都希望要本项目代码,本项目githup地址https://github.com/hekf2021/autodatasource.git

测试说明:按本项目测试,需要创建4个数据库ds01、ds02、ds03、ds04,sql语句在sql.sql中,里面表都一样,只是数据不一样,比如ds01库表中的记录reason写dso1,ds02数据库中表的记录写ds02,ds03数据库中表的记录写ds03,ds04数据库中表的记录写ds04,以此类推,自己修改数据...,通过查询传不同的数据库编号,返回的不同数据,来辨别是否切换到了对应的数据库

如下图(如有什么不对的对方,可以加Q群 147960493,联系群主我)

补充信息:

在实际项目中如何应用,提示一下大家,1、首先得有一个公共全局数据库,如all_database_url,这里面存所有数据源的jdbc url地址,以及连对应数据库的用户名及密码。2、修改DynamicDataSource 中的DynamicDataSource()方法从all_database_url库中取出所有数据库的jdbc url信息,进行初始化。3、DynamicDataSource()方法从all_database_url库中取出所有数据库的jdbc url信息,怎么取?自己写原生代码查询数据all_database_url,不能用框架了,原因是框架连数据库,给ds01,ds02,ds03这些具体数据库用了。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/52362
推荐阅读
相关标签
  

闽ICP备14008679号