1. 程式人生 > >Spring + Mybatis配置多資料庫

Spring + Mybatis配置多資料庫

目前有兩種思路:

1.動態切換資料來源,需要自定義一個數據源類繼承自AbstractRoutingDataSource抽象類,這種方式有弊端,如果是併發系統中,當你把資料來源改了,系統中所有的操作資料來源都改了,即使你立馬再改回去,還是有風險;

2.建立兩套資料來源,在spring載入Mapper時關聯不同的資料來源。

以下僅介紹第二種方式:

(1)新建兩套資料來源:

資料來源一:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
	                    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd     
	                    http://www.springframework.org/schema/aop     
	                    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd     
	                    http://www.springframework.org/schema/tx      
	                    http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
	                    http://www.springframework.org/schema/context
    					http://www.springframework.org/schema/context/spring-context-3.0.xsd">
  
    
	<!-- 配置DataSource資料來源 -->
    <bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource"  
         destroy-method="close">  
         <!-- 資料庫驅動 -->  
         <property name="driverClass" value="${jdbc_driverClassName}" />  
         <!-- 相應驅動的jdbcUrl -->  
         <property name="jdbcUrl" value="${jdbc_url}" /> 
         <!-- 資料庫的使用者名稱 -->  
         <property name="username" value="${jdbc_username}" />  
         <!-- 資料庫的密碼 -->  
         <property name="password" value="${jdbc_password}" />  
       
       
         
        <!-- /** Maximum age of an unused connection before it is closed off. */ -->
		<!-- 設定分割槽個數。這個引數預設為1,建議3-4(根據特定應用程式而定)。
		 為了減少鎖競爭和改善效能,從當前執行緒分割槽(thread-affinity)中獲取一個connection,
		 也就是這個樣子:partitions[Thread.currentThread().getId() % partitionCount]。
		 當擁有充足的短期(short-lived)的執行緒時候,這個引數設定越大,效能越好。
		當超過一定的閥值時,連線池的維護工作就可能對效能造成一定的負面影響(僅當分割槽上的connection使用耗盡時) -->
		<property name="partitionCount" value="${db.partitionCount}" />
		
		<!-- 設定每個分割槽含有connection最大個數。這個引數預設為2。如果小於2,BoneCP將設定為50。
		比如:partitionCount設定為3,maxConnectionPerPartition設定為5,你就會擁有總共15個connection。
		注意:BoneCP不會將這些connection一起創建出來,而是說在需要更多connection的時候從minConnectionsPerPartition引數開始逐步地增長connection數量。  -->
		<property name="maxConnectionsPerPartition" value="${db.maxConnectionsPerPartition}" />
		
		<!-- 設定每個分割槽含有connection最大小個數。這個引數預設為0。  -->
		<property name="minConnectionsPerPartition" value="${db.minConnectionsPerPartition}" />
		
		<!-- 設定分割槽中的connection增長數量。這個引數預設為1。
		當每個分割槽中的connection大約快用完時,BoneCP動態批量建立connection,
		這個屬性控制一起建立多少個connection(不會大於maxConnectionsPerPartition)。
		注意:這個配置屬於每個分割槽的設定。  -->
		<property name="acquireIncrement" value="${db.acquireIncrement}" />
		
		<!-- 設定連線池閥值。這個引數預設為20。如果小於0或是大於100,BoneCP將設定為20。
		連線池觀察執行緒(PoolWatchThread)試圖為每個分割槽維護一定數量的可用connection。
		這個數量趨於maxConnectionPerPartition和minConnectionPerPartition之間。這個引數是以百分比的形式來計算的。
		例如:設定為20,下面的條件如果成立:Free Connections / MaxConnections < poolAvailabilityThreshold;就會創建出新的connection。
		換句話來說連線池為每個分割槽至少維持20%數量的可用connection。
		設定為0時,每當需要connection的時候,連線池就要重新建立新connection,這個時候可能導致應用程式可能會為了獲得新connection而小等一會。  -->
		<property name="poolAvailabilityThreshold" value="${db.poolAvailabilityThreshold}" />
		
		<!-- 設定獲取connection超時的時間。這個引數預設為Long.MAX_VALUE;單位:毫秒。
		在呼叫getConnection獲取connection時,獲取時間超過了這個引數,就視為超時並報異常。  -->
		<property name="connectionTimeoutInMs" value="${db.connectionTimeoutInMs}" />
		
		<!-- /** A connection older than maxConnectionAge will be destroyed and purged from the pool. */ -->
		<!-- 設定connection的存活時間。這個引數預設為0,單位:毫秒。設定為0該功能失效。
		通過ConnectionMaxAgeThread觀察每個分割槽中的connection,不管connection是否空閒,
		如果這個connection距離建立的時間大於這個引數就會被清除。當前正在使用的connection不受影響,直到返回到連線池再做處理。 -->
		<!-- 48小時關閉一個連結 -->
		<property name="maxConnectionAgeInSeconds" value="${db.maxConnectionAgeInSeconds}" />
		
		<!-- /** SQL statement to use for keep-alive/test of connection. */ -->
		<property name="connectionTestStatement" value="${db.connectionTestStatement}" />
		
		<!-- 設定connection的空閒存活時間。這個引數預設為60,單位:分鐘。設定為0該功能失效。
		通過ConnectionTesterThread觀察每個分割槽中的connection,如果這個connection距離最後使用的時間大於這個引數就會被清除。
		注意:這個引數僅和idleConnectionTestPeriodInSeconds搭配使用,而且不要在這裡設定任何挑釁的引數!  -->
		<!-- 1小時回收空閒連結 -->
		<property name="idleMaxAgeInMinutes" value="${db.idleMaxAgeInMinutes}" />
		
		<!-- /** Connections older than this are sent a keep-alive statement. */ -->
		<!-- 設定測試connection的間隔時間。這個引數預設為240*60,單位:分鐘。設定為0該功能失效。
		通過ConnectionTesterThread觀察每個分割槽中的connection, 
		如果這個connection距離最後使用的時間大於這個引數並且距離上一次測試的時間大於這個引數就會向資料庫傳送一條測試語句,如果執行失敗則將這個connection清除。
		注意:這個值僅和idleMaxAge搭配使用,而且不要在這裡設定任何挑釁的引數! -->
		<!-- 4小時檢測一次空閒連結 -->
		<property name="idleConnectionTestPeriodInMinutes" value="${db.idleConnectionTestPeriodInMinutes}" />
		
		<!-- /** After attempting to acquire a connection and failing, try to connect these many times before giving up. */ -->
		<!-- 設定重新獲取連線的次數。這個引數預設為5。
		獲取某個connection失敗之後會多次嘗試重新連線,如果在這幾次還是失敗則放棄。  -->
		<property name="acquireRetryAttempts" value="${db.acquireRetryAttempts}" />
		
		<!-- 設定重新獲取連線的次數間隔時間。這個引數預設為7000,單位:毫秒。如果小於等於0,BoneCP將設定為1000。
		獲取connection失敗之後再次嘗試獲取connection的間隔時間。  -->
		<property name="acquireRetryDelayInMs" value="${db.acquireRetryDelayInMs}" />
		
		<!-- 設定連線池初始化功能。這個引數預設為false。
		設定為true,連線池將會初始化為空,直到獲取第一個connection。  -->
		<property name="lazyInit" value="${db.lazyInit}" />
		
		<!-- 設定是否關閉JMX功能。這個引數預設為false。  -->
		<property name="disableJMX" value="${db.disableJMX}" />
		
		<!-- 設定連線池名字。用於當作JMX和助手執行緒名字的字尾。  -->
		<property name="poolName" value="${db.poolName}" />
		
		<!-- /** Min no of prepared statements to cache. */ -->
		<!-- 設定statement快取個數。這個引數預設為0。  -->
		<property name="statementsCacheSize" value="${db.statementsCacheSize}" />
		
		<!-- 設定是否開啟記錄SQL語句功能。這個引數預設是false。
		將執行的SQL記錄到日誌裡面(包括引數值)。  -->
		<property name="logStatementsEnabled" value="${db.logStatementsEnabled}" />
		
		<!-- 設定執行SQL的超時時間。這個引數預設為0;單位:毫秒。
		當查詢語句執行的時間超過這個引數,執行的情況就會被記錄到日誌中。
		設定為0時,該功能失效。   -->
		<property name="queryExecuteTimeLimitInMs" value="${db.queryExecuteTimeLimit}" />
     </bean>
	
	<!-- 對資料來源進行事務管理 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>      
		
	<!-- 配置SqlSessionFactoryBean -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		
		<!-- mapper和resultmap配置路徑 -->
		<property name="mapperLocations">
			<list>                
				<value>classpath:mapper/*Mapper.xml</value>
			</list>
		</property>
	</bean>        

	<tx:annotation-driven  transaction-manager="transactionManager" />  

</beans>

資料來源二:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
	                    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd     
	                    http://www.springframework.org/schema/aop     
	                    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd     
	                    http://www.springframework.org/schema/tx      
	                    http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
	                    http://www.springframework.org/schema/context
    					http://www.springframework.org/schema/context/spring-context-3.0.xsd">
  
    
	<!-- 配置DataSource資料來源 -->
    <bean id="dataSource2" class="com.jolbox.bonecp.BoneCPDataSource"  
         destroy-method="close">  
         <!-- 資料庫驅動 -->  
         <property name="driverClass" value="${jdbc_driverClassName}" />  
         <!-- 相應驅動的jdbcUrl -->  
         <property name="jdbcUrl" value="${jdbc_url2}" /> 
         <!-- 資料庫的使用者名稱 -->  
         <property name="username" value="${jdbc_username2}" />  
         <!-- 資料庫的密碼 -->  
         <property name="password" value="${jdbc_password2}" />  
       
       
         
        <!-- /** Maximum age of an unused connection before it is closed off. */ -->
		<!-- 設定分割槽個數。這個引數預設為1,建議3-4(根據特定應用程式而定)。
		 為了減少鎖競爭和改善效能,從當前執行緒分割槽(thread-affinity)中獲取一個connection,
		 也就是這個樣子:partitions[Thread.currentThread().getId() % partitionCount]。
		 當擁有充足的短期(short-lived)的執行緒時候,這個引數設定越大,效能越好。
		當超過一定的閥值時,連線池的維護工作就可能對效能造成一定的負面影響(僅當分割槽上的connection使用耗盡時) -->
		<property name="partitionCount" value="${db.partitionCount}" />
		
		<!-- 設定每個分割槽含有connection最大個數。這個引數預設為2。如果小於2,BoneCP將設定為50。
		比如:partitionCount設定為3,maxConnectionPerPartition設定為5,你就會擁有總共15個connection。
		注意:BoneCP不會將這些connection一起創建出來,而是說在需要更多connection的時候從minConnectionsPerPartition引數開始逐步地增長connection數量。  -->
		<property name="maxConnectionsPerPartition" value="${db.maxConnectionsPerPartition}" />
		
		<!-- 設定每個分割槽含有connection最大小個數。這個引數預設為0。  -->
		<property name="minConnectionsPerPartition" value="${db.minConnectionsPerPartition}" />
		
		<!-- 設定分割槽中的connection增長數量。這個引數預設為1。
		當每個分割槽中的connection大約快用完時,BoneCP動態批量建立connection,
		這個屬性控制一起建立多少個connection(不會大於maxConnectionsPerPartition)。
		注意:這個配置屬於每個分割槽的設定。  -->
		<property name="acquireIncrement" value="${db.acquireIncrement}" />
		
		<!-- 設定連線池閥值。這個引數預設為20。如果小於0或是大於100,BoneCP將設定為20。
		連線池觀察執行緒(PoolWatchThread)試圖為每個分割槽維護一定數量的可用connection。
		這個數量趨於maxConnectionPerPartition和minConnectionPerPartition之間。這個引數是以百分比的形式來計算的。
		例如:設定為20,下面的條件如果成立:Free Connections / MaxConnections < poolAvailabilityThreshold;就會創建出新的connection。
		換句話來說連線池為每個分割槽至少維持20%數量的可用connection。
		設定為0時,每當需要connection的時候,連線池就要重新建立新connection,這個時候可能導致應用程式可能會為了獲得新connection而小等一會。  -->
		<property name="poolAvailabilityThreshold" value="${db.poolAvailabilityThreshold}" />
		
		<!-- 設定獲取connection超時的時間。這個引數預設為Long.MAX_VALUE;單位:毫秒。
		在呼叫getConnection獲取connection時,獲取時間超過了這個引數,就視為超時並報異常。  -->
		<property name="connectionTimeoutInMs" value="${db.connectionTimeoutInMs}" />
		
		<!-- /** A connection older than maxConnectionAge will be destroyed and purged from the pool. */ -->
		<!-- 設定connection的存活時間。這個引數預設為0,單位:毫秒。設定為0該功能失效。
		通過ConnectionMaxAgeThread觀察每個分割槽中的connection,不管connection是否空閒,
		如果這個connection距離建立的時間大於這個引數就會被清除。當前正在使用的connection不受影響,直到返回到連線池再做處理。 -->
		<!-- 48小時關閉一個連結 -->
		<property name="maxConnectionAgeInSeconds" value="${db.maxConnectionAgeInSeconds}" />
		
		<!-- /** SQL statement to use for keep-alive/test of connection. */ -->
		<property name="connectionTestStatement" value="${db.connectionTestStatement}" />
		
		<!-- 設定connection的空閒存活時間。這個引數預設為60,單位:分鐘。設定為0該功能失效。
		通過ConnectionTesterThread觀察每個分割槽中的connection,如果這個connection距離最後使用的時間大於這個引數就會被清除。
		注意:這個引數僅和idleConnectionTestPeriodInSeconds搭配使用,而且不要在這裡設定任何挑釁的引數!  -->
		<!-- 1小時回收空閒連結 -->
		<property name="idleMaxAgeInMinutes" value="${db.idleMaxAgeInMinutes}" />
		
		<!-- /** Connections older than this are sent a keep-alive statement. */ -->
		<!-- 設定測試connection的間隔時間。這個引數預設為240*60,單位:分鐘。設定為0該功能失效。
		通過ConnectionTesterThread觀察每個分割槽中的connection, 
		如果這個connection距離最後使用的時間大於這個引數並且距離上一次測試的時間大於這個引數就會向資料庫傳送一條測試語句,如果執行失敗則將這個connection清除。
		注意:這個值僅和idleMaxAge搭配使用,而且不要在這裡設定任何挑釁的引數! -->
		<!-- 4小時檢測一次空閒連結 -->
		<property name="idleConnectionTestPeriodInMinutes" value="${db.idleConnectionTestPeriodInMinutes}" />
		
		<!-- /** After attempting to acquire a connection and failing, try to connect these many times before giving up. */ -->
		<!-- 設定重新獲取連線的次數。這個引數預設為5。
		獲取某個connection失敗之後會多次嘗試重新連線,如果在這幾次還是失敗則放棄。  -->
		<property name="acquireRetryAttempts" value="${db.acquireRetryAttempts}" />
		
		<!-- 設定重新獲取連線的次數間隔時間。這個引數預設為7000,單位:毫秒。如果小於等於0,BoneCP將設定為1000。
		獲取connection失敗之後再次嘗試獲取connection的間隔時間。  -->
		<property name="acquireRetryDelayInMs" value="${db.acquireRetryDelayInMs}" />
		
		<!-- 設定連線池初始化功能。這個引數預設為false。
		設定為true,連線池將會初始化為空,直到獲取第一個connection。  -->
		<property name="lazyInit" value="${db.lazyInit}" />
		
		<!-- 設定是否關閉JMX功能。這個引數預設為false。  -->
		<property name="disableJMX" value="${db.disableJMX}" />
		
		<!-- 設定連線池名字。用於當作JMX和助手執行緒名字的字尾。  -->
		<property name="poolName" value="${db.poolName}" />
		
		<!-- /** Min no of prepared statements to cache. */ -->
		<!-- 設定statement快取個數。這個引數預設為0。  -->
		<property name="statementsCacheSize" value="${db.statementsCacheSize}" />
		
		<!-- 設定是否開啟記錄SQL語句功能。這個引數預設是false。
		將執行的SQL記錄到日誌裡面(包括引數值)。  -->
		<property name="logStatementsEnabled" value="${db.logStatementsEnabled}" />
		
		<!-- 設定執行SQL的超時時間。這個引數預設為0;單位:毫秒。
		當查詢語句執行的時間超過這個引數,執行的情況就會被記錄到日誌中。
		設定為0時,該功能失效。   -->
		<property name="queryExecuteTimeLimitInMs" value="${db.queryExecuteTimeLimit}" />
     </bean>
			
	<!-- 配置SqlSessionFactoryBean -->
	<bean id="sqlSessionFactory2" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource2" />     
		
		<!-- mapper和resultmap配置路徑 -->
		<property name="mapperLocations">
			<list>                
				<value>classpath:mapper2/*Mapper.xml</value>
			</list>
		</property>
	</bean>        

</beans>
注意:(1)sqlSessionFactory2關聯的Mapper.xml的對映地址;(2)資料來源2中去除了事務管理的配置,否則使用事務時會找到兩個事務管理器,有興趣的可以研究下怎麼控制事務。

(2)在spring中掃描Mapper.java檔案:

	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="com.alan.test.mapper" />
		<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
	</bean>

	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="com.alan.test.mapper2" />
		<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory2"></property>
	</bean>

注意:關聯不同的包和sqlSessionFactory,這裡使用sqlSessionFactoryBeanName,而不是sqlSessionFactory;

如果只是關聯一個Mapper,則可以使用如下方式

<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
  <property name="mapperInterface" value="com.alan.test.mapper2.UserMapper" />
  <property name="sqlSessionFactory" ref="sqlSessionFactory2" />
</bean>

注意:mapper和mapper2中不能有相同的類名,因為掃描的時候會根據類名來新建bean託管給spring。

其它的Dao層等不用修改,在需要呼叫新資料庫的地方,呼叫對應的mapper就可以了。