`

spring动态数据源的切换

 
阅读更多

目前项目框架很简单,spring+spring jdbc。

客户想,

1,临时添加一个数据源,然后切换到此数据源,进行操作。

2,能保证每个数据源的表结构是统一的。

 

解决思路,spring jdbc用到的是jdbctemplate, jdbctemplate需要一个datasource。实现一个datasource,

把“判断连接哪个数据源”的条件存在 ThreadLocal 中,这样在自己的datasource里,就可以取出来使用。而不用

在service和dao中该代码了。

 

1,在controller层中切换数据源。根据id在一个固定数据源()中查找已经储存的数据源信息,把需要切换的数据源和当前登录用户绑定起来(这里自己任意实现)。

 

 

public String changeDBSource(){
		if( !StringUtils.isBlank(id) ){
			dbSource = databaseSourceService.findDBSourceById(id);
			boolean b = false;
			if(b){
				//用户登录情况下,把dbSource与用户绑定。
			}else{
				//没有登录的情况下
				ActionContext.getContext().getSession().put(DatabaseObserver.DBKEY, dbSource);
			}
			DatabaseObserver.put(dbSource);
		}
		if( StringUtils.isBlank(dbSource.getId())){
			flag = "0";
		}else{
			flag = "1";
		}
		return "changeResult";
}

 附上DatabaseObserver的代码,很简单

 

public class DatabaseObserver {
    public static final String DBKEY = "dbkey";
    private static ThreadLocal <DatabaseSource> dbSource = new ThreadLocal<DatabaseSource>();    
    public static void put (DatabaseSource dbs)    
    {    
    	dbSource.set(dbs);    
    }    
    public static DatabaseSource get ()    
    {    
       return (DatabaseSource)dbSource.get();    
    }    
        
}   
 

 

 

2,与用户绑定后,用一个Filter过滤所有请求,把与用户绑定的数据源信息,通过DatabaseObserver写到ThreadLocal中。

 

 

public class ServerFilter extends HttpServlet implements Filter {   
    private static final long serialVersionUID = 6452049924844786456L;   
    private static FilterConfig filterConfig;   
    public void destroy() {   
        // TODO Auto-generated method stub   
    }   
    public void init(FilterConfig filterConfig) throws ServletException   
    {   
    }   
    public void doFilter(ServletRequest request, ServletResponse response,   
            FilterChain filterChain) throws IOException, ServletException {   
    	boolean b = false;
    	//如果用户登录了,则把数据源信息与用户绑定
    	HttpServletRequest httpRequest = (HttpServletRequest)request;
    	if(b==true){
    	}
    	else{
    		//没有登录的情况下
    		DatabaseSource dbSource = (DatabaseSource)httpRequest.getSession().getAttribute(DatabaseObserver.DBKEY);
    		if(dbSource!=null){
    			DatabaseObserver.put(dbSource);
    		}
    	}
        filterChain.doFilter(request, response);   
    }   
}
 

 

3,最后在自己实现的datasource中,根据Threadlocal的数据源信息,返回的datasource。

 

 

public class DataSourceWithCache implements DataSource { 
 
    private static Map<String, DataSource> sources = new HashMap<String, DataSource>(); 

    @Resource
    private IDatabaseSourceService databaseSourceService ;
    
    private DataSource getDataSource() { 
        DatabaseSource dbSource = DatabaseObserver.get();
        if( dbSource == null ){
        	List<DatabaseSource> dbList = databaseSourceService.findBDSourcesByCond(dbSource, 0	, 1);
        	if(dbList.size()>0){
        		dbSource = dbList.get(0);
        	}
            if( dbSource == null ){
            	return null;
            }
        }
        DataSource source = sources.get(dbSource.getId()); 
        if (source == null) { 
            source = createSource(dbSource);
            sources.put(dbSource.getId(), source); 
        } 
        return source; 
    } 
 
    private DataSource createSource( DatabaseSource dbSource  ) { 
        SingleConnectionDataSource source = new SingleConnectionDataSource(); 
        source.setDriverClassName("com.mysql.jdbc.Driver"); 
        source.setUrl(dbSource.getUrl()); 
        source.setUsername(dbSource.getUsername()); 
        source.setPassword(dbSource.getPassword()); 
        source.setSuppressClose(true); 
        return source; 
    } 
 
    @Override 
    public Connection getConnection() throws SQLException { 
        return getDataSource().getConnection(); 
    } 
 
    @Override 
    public Connection getConnection(String username, String password) 
            throws SQLException { 
        return getDataSource().getConnection(username, password); 
    } 
 
    @Override 
    public PrintWriter getLogWriter() throws SQLException { 
        return getDataSource().getLogWriter(); 
    } 
 
    @Override 
    public int getLoginTimeout() throws SQLException { 
        return getDataSource().getLoginTimeout(); 
    } 
 
    @Override 
    public void setLogWriter(PrintWriter out) throws SQLException { 
        getDataSource().setLogWriter(out); 
 
    } 
 
    @Override 
    public void setLoginTimeout(int seconds) throws SQLException { 
        getDataSource().setLoginTimeout(seconds); 
    } 
 
    @Override 
    public boolean isWrapperFor(Class<?> iface) throws SQLException { 
        return getDataSource().isWrapperFor(iface); 
    } 
 
    @Override 
    public <T> T unwrap(Class<T> iface) throws SQLException { 
        return getDataSource().unwrap(iface); 
    }

	public IDatabaseSourceService getDatabaseSourceService() {
		return databaseSourceService;
	}

	public void setDatabaseSourceService(IDatabaseSourceService databaseSourceService) {
		this.databaseSourceService = databaseSourceService;
	}
    
}
 

 

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics