在spring中配置多数据库读取

在应对大量用户读取的系统中,对数据库的操作通常采用读写分离方式,往一个数据库写入,然后通过复制将数据同步到另外的多个数据库中,读操作都从这些数据库中操作,在采用spring来配置多数据库时,并不能直接支持从多个DataSource中获得数据库连接,为此需要开发一个DataSource的代理,代理实现javax.sql.DataSource接口。该代理根据一定的策略从已有的多个DataSource中选择一个,提供给SessionFactory,供数据访问层使用。原理如下图所示:



DataSource Proxy选择DataSource的方式可以根据实际进行设计,这里为简单,就采用随机方式选择一个。源代码如下:

package code;

import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;

import java.util.List;
import java.util.Random;

import javax.sql.DataSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class RandomDataSource  implements DataSource {

	private List<DataSource> dataSourcePool ;
	protected Log log =  LogFactory.getLog(getClass());
	
	private  static ThreadLocal<DataSource> dsHolder = new ThreadLocal<DataSource>();
	
	
	/**
	 * 从已有DataSource中随机选择一个
	 *
	 *
	 */
	private DataSource randomDs(){
		
		int size = dataSourcePool.size();
		
		Random r= new Random();
		
		int t = r.nextInt(size);
		
		dsHolder.set(dataSourcePool.get(t));
		return dsHolder.get();
		
		
	}
	
	
	@Override
	public Connection getConnection() throws SQLException {
		
		Connection conn = randomDs().getConnection();
		log.info("conn URL---->"+conn.getMetaData().getURL());
		return conn;
	}

	@Override
	public Connection getConnection(String username, String password)
			throws SQLException {
		// TODO Auto-generated method stub
		
		Connection conn = randomDs().getConnection(username, password);
		
		
		return conn;
	}

	@Override
	public PrintWriter getLogWriter() throws SQLException {
		
		return dsHolder.get().getLogWriter();
	}

	@Override
	public int getLoginTimeout() throws SQLException {
		// TODO Auto-generated method stub
		return dsHolder.get().getLoginTimeout();
	}

	@Override
	public void setLogWriter(PrintWriter out) throws SQLException {
		// TODO Auto-generated method stub
		dsHolder.get().setLogWriter(out);
	}

	@Override
	public void setLoginTimeout(int seconds) throws SQLException {
		// TODO Auto-generated method stub
		dsHolder.get().setLoginTimeout(seconds);
	}

	@Override
	public boolean isWrapperFor(Class<?> iface) throws SQLException {
		// TODO Auto-generated method stub
		return dsHolder.get().isWrapperFor(iface);
	}

	@Override
	public <T> T unwrap(Class<T> iface) throws SQLException {
		// TODO Auto-generated method stub
		return dsHolder.get().unwrap(iface);
	}

	public List<DataSource> getDataSourcePool() {
		return dataSourcePool;
	}

	public void setDataSourcePool(List<DataSource> dataSourcePool) {
		
		this.dataSourcePool = dataSourcePool;
	}

}



为了可用性,实际生产环境中需要判断取到的DataSource对应的数据库是否可访问,若不能访问,则要取其他可用的DataSource。


在springframework中的配置如下:

<bean id="dataSource" class="code.RandomDataSource">
 		<property name="dataSourcePool">
 			<list>
 				<ref bean="dataSource1" />
 				<ref bean="dataSource2" />
 			</list>
 		</property>
 	</bean>
 	
	
	<bean id="dataSource1" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
		<property name="driverClass" value="com.mysql.jdbc.Driver"/>
		<property name="jdbcUrl" value="jdbc:mysql://192.168.2.192/ebook"/>
		<property name="user" value="test"/>
		<property name="password" value="test"/>
	</bean>
	
	 <bean id="dataSource2" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
		<property name="driverClass" value="com.mysql.jdbc.Driver"/>
		<property name="jdbcUrl" value="jdbc:mysql://192.168.2.105/ebook"/>
		<property name="user" value="test"/>
		<property name="password" value="test"/>
	</bean>
	
	
	<!-- Hibernate SessionFactory -->
	<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
				<prop key="hibernate.show_sql">true</prop>
				<prop key="hibernate.format_sql">true</prop>
				
			</props>
		</property>
		<property name="dataSource" ref="dataSource"/>
		
		
	</bean>


这里连接的是MySQL数据库,如果是其他数据库,需要将DataSource1和DataSource2中的参数以及hibernate.dialect做相应修改。




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值