Spring 多数据源连接配置 解决方案

List:

1.需求
2.实现
3.总结



……1.需求……


         数据库实例的管理和配置一般都是使用spring框架。项目中需要切换多个数据库,动态切换,在编码过程中,决定在哪个DB中写入或读取数据。还有,在大型应用中对数据进行切分,也是采用多个数据库实例进行管理,这样可以有效提高系统的水平伸缩性。所以spring提供AbstractRoutingDataSource为我们管理多个数据库实例。


……2.实现……


1.spring配置文件中配置数据库实例们

<!-- 多数据源配置 -->
	<!-- 数据库库一 -->
	<bean id="ds_ResourceManagementSystemPlat" class="org.apache.tomcat.jdbc.pool.DataSource">
		<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
		<property name="url" value="jdbc:sqlserver://ip:port;databaseName=ResourceManagementSystemPlat" />
		<property name="username" value="sa"/>
		<property name="password" value="pwd"/>
		<!-- (int) 最大空闲连接: 连接池中容许保持空闲状态的最大连接数量,
     	超过的空闲连接将被释放, 如果设置为负数表示不限制如果启用,将定期检查限制连接,
     	如果空闲时间超过minEvictableIdleTimeMillis 则释放连接 ( 参考testWhileIdle )  
     	-->
    	<property name="maxIdle" value="10" />
    	<!-- (int) 最小空闲连接: 连接池中容许保持空闲状态的最小连接数量, 低于这个数量将创建新的连接, 
    	如果设置为0 则不创建,如果连接验证失败将缩小这个值,默认与initialSize 相同 
    	-->
    	<property name="minIdle" value="10" />
    	<!-- (int) 最大活动连接: 连接池在同一时间能够分配的最大活动连接的数量, 
    	如果设置为非正数则表示不限制 
    	-->
    	<property name="maxActive" value="10" />
	    <!-- (int) 最大等待时间: 当没有可用连接时, 连接池等待连接被归还的最大时间( 以毫秒计数), 
	    	超过时间则抛出异常, 如果设置为-1 表示无限等待,默认30000(30秒) 
	    	-->
	    <property name="maxWait" value="10000" />
	    <!-- (int) 初始化连接: 连接池启动时创建的初始化连接数量 -->
	    <property name="initialSize" value="10" />
	    <!-- (boolean) 标记是否删除泄露的连接, 如果他们超过了removeAbandonedTimout 的限制。 
	    	如果设置为true, 连接被认为是被泄露并且可以被删除, 如果空闲时间超过removeAbandonedTimeout。 
	    	设置为true 可以为写法糟糕的没有关闭连接的程序修复数据库连接。 参考logAbandoned 
	    	-->
	    <property name="removeAbandoned" value="true" />
	    <!-- (int) 泄露的连接可以被删除的超时值, 单位秒应设置为应用中查询执行最长的时间 -->
	    <property name="removeAbandonedTimeout" value="600" />
	    <!-- 验证连接是否有效,(String) SQL 查询, 用来验证从连接池取出的连接, 在将连接返回给调用者
	    	之前。如果指定, 则查询必须是一个SQL SELECT 并且必须返回至少一行记录 查询不必返回记录,
	    	但这样将不能抛出SQL异常 
	    	-->
	    <property name="validationQuery" value="select 1" />
	    <!-- (long) 避免过度验证,保证验证不超过这个频率——以毫秒为单位。如果一个连接应该被验证,
	   	 但上次验证未达到指定间隔,将不再次验证。  30000(30秒) 
	   	 -->
	    <property name="validationInterval" value="30000" />
	    <!-- (boolean) 连接池创建的连接的默认的auto-commit 状态,driver default -->
	    <property name="defaultAutoCommit" value="true" />
	    <!-- 验证失败时,是否将连接从池中丢弃 -->
	    <property name="testWhileIdle" value="true" />
	    <!-- 把空闲时间超过minEvictableIdleTimeMillis毫秒的连接断开,
	    	直到连接池中的连接数到minIdle为止(毫秒,30分钟) 
	    	-->
	    <property name="timeBetweenEvictionRunsMillis" value="1200000" />
	    <!-- 连接池中连接可空闲的时间(毫秒,5分钟) -->
	    <property name="minEvictableIdleTimeMillis" value="1800000" />
	    <!-- 在每次空闲连接回收器线程(如果有)运行时检查的连接数量 -->
	    <property name="numTestsPerEvictionRun" value="5" />
	</bean>
	<!-- 数据库库二 -->
	<bean id="ds_TradeRoad" class="org.apache.tomcat.jdbc.pool.DataSource">
		<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
		<property name="url" value="jdbc:sqlserver://ip:port;databaseName=TradeRoad" />
		<property name="username" value="sa"/>
		<property name="password" value="pwd"/>
		<!-- (int) 最大空闲连接: 连接池中容许保持空闲状态的最大连接数量,
     	超过的空闲连接将被释放, 如果设置为负数表示不限制如果启用,将定期检查限制连接,
     	如果空闲时间超过minEvictableIdleTimeMillis 则释放连接 ( 参考testWhileIdle )  
     	-->
    	<property name="maxIdle" value="10" />
    	<!-- (int) 最小空闲连接: 连接池中容许保持空闲状态的最小连接数量, 低于这个数量将创建新的连接, 
    	如果设置为0 则不创建,如果连接验证失败将缩小这个值,默认与initialSize 相同 
    	-->
    	<property name="minIdle" value="10" />
    	<!-- (int) 最大活动连接: 连接池在同一时间能够分配的最大活动连接的数量, 
    	如果设置为非正数则表示不限制 
    	-->
    	<property name="maxActive" value="10" />
	    <!-- (int) 最大等待时间: 当没有可用连接时, 连接池等待连接被归还的最大时间( 以毫秒计数), 
	    	超过时间则抛出异常, 如果设置为-1 表示无限等待,默认30000(30秒) 
	    	-->
	    <property name="maxWait" value="10000" />
	    <!-- (int) 初始化连接: 连接池启动时创建的初始化连接数量 -->
	    <property name="initialSize" value="10" />
	    <!-- (boolean) 标记是否删除泄露的连接, 如果他们超过了removeAbandonedTimout 的限制。 
	    	如果设置为true, 连接被认为是被泄露并且可以被删除, 如果空闲时间超过removeAbandonedTimeout。 
	    	设置为true 可以为写法糟糕的没有关闭连接的程序修复数据库连接。 参考logAbandoned 
	    	-->
	    <property name="removeAbandoned" value="true" />
	    <!-- (int) 泄露的连接可以被删除的超时值, 单位秒应设置为应用中查询执行最长的时间 -->
	    <property name="removeAbandonedTimeout" value="600" />
	    <!-- 验证连接是否有效,(String) SQL 查询, 用来验证从连接池取出的连接, 在将连接返回给调用者
	    	之前。如果指定, 则查询必须是一个SQL SELECT 并且必须返回至少一行记录 查询不必返回记录,
	    	但这样将不能抛出SQL异常 
	    	-->
	    <property name="validationQuery" value="select 1" />
	    <!-- (long) 避免过度验证,保证验证不超过这个频率——以毫秒为单位。如果一个连接应该被验证,
	   	 但上次验证未达到指定间隔,将不再次验证。  30000(30秒) 
	   	 -->
	    <property name="validationInterval" value="30000" />
	    <!-- (boolean) 连接池创建的连接的默认的auto-commit 状态,driver default -->
	    <property name="defaultAutoCommit" value="true" />
	    <!-- 验证失败时,是否将连接从池中丢弃 -->
	    <property name="testWhileIdle" value="true" />
	    <!-- 把空闲时间超过minEvictableIdleTimeMillis毫秒的连接断开,
	    	直到连接池中的连接数到minIdle为止(毫秒,30分钟) 
	    	-->
	    <property name="timeBetweenEvictionRunsMillis" value="1200000" />
	    <!-- 连接池中连接可空闲的时间(毫秒,5分钟) -->
	    <property name="minEvictableIdleTimeMillis" value="1800000" />
	    <!-- 在每次空闲连接回收器线程(如果有)运行时检查的连接数量 -->
	    <property name="numTestsPerEvictionRun" value="5" />
	</bean>
	<!-- 数据库库三 -->
	<bean id="ds_TradeRoad_APP" class="org.apache.tomcat.jdbc.pool.DataSource">
		<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
		<property name="url" value="jdbc:sqlserver://ip:port;databaseName=TradeRoadAPP" />
		<property name="username" value="sa"/>
		<property name="password" value="pwd"/>
		<!-- (int) 最大空闲连接: 连接池中容许保持空闲状态的最大连接数量,
     	超过的空闲连接将被释放, 如果设置为负数表示不限制如果启用,将定期检查限制连接,
     	如果空闲时间超过minEvictableIdleTimeMillis 则释放连接 ( 参考testWhileIdle )  
     	-->
    	<property name="maxIdle" value="10" />
    	<!-- (int) 最小空闲连接: 连接池中容许保持空闲状态的最小连接数量, 低于这个数量将创建新的连接, 
    	如果设置为0 则不创建,如果连接验证失败将缩小这个值,默认与initialSize 相同 
    	-->
    	<property name="minIdle" value="10" />
    	<!-- (int) 最大活动连接: 连接池在同一时间能够分配的最大活动连接的数量, 
    	如果设置为非正数则表示不限制 
    	-->
    	<property name="maxActive" value="10" />
	    <!-- (int) 最大等待时间: 当没有可用连接时, 连接池等待连接被归还的最大时间( 以毫秒计数), 
	    	超过时间则抛出异常, 如果设置为-1 表示无限等待,默认30000(30秒) 
	    	-->
	    <property name="maxWait" value="10000" />
	    <!-- (int) 初始化连接: 连接池启动时创建的初始化连接数量 -->
	    <property name="initialSize" value="10" />
	    <!-- (boolean) 标记是否删除泄露的连接, 如果他们超过了removeAbandonedTimout 的限制。 
	    	如果设置为true, 连接被认为是被泄露并且可以被删除, 如果空闲时间超过removeAbandonedTimeout。 
	    	设置为true 可以为写法糟糕的没有关闭连接的程序修复数据库连接。 参考logAbandoned 
	    	-->
	    <property name="removeAbandoned" value="true" />
	    <!-- (int) 泄露的连接可以被删除的超时值, 单位秒应设置为应用中查询执行最长的时间 -->
	    <property name="removeAbandonedTimeout" value="600" />
	    <!-- 验证连接是否有效,(String) SQL 查询, 用来验证从连接池取出的连接, 在将连接返回给调用者
	    	之前。如果指定, 则查询必须是一个SQL SELECT 并且必须返回至少一行记录 查询不必返回记录,
	    	但这样将不能抛出SQL异常 
	    	-->
	    <property name="validationQuery" value="select 1" />
	    <!-- (long) 避免过度验证,保证验证不超过这个频率——以毫秒为单位。如果一个连接应该被验证,
	   	 但上次验证未达到指定间隔,将不再次验证。  30000(30秒) 
	   	 -->
	    <property name="validationInterval" value="30000" />
	    <!-- (boolean) 连接池创建的连接的默认的auto-commit 状态,driver default -->
	    <property name="defaultAutoCommit" value="true" />
	    <!-- 验证失败时,是否将连接从池中丢弃 -->
	    <property name="testWhileIdle" value="true" />
	    <!-- 把空闲时间超过minEvictableIdleTimeMillis毫秒的连接断开,
	    	直到连接池中的连接数到minIdle为止(毫秒,30分钟) 
	    	-->
	    <property name="timeBetweenEvictionRunsMillis" value="1200000" />
	    <!-- 连接池中连接可空闲的时间(毫秒,5分钟) -->
	    <property name="minEvictableIdleTimeMillis" value="1800000" />
	    <!-- 在每次空闲连接回收器线程(如果有)运行时检查的连接数量 -->
	    <property name="numTestsPerEvictionRun" value="5" />
	</bean>




