加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

SpringMVC多数据源动态加载切换

(2014-09-17 12:43:19)
标签:

多数据源

spring

分类: Java/Spring/Mysql
最近在做SpringMVC相关的开发,遇到多个数据源的问题,研究了很久终于解决了。初步有两个方案:
(1)在配置文件里配置好所有的数据源,在需要的时候根绝数据源的名字动态切换。无疑这样做是可行的,如果数据源不经常变化或者数据源较少的话,可以采取这样的策略。
(2)在程序中根据需要动态的创建数据源,并切换。这样想法是最优的,难度也比较大。

在此主要记录了第二中方案的一些做法:
1.首先在applicationContext.xml文件中添加:

       
           
       
       
   
   
   
   
       
       
   
2.然后编写数据源的切换:

public final class Dbs {
   
    private static final ThreadLocal local = new ThreadLocal();
   
    public static String getDbType(){
        return local.get();
    }
   
    public static void setDbType(String dbName){
        local.set(dbName);
    }
   
    public static void clear(){
        local.remove();
    }
}

3.编写一个动态的数据源完成创建切换数据源的任务:
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.dbcp.BasicDataSource;
import org.apache.log4j.Logger;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;


public class DynamicDataSource extends AbstractRoutingDataSource {

    private Logger log = Logger.getLogger(this.getClass());
    private Map targetDataSource = null;

    @Override
    protected Object determineCurrentLookupKey() {
        // TODO Auto-generated method stub
        String dataSourceName = Dbs.getDbType();
        if (dataSourceName == null) {
            // 默认的数据源名字
            dataSourceName = "dataSource";
        } else {
            this.selectDataSource(dataSourceName);
            if (dataSourceName.equals("0")) {
                dataSourceName = "dataSource";
            }
        }
        log.debug("use datasource : " + dataSourceName);
        return dataSourceName;
    }

    public void setTargetDataSource(Map targetDataSource) {
        this.targetDataSource = targetDataSource;
        super.setTargetDataSources(this.targetDataSource);
    }
   
    public Map getTargetDataSource(){
        return this.targetDataSource;
    }

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

    public BasicDataSource createDataSource(String url) {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl(url);
        dataSource.setUsername("app_userlevel1");
        dataSource.setPassword("app_userlevel1");
        dataSource.setTestWhileIdle(true);

        return dataSource;
    }

    public 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 selectDataSource(String dbType) {
        Object sid = Dbs.getDbType();
        if ("0".equals(dbType)) {
            Dbs.setDbType("0");
            return;
        }
        Object obj = this.targetDataSource.get(dbType);
        if (null != obj && sid.equals(dbType)) {
            return;
        } else {
            BasicDataSource dataSource = this.getDataSource(dbType);
            if(null != dataSource){
                this.setDataSource(dbType, dataSource);
            }
        }
    }

   
    public BasicDataSource getDataSource(String dbtype) {
        this.selectDataSource("0");
        this.determineCurrentLookupKey();
        Connection conn = null;
        HashMap map = null;

        try {
            conn = this.getConnection();
            PreparedStatement ps = conn
                    .prepareStatement("SELECT * FROM dbs WHERE active = 'y' and type = ?");
            ps.setString(1, dbtype);
            ResultSet rs = ps.executeQuery();
            map = new HashMap();

            if (rs.next()) {
                map.put("active", rs.getString("active"));
                map.put("db_name", rs.getString("db_name"));
                map.put("ip", rs.getString("ip"));
                map.put("port", rs.getInt("port"));
                map.put("type", rs.getString("type"));
            }
            rs.close();
            ps.close();
        } catch (SQLException e) {
            log.error(e);
        } finally {
            try {
                conn.close();
            } catch (SQLException e) {
                log.error(e);
            }
        }
        if (null != map) {
            String url = "jdbc:mysql://" + map.get("ip") + ":"
                    + map.get("port") + "/" + map.get("db_name")
                    + "?useUnicode=true&characterEncoding=utf-8";
            BasicDataSource dataSource = createDataSource(url);
            return dataSource;
        }
        return null;
    }
   
    public void setDataSource(String type, BasicDataSource dataSource){
        this.addTargetDataSource(type, dataSource);
        Dbs.setDbType(type);
    }

    @Override
    public void setTargetDataSources(Map targetDataSources) {
        // TODO Auto-generated method stub
        super.setTargetDataSources(targetDataSources);
        //重点:通知container容器数据源发生了变化
        super.afterPropertiesSet();
     
}

这样在spring的controller中就可以简单的使用Dbs.setDbType("databasename")来切换需要的数据源了。

苦苦研究了三四天,记录一下以备后用。

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有