Spring4.0 + druid 配置动态配置数据源以及多数据源切换功能实现

数据源连接池使用druid 其他的数据源基本原理相同

spring中配置默认数据源连接池如下:

1<!-- 数据源配置, 使用 BoneCP 数据库连接池 --> 2    <bean id="dataSourceOne" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">  3        <property name="name" value="dataSourceOne"/> 4        <!-- 数据源驱动类可不写,Druid默认会自动根据URL识别DriverClass --> 5        <property name="driverClassName" value="${jdbc.driver}" /> 6         7        <!-- 基本属性 url、user、password --> 8        <property name="url" value="${jdbc.url}" /> 9        <property name="username" value="${jdbc.username}" /> 10        <property name="password" value="${jdbc.password}" /> 11         12        <!-- 配置初始化大小、最小、最大 --> 13        <property name="initialSize" value="${jdbc.pool.init}" /> 14        <property name="minIdle" value="${jdbc.pool.minIdle}" />  15        <property name="maxActive" value="${jdbc.pool.maxActive}" /> 16         17        <!-- 配置获取连接等待超时的时间 --> 18        <property name="maxWait" value="60000" /> 19         20        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --> 21        <property name="timeBetweenEvictionRunsMillis" value="60000" /> 22         23        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --> 24        <property name="minEvictableIdleTimeMillis" value="300000" /> 25         26        <property name="validationQuery" value="${jdbc.testSql}" /> 27        <property name="testWhileIdle" value="true" /> 28        <property name="testOnBorrow" value="false" /> 29        <property name="testOnReturn" value="false" /> 30         31        <!-- 打开PSCache,并且指定每个连接上PSCache的大小(Oracle使用) 32        <property name="poolPreparedStatements" value="true" /> 33        <property name="maxPoolPreparedStatementPerConnectionSize" value="20" /> --> 34         35        <!-- 配置监控统计拦截的filters --> 36        <property name="filters" value="stat" />  37    </bean>

接下来配置多数据源bean

1<!-- 多数据源配置 --> 2     <bean id="dynamicDataSource" class="com.XXX.datasource.DynamicDataSource" >   3        <property name="targetDataSources">   4            <map>   5                <entry value-ref="dataSourceOne" key="dataSourceOne"></entry>   6 7                <!--此处是对数据源的引用--> 8               <!--  <entry value-ref="dataSourceTow" key="dataSourceTow"></entry> --> 9            </map>   10        </property>   11        <property name="defaultTargetDataSource" ref="dataSourceOne" />   12        <property name="debug"  value="true"/> 13    </bean> 

这个类 com.XXX.datasource.DynamicDataSource 需要手动创建

