【Web项目多数据源切换-个人梳理】

package com.dclw.Common;

import com.dclw.Common.model.BasicDataSource;
import com.dclw.Common.model.CenterDatebase;
import com.dclw.Service.SystemConfigServie;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import javax.sql.DataSource;
import javax.transaction.SystemException;
import java.util.HashMap;
import java.util.Map;

/**
 * Copyright: Copyright(c) 2017 xxxxx
 *
 * @作者 李富业
 * @版本
 * @日期 创建日期:2017/2/26
 * @描述:
 */
public class DynamicDataSource1 extends AbstractRoutingDataSource {

    @Autowired
    private SystemConfigServie systemConfigServie;
    // 默认数据源,也就是主库
    protected javax.sql.DataSource masterDataSource;
    // 保存动态创建的数据源
    private static final Map targetDataSource = new HashMap<>();

    private static final ThreadLocal<String> dbs = new ThreadLocal<String>();

    @Override
    protected javax.sql.DataSource determineTargetDataSource() {
        // 根据数据库选择方案,拿到要访问的数据库
        String dataSourceName = determineCurrentLookupKey();
        if("dataSource".equals(dataSourceName)) {
            // 访问默认主库
            return masterDataSource;
        }

        // 根据数据库名字,从已创建的数据库中获取要访问的数据库
        javax.sql.DataSource dataSource = (javax.sql.DataSource) targetDataSource.get(dataSourceName);
        if(null == dataSource) {
            // 从已创建的数据库中获取要访问的数据库,如果没有则创建一个
            try {
                dataSource = this.selectDataSource(dataSourceName);
            } catch (SystemException e) {
                e.printStackTrace();
            }
        }
        return dataSource;
    }

    @Override
    protected String determineCurrentLookupKey() {
        String dataSourceName = dbs.get();
        if (dataSourceName == null || dataSourceName == "dataSource") {
            // 默认的数据源名字
            dataSourceName = "dataSource";
        }
        return dataSourceName;
    }

    public void addTargetDataSource(String key, BasicDataSource dataSource) {
        targetDataSource.put(key, dataSource);
    }


    /**
     * 该方法为同步方法,防止并发创建两个相同的数据库
     * 使用双检锁的方式,防止并发
     * @param dbType
     * @return
     */
    private synchronized DataSource selectDataSource(String dbType) throws SystemException {
        // 再次从数据库中获取,双检锁
        javax.sql.DataSource obj = (javax.sql.DataSource)targetDataSource.get(dbType);
        if (null != obj) {
            return obj;
        }
        // 为空则创建数据库
        BasicDataSource dataSource = this.getDataSource(dbType);
        if (null != dataSource) {
            // 将新创建的数据库保存到map中
            this.setDataSource(dbType, dataSource);
            return dataSource;
        }else {
            throw new SystemException("创建数据源失败!");
        }
    }

    /**
     * 查询对应数据库的信息
     * @param dbtype
     * @return
     */
    private BasicDataSource getDataSource(String dbtype) {
        String oriType = dbs.get();
        // 先切换回主库
        dbs.set("dataSource");
        // 查询所需信息
        CenterDatebase datebase = systemConfigServie.centerDatebaseManagerById(dbtype);
        // 切换回目标库
        dbs.set(oriType);
        String url = "jdbc:sqlserver://" + datebase.getIp() + ":1433"
                + ";DatabaseName=" + datebase.getDataBaseName();
        BasicDataSource dataSource = createDataSource(url,datebase.getUserName(),datebase.getPassWord());
        return dataSource;
    }

    //创建SQLServer数据源
    private BasicDataSource createDataSource(String url,String userName,String password) {
        return createDataSource("com.microsoft.sqlserver.jdbc.SQLServerDriver", url, userName, password);
    }

    //创建数据源
    private BasicDataSource createDataSource(String driverClassName, String url,
                                             String username, String password) {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setTestWhileIdle(true);
        return dataSource;
    }

    public void setDataSource(String type, BasicDataSource dataSource) {
        this.addTargetDataSource(type, dataSource);
        dbs.set(type);
    }

    /**
     * 该方法重写为空,因为AbstractRoutingDataSource类中会通过此方法将,targetDataSources变量中保存的数据源交给resolvedDefaultDataSource变量
     * 在本方案中动态创建的数据源保存在了本类的targetDataSource变量中。如果不重写该方法为空,会因为targetDataSources变量为空报错
     * 如果仍然想要使用AbstractRoutingDataSource类中的变量保存数据源,则需要在每次数据源变更时,调用此方法来为resolvedDefaultDataSource变量更新
     */
    @Override
    public void afterPropertiesSet() {
    }

    public javax.sql.DataSource getMasterDataSource() {
        return masterDataSource;
    }

    public void setMasterDataSource(DataSource masterDataSource) {
        this.masterDataSource = masterDataSource;
    }
}

BasicDataSource.java
package com.dclw.Common.model;

import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

/**
 * Copyright: Copyright(c) 2018 xxxxx
 *
 * @作者 李富业
 * @版本
 * @日期 创建日期:2017/2/26
 * @描述:
 */
public class BasicDataSource  implements DataSource{

    private String driverClassName;
    private String url;
    private String username;
    private String password;
    private boolean testWhileIdle;

    public String getDriverClassName() {
        return driverClassName;
    }

    public void setDriverClassName(String driverClassName) {
        this.driverClassName = driverClassName;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public boolean isTestWhileIdle() {
        return testWhileIdle;
    }

    public void setTestWhileIdle(boolean testWhileIdle) {
        this.testWhileIdle = testWhileIdle;
    }


    private List<Connection> pool = new ArrayList<Connection>();

    @Override
    public Connection getConnection() throws SQLException {
        return null;
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        synchronized (pool) {
            while (true) {
                if (pool.size() == 0) {
                    try {
                        pool.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                } else {
                    return pool.remove(0);
                }
            }
        }
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return null;
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return false;
    }

    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return null;
    }

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {

    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {

    }

    @Override
    public int getLoginTimeout() throws SQLException {
        return 0;
    }

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值