2.编写spring配置文件配置多数据源映射关系


<!-- 动态配置数据源 -->
	<bean id="dataSource" class="com.jczb.trApp.teacher.datasource.DynamicDataSource">
		<property name="targetDataSources">
			<map key-type="java.lang.String">
				<entry value-ref="ds_ResourceManagementSystemPlat" key="ds_ResourceManagementSystemPlat"></entry>
				<entry value-ref="ds_TradeRoad" key="ds_TradeRoad"></entry>
				<entry value-ref="ds_TradeRoad_APP" key="ds_TradeRoad_APP"></entry>
			</map>
		</property>
		<!-- 默认使用ds1的数据源 -->
		<property name="defaultTargetDataSource" ref="ds_TradeRoad"></property>      
	</bean>



3.建立数据库名称常量类


public class DataSourceType {
	public static final String SOURCE_RMSP = "ds_ResourceManagementSystemPlat";
	public static final String SOURCE_TR = "ds_TradeRoad";
	public static final String SOURCE_TRAPP = "ds_TradeRoad_APP";
}


4.建立一个改变数据库实例的上下文类


          ThreadLocal是解决线程安全问题一个很好的思路,它通过为每个线程提供一个独立的变量副本解决了变量并发访问的冲突问题。在很多情况下,ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简单,更方便,且结果程序拥有更高的并发性。



public class DataSourceContextHolder {
	private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();


	public static void setDbType(String dbType) {
		contextHolder.set(dbType);
	}


	public static String getDbType() {
		return ((String) contextHolder.get());
	}


	public static void clearDbType() {
		contextHolder.remove();
	}
}



5.建立动态数据源类


       AbstractRoutingDataSource中的抽象方法determineCurrentLookupKey是实现数据源的route的核心。


public class DynamicDataSource extends AbstractRoutingDataSource {
	@Override
	protected Object determineCurrentLookupKey() {
		return DataSourceContextHolder.getDbType();
	}
}



……3.总结……


         优点:改动不大,还是用spring配置,可以兼容单数据实例和多数据实例,因为可以指定一个缺省的。便于维护。
         But,缺点是,当多用户访问时,多数据源可能会导致系统性能下降。引起资源的争抢。




          当初做权限的时候还不知道这个用法,学习了。






评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值