1import java.sql.Connection; 2import java.sql.DriverManager; 3import java.sql.SQLException; 4import java.util.Map; 5import java.util.Properties; 6import java.util.Set; 7 8import javax.sql.DataSource; 9 10import org.slf4j.Logger; 11import org.slf4j.LoggerFactory; 12import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; 13import org.springframework.util.StringUtils; 14 15import com.alibaba.druid.pool.DruidConnectionHolder; 16import com.alibaba.druid.pool.DruidDataSource; 17import com.alibaba.druid.pool.DruidDataSourceFactory; 18import com.alibaba.druid.pool.DruidPooledConnection; 19import com.alibaba.druid.stat.DruidDataSourceStatManager; 20import com.alibaba.druid.util.DruidDataSourceUtils; 21 22/** 23 * @author zh 24 */ 25public class DynamicDataSource extends AbstractRoutingDataSource{ 26 27    private boolean debug = false; 28    Logger log = LoggerFactory.getLogger(this.getClass()); 29    private Map<Object, Object> dynamicTargetDataSources; 30 31    private Object dynamicDefaultTargetDataSource; 32    /* (non-Javadoc) 33@see org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource#determineCurrentLookupKey() 34     */ 35    @Override 36    protected Object determineCurrentLookupKey() { 37         String datasource=DBContextHolder.getDataSource(); 38         if(debug) 39         { 40             if(StringUtils.isEmpty(datasource)){ 41                log.info("---当前数据源:默认数据源---");  42             }else{ 43                 log.info("---当前数据源:"+datasource+"---");  44             } 45         } 46         47         return datasource; 48    } 49     50    @Override 51    public void setTargetDataSources(Map<Object, Object> targetDataSources) { 52        super.setTargetDataSources(targetDataSources); 53        this.dynamicTargetDataSources = targetDataSources; 54    } 55    //创建数据源 56    public boolean createDataSource(String key,String driveClass,String url,String username,String password){ 57        try { 58            try {    //排除连接不上的错误 59                Class.forName(driveClass);   60                DriverManager.getConnection(url, username, password); 61            } catch (Exception e) { 62                return false; 63            } 64            @SuppressWarnings("resource") 65            DruidDataSource druidDataSource = new DruidDataSource(); 66            druidDataSource.setName(key); 67            druidDataSource.setDriverClassName(driveClass); 68            druidDataSource.setUrl(url); 69            druidDataSource.setUsername(username); 70            druidDataSource.setPassword(password); 71            druidDataSource.setMaxWait(60000); 72            druidDataSource.setFilters("stat"); 73            DataSource createDataSource = (DataSource)druidDataSource; 74            druidDataSource.init(); 75            Map<Object, Object> dynamicTargetDataSources2 =  this.dynamicTargetDataSources; 76            dynamicTargetDataSources2.put(key, createDataSource);//加入map 77            setTargetDataSources(dynamicTargetDataSources2);//将map赋值给父类的TargetDataSources 78            super.afterPropertiesSet();//将TargetDataSources中的连接信息放入resolvedDataSources管理 79            return true; 80        } catch (Exception e) { 81            log.error(e+""); 82            return false; 83        } 84    } 85    //删除数据源 86    public boolean delDatasources(String datasourceid){ 87        Map<Object, Object> dynamicTargetDataSources2 =  this.dynamicTargetDataSources; 88        if(dynamicTargetDataSources2.containsKey(datasourceid)){ 89            Set<DruidDataSource> druidDataSourceInstances = DruidDataSourceStatManager.getDruidDataSourceInstances(); 90            for(DruidDataSource l:druidDataSourceInstances){ 91                if(datasourceid.equals(l.getName())){ 92                    System.out.println(l); 93                    dynamicTargetDataSources2.remove(datasourceid); 94                    DruidDataSourceStatManager.removeDataSource(l); 95                    setTargetDataSources(dynamicTargetDataSources2);//将map赋值给父类的TargetDataSources 96                    super.afterPropertiesSet();//将TargetDataSources中的连接信息放入resolvedDataSources管理 97                    return true; 98                } 99            } 100            return false; 101        }else{ 102            return false; 103        } 104    } 105     106    //测试数据源连接是否有效 107    public boolean testDatasource(String key,String driveClass,String url,String username,String password){ 108        try { 109            Class.forName(driveClass);   110            DriverManager.getConnection(url, username, password);   111            return true; 112        } catch (Exception e) { 113            return false; 114        } 115    } 116    /** 117     * Specify the default target DataSource, if any. 118     * <p>The mapped value can either be a corresponding {@link javax.sql.DataSource} 119     * instance or a data source name String (to be resolved via a 120     * {@link #setDataSourceLookup DataSourceLookup}). 121     * <p>This DataSource will be used as target if none of the keyed 122     * {@link #setTargetDataSources targetDataSources} match the 123     * {@link #determineCurrentLookupKey()} current lookup key. 124     */ 125    public void setDefaultTargetDataSource(Object defaultTargetDataSource) { 126        super.setDefaultTargetDataSource(defaultTargetDataSource); 127        this.dynamicDefaultTargetDataSource = defaultTargetDataSource; 128    } 129    /** 130     * @param debug the debug to set 131     */ 132    public void setDebug(boolean debug) { 133        this.debug = debug; 134    } 135 136    /** 137     * @return the debug 138     */ 139    public boolean isDebug() { 140        return debug; 141    } 142 143    /** 144     * @return the dynamicTargetDataSources 145     */ 146    public Map<Object, Object> getDynamicTargetDataSources() { 147        return dynamicTargetDataSources; 148    } 149 150    /** 151     * @param dynamicTargetDataSources the dynamicTargetDataSources to set 152     */ 153    public void setDynamicTargetDataSources( 154            Map<Object, Object> dynamicTargetDataSources) { 155        this.dynamicTargetDataSources = dynamicTargetDataSources; 156    } 157 158    /** 159     * @return the dynamicDefaultTargetDataSource 160     */ 161    public Object getDynamicDefaultTargetDataSource() { 162        return dynamicDefaultTargetDataSource; 163    } 164     165    /** 166     * @param dynamicDefaultTargetDataSource the dynamicDefaultTargetDataSource to set 167     */ 168    public void setDynamicDefaultTargetDataSource( 169            Object dynamicDefaultTargetDataSource) { 170        this.dynamicDefaultTargetDataSource = dynamicDefaultTargetDataSource; 171    } 172     173}

其中该类继承了spring的AbstractRoutingDataSource 查看其源码,发现所有的数据源都是通过

afterPropertiesSet() 将存放在targetDataSources 这个Map中的数据源赋值给resolvedDataSources

对象的,spring是从resolvedDataSources对象中获取数据源对象的,我们能需要把自己的数据源放入

resolvedDataSources这个Map中就ok了。

接下来创建数据源切换工具类

1/** 2 * 数据源切换 3 * @author zh 4 * 5 */ 6public class DBContextHolder { 7     private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();   8      9         //调用此方法,切换数据源 10        public static void setDataSource(String dataSource) {   11            contextHolder.set(dataSource);   12        }   13           14        public static String getDataSource() {   15            return contextHolder.get();   16        }   17           18        public static void clearDataSource() {   19            contextHolder.remove();   20        }   21}

具体实动态新增数据源,需要创建数据库用以存储 数据库连接信息,以及数据源key信息。

初始话数据库连接数据源,可以使用spring监听 实现ApplicationListener即可,如下

1import java.util.List; 2 3import org.springframework.beans.factory.annotation.Autowired; 4import org.springframework.context.ApplicationEvent; 5import org.springframework.context.ApplicationListener; 6 7import com.casking.cdds.modules.datasource.entity.CNDatasources; 8 9public class InitDatasourcesLS implements ApplicationListener<ApplicationEvent>{ 10 11    @Autowired 12    private CNDatasourcesService service; 13     14    @Override 15    public void onApplicationEvent(ApplicationEvent event) { 16        List<CNDatasources> list = service.findList(new CNDatasources()); 17        for(CNDatasources li:list){ 18 19            //这里调用创建数据源的方法即可 20            service.addDataSourceDynamic(li.getDatasource(),li); 21        } 22    } 23 24}
点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

SSH实现动态数据源切换,事务场景下使用AOP

上周写代码遇到了切换数据源的问题,在同一个方法中向两个不同数据源做一些操作,但是这个方法使用了事务,所以网上一般动态切换数据源的方法就失效了。框架是spirngmvchibernate,数据库是oracle,连接池druid。一般情况下,操作数据都是在DAO层进行处理。一种办法是使用多个DataSource然后创建多个SessionFa

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )