码迷,mamicode.com
首页 > 编程语言 > 详细

saas模式下的spring多数据源管理

时间:2015-03-30 21:10:52      阅读:269      评论:0      收藏:0      [点我收藏+]

标签:saas   数据源   spring   spring多数据源管理   

开发saas程序时,要求每个公司使用一个数据库,当使用spring时如何配置数据源使得每个公司使用不同的数据库连接?

1、将公司id存放到一个ThreadLocal变量中,每次请求时设置,使得每次访问数据源可以从ThreadLocal获取当前请求所属的公司id。

/**
 * 用来存放当前线程的数据
 */
public class ThreadHolder {
	//公司id
	private static ThreadLocal<String> localDid = new ThreadLocal<String>();

	public static void putSp(String sp) {
		localDid.set(sp);
	}

	public static String getSp() {
		if (localDid.get() == null)
			return "";
		else
			return (String)localDid.get();
	}
}
2、在每次请求时调用ThreadHolder.putSp方法设置公司id。
可以定义一个filter,在doFilter方法中调用即可达到每次请求设置的效果。至于客户端请求的公司id参数放在哪里,这个可以灵活设置,可以放在每个请求的request参数中,也可以放在cookie中


3、修改spring数据源配置
原配置(一般使用c0p3数据原的配置)

	<bean id="dataSource"
		class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="xxxx" />
		<property name="jdbcUrl" value="xxx" />
		<property name="user" value="user" />
		<property name="password" value="password" />
		<property name="minPoolSize" value="1" />
		<property name="maxPoolSize" value="800" />
		<property name="maxIdleTime" value="25000" />
		<property name="acquireIncrement" value="1" />
		<property name="maxStatements" value="0" />
		<property name="initialPoolSize" value="100" />
		<property name="idleConnectionTestPeriod" value="18000" />
		<property name="acquireRetryAttempts" value="10" />
		<property name="acquireRetryDelay" value="1000" />
		<property name="breakAfterAcquireFailure" value="false" />
		<property name="checkoutTimeout" value="10000" />
		<property name="testConnectionOnCheckout" value="false" />
	</bean>
修改成:

    <bean id="dataSource" class="com.sangfor.frame.multiclient.MultiClientDataSource">  
        <property name="dataSource">  
            <ref bean="dataSourceDefault" />  
         </property>  
    </bean>  
	<bean id="dataSourceDefault"
		class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="xxxx" />
		<property name="jdbcUrl" value="xxx" />
		<property name="user" value="user" />
		<property name="password" value="password" />
		<property name="minPoolSize" value="1" />
		<property name="maxPoolSize" value="800" />
		<property name="maxIdleTime" value="120" />
		<property name="acquireIncrement" value="1" />
		<property name="maxStatements" value="0" />
		<property name="initialPoolSize" value="100" />
		<property name="idleConnectionTestPeriod" value="65" />
		<property name="acquireRetryAttempts" value="10" />
		<property name="acquireRetryDelay" value="1000" />
		<property name="breakAfterAcquireFailure" value="false" />
		<property name="checkoutTimeout" value="10000" />
	</bean>
MultiClientDataSource:

public class MultiClientDataSource implements DataSource {

	public static final String DBNAME_PREFIX = "CLIENT_";
	private ComboPooledDataSource dataSource = null;
	private Map<String,DataSource> dsMap = new HashMap<String,DataSource>();
	private static Object lock=new Object(); 
	
	public DataSource addDataSource(String did){
		try{
			synchronized (lock) {
				if (dsMap==null)
					dsMap = new HashMap<String,DataSource>();
				DataSource ds = dsMap.get(did);
				if (ds != null)
					return ds;
				ComboPooledDataSource newDs = getNewDataSource(did);
				dsMap.put(did, newDs);
			}
		}catch(Exception e){
			e.printStackTrace();
		}
		return dsMap.get(did);
	}
	public void removeDataSource(String did){
		if (dsMap==null)
			return;
		dsMap.remove(did);
	}
	private ComboPooledDataSource getNewDataSource(String did) throws Exception{
		ComboPooledDataSource ds = new ComboPooledDataSource();
		ds.setDriverClass("xxx");//driver class
		String jdbcUrl = "jdbc:mysql://127.0.0.1" //一般将ip配置在配置文件
				+":3306"+"/"+ DBNAME_PREFIX + did
				+ "?useUnicode=true&characterEncoding=utf-8";
		ds.setJdbcUrl(jdbcUrl);
		ds.setUser("user");
		ds.setPassword("password");
		ds.setMinPoolSize(1);
		ds.setMaxPoolSize(800);
		ds.setMaxIdleTime(2000);
		ds.setAcquireIncrement(1);
		ds.setMaxStatements(0);
		ds.setInitialPoolSize(100);
		ds.setIdleConnectionTestPeriod(1800);
		ds.setAcquireRetryAttempts(10);
		ds.setAcquireRetryDelay(1000);
		ds.setBreakAfterAcquireFailure(false);
		ds.setCheckoutTimeout(10000);
		ds.setPreferredTestQuery(" select FORMID from FLOW_FORM where 1 = 2");
		ds.setTestConnectionOnCheckout(false);
		return ds;
	}
	
	private void initDsMap()throws Exception{
		try{
			if (dsMap==null){
				dsMap = new HashMap<String,DataSource>();
			}
		}catch(Exception e){
			throw new Exception(e);			
		}
	}
	
	public Connection getConnection() throws SQLException {
		return getDataSource().getConnection();
	}

	public Connection getConnection(String arg0, String arg1)
			throws SQLException {
		return getDataSource().getConnection(arg0, arg1);
	}

	public PrintWriter getLogWriter() throws SQLException {
		return getDataSource().getLogWriter();
	}

	public int getLoginTimeout() throws SQLException {
		return getDataSource().getLoginTimeout();
	}

	public void setLogWriter(PrintWriter arg0) throws SQLException {
		getDataSource().setLogWriter(arg0);
	}

	public void setLoginTimeout(int arg0) throws SQLException {
		getDataSource().setLoginTimeout(arg0);
	}
	public DataSource getDataSource(String dataSourceName)throws SQLException {
		try{
			if(dataSourceName==null||dataSourceName.equals("")){
				return this.dataSource;
			}else{
				DataSource ds = dsMap.get(dataSourceName);
				if (ds!=null)
					return ds;
				else
					return null;
			}
		}catch(NoSuchBeanDefinitionException ex){
			throw new SQLException("There is not the dataSource <name:"+dataSourceName+"> in the applicationContext!");
		}
	}
	
	public void setDataSource(ComboPooledDataSource dataSource) {
		this.dataSource = dataSource;
	}

	public ComboPooledDataSource getDataSource()throws SQLException{
		
		String did = ThreadHolder.getSp();
		DataSource  ds = getDataSource(did);
		if (ds == null)
			return null;
		else
			return (ComboPooledDataSource)ds;
	}
	public DataSource getDefaultDataSource()throws SQLException{
		
		return dataSource;
	}
	@Override
	public boolean isWrapperFor(Class<?> arg0) throws SQLException {
		// TODO Auto-generated method stub
		return false;
	}
	@Override
	public <T> T unwrap(Class<T> arg0) throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

}
实现原理:
自己新建一个MultiClientDataSource类(实现DataSource接口)去代替原来注入dataSource的ComboPooledDataSource,MultiClientDataSource类的实现精华在于使用一个map,用公司id(did)作为key,value为connection,在getConnection方法中判断是否在map中已经有该did的key,如果没有就新建connection,并且加入到map中




saas模式下的spring多数据源管理

标签:saas   数据源   spring   spring多数据源管理   

原文地址:http://blog.csdn.net/kingofworld/article/details/44757079

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!