spring动态创建数据源、动态切换数据源-改进版

一、创建动态数据源

package com.yhbc.datasourceT;

import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

import org.apache.commons.lang3.StringUtils;
import org.hibernate.SessionFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.stereotype.Component;

import com.alibaba.druid.pool.DruidDataSource;
//@Component 不能有这个注解 ,xml的bean比他晚生成
public class RoutingDataSource extends AbstractRoutingDataSource {
private Map dataSources = new HashMap<>();
//@Autowired
//@Qualifier("dataSource")//根据xml的id写
private DruidDataSource defaultTargetDataSource ;//主数据源注入
JdbcTemplate jdbcTemplate;
protected SessionFactory sessionFactory;

 @Override
protected DataSource determineTargetDataSource() {
    // 根据数据库选择方案,拿到要访问的数据库
        String dataSourceName = (String) determineCurrentLookupKey();
        if(RoutingDataSourceContext.MASTER_DATASOURCE.equals(dataSourceName)) {
            // 访问默认主库
            return defaultTargetDataSource;
        }
        
        // 根据数据库名字,从已创建的数据库中获取要访问的数据库
        return (DataSource) this.dataSources.get(dataSourceName);

}

@Override
    protected Object determineCurrentLookupKey() {
        System.out.println("---determineCurrentLookupKey-----主数据源=="+defaultTargetDataSource);
        String dbName = RoutingDataSourceContext.getDataSourceRoutingKey();
        if (StringUtils.isEmpty(dbName)) {
            return RoutingDataSourceContext.getMainKey();
        }
        if (!dataSources.containsKey(dbName)){
            createAndSaveDataSource(dbName);
        } 
        return dbName;
    }
 
private synchronized void createAndSaveDataSource(String dbName) {
    DruidDataSource dataSource = createDruidDataSource(dbName);
    dataSources.put(dbName, dataSource);
    super.setTargetDataSources(dataSources);
    afterPropertiesSet();
}




/**
 * 根据配置创建DruidDataSource
 * @param fanDataSource
 * @return
 */
public  DruidDataSource createDruidDataSource(String dbName ) {
    
    if(dataSources.containsKey(dbName)){
        return (DruidDataSource) dataSources.get(dbName);
    }
    DruidDataSource dataSource = new DruidDataSource();
    dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    dataSource.setName(dbName);
    dataSource.setUrl("jdbc:mysql://192.168.1.13:3306/"+dbName+"?useUnicode=true&allowMultiQueries=true&useSSL=false");
    dataSource.setUsername("root");
    dataSource.setPassword("root");

    dataSource.setInitialSize(2);
    // 从池中取得链接时做健康检查,该做法十分保守
    dataSource.setTestOnBorrow(true);
    // 如果连接空闲超过1小时就断开
    dataSource.setMinEvictableIdleTimeMillis(1 * 60000 * 60);
    // 每十分钟验证一下连接
    dataSource.setTimeBetweenEvictionRunsMillis(600000);
    // 运行ilde链接测试线程,剔除不可用的链接
    dataSource.setTestWhileIdle(true);
    dataSource.setMaxWait(-1);
    return dataSource;
}

public void setDefaultTargetDataSource(DruidDataSource defaultTargetDataSource) {
    System.out.println("---setDefaultTargetDataSource-----主数据源=="+defaultTargetDataSource);
    this.defaultTargetDataSource = defaultTargetDataSource;
}

}

二、创建线程切换数据源工具类

package com.yhbc.datasourceT;

public class RoutingDataSourceContext {

static final ThreadLocal<String> threadLocalDataSourceKey = new ThreadLocal<>();
public static final String MASTER_DATASOURCE="defaultDataSource";

/**
 * 获取主数据库的key
 * @return
 */
public static String getMainKey() {
    return MASTER_DATASOURCE;
}

/**
 * 获取数据库key
 * @return
 */
public static String getDataSourceRoutingKey() {
    String key = threadLocalDataSourceKey.get();
    return key == null ? getMainKey() : key;
}

/**
 * 设置数据库的key
 * @param key
 */
public static void setThreadLocalDataSourceKey(String key) {
    threadLocalDataSourceKey.set(key);
}
/**
 * 还原默认的
 * @param key
 */
public static void remove() {
    threadLocalDataSourceKey.remove();
}

}

三、重要的一步,配置默认数据源bean,关联动态数据源类 RoutingDataSource

<beans:bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<beans:property name="driverClassName" value="{silverbox.driver}" /> <beans:property name="url" value="{silverbox.url}" />
<beans:property name="username" value="{silverbox.username}" /> <beans:property name="password" value="{silverbox.password}" />
<beans:property name="maxActive" value="{silverbox.maxActive}" /> <beans:property name="validationQuery" value="{silverbox.testSql}"/>
<beans:property name="testWhileIdle" value="true"/>
<beans:property name="initialSize" value="{silverbox.initialSize}"/> <beans:property name="maxWait" value="{silverbox.maxWait}"/>
</beans:bean>

<beans:bean id="routingDataSource" class="com.yhbc.datasourceT.RoutingDataSource">
    <beans:property name="targetDataSources">
        <beans:map key-type="java.lang.String">
             <beans:entry key="defaultDataSource" value-ref="dataSource" /> 
        </beans:map>
    </beans:property>
    <beans:property name="defaultTargetDataSource" ref="dataSource" ></beans:property>
</beans:bean>



<beans:bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <!-- <beans:property name="dataSource" ref="dataSource" /> -->
    <beans:property name="dataSource" ref="routingDataSource" />
    <beans:property name="packagesToScan">
        <beans:list>
            <beans:value>com.yhbc.entity</beans:value>
        </beans:list>
    </beans:property>
    <beans:property name="hibernateProperties">
        <beans:value>
            hibernate.dialect= org.hibernate.dialect.MySQLDialect
            hibernate.show_sql=false
            hibernate.format_sql=false
            hibernate.query.substitutions=true 1, false 0
            hibernate.jdbc.batch_size=20
            hibernate.cache.use_query_cache=false
            hibernate.cache.use_second_level_cache=true
            hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory
            hibernate.search.default.directory_provider=filesystem
            hibernate.search.default.indexBase=d:\\index
        </beans:value>
    </beans:property>
</beans:bean>

四、调用测试

@RequestMapping(value = { "/hybd-findfunction.htm" }, produces = "text/html;charset=UTF-8")
@ResponseBody
public String findfunction(String functionUsername,String dbtype) {
JSONObject jo=new JSONObject();
log.info("-----------------------------/hybd-add.htm");
try {
//silverbox_backup
/Dbs.setDbType("backup");
dynamicDataSource.determineTargetDataSource();
/
if(dbtype!=null){
//切换数据源,dbtype是数据库名称哦,这里的所有数据源默认都是相同的host,只是库的区别
//不能在service里面切换,determineTargetDataSource,在进入service前调用
RoutingDataSourceContext.setThreadLocalDataSourceKey(dbtype);
}

        System.out.println("sessionFactory==="+sessionFactory.toString());
        
        List<?> list=this.hYBDService.findFunction(functionUsername);
        
        jo.put("msg", "添加成功");
        jo.put("list", list);
        jo.put("success", true);
    } catch (Exception e) {
        jo.put("success", false);
       e.printStackTrace();
       log.error("error---hybd-add.htm-----:"+Utils.log4jDetail(e));
    }
    return jo.toJSONString();
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容