天天看點

spring+hibernate動态切換資料源

動态切換資料源确切的來說是在同一類型資料庫的情況下的。意思就是說 , 在系統中的使用的資料庫分布在多台資料庫伺服器或者在同台伺服器上的多個資料庫. 在運作時期間根據某種辨別符來動态的選擇目前操作的資料庫.

  1. 資料源是相同類型的資料庫: 一個SessionFactory+動态資料源+一個事務管理器
  2. 資料源是不同類型的資料庫: 根據類型 配置多套SessionFactory

spring配置

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <bean id="transactionInterceptor"
          class="org.springframework.transaction.interceptor.TransactionInterceptor">
         <property name="transactionManager" ref="transactionManager"/>
         <property name="transactionAttributes">
        <!--  如果還有其他的發放類型需要進行事務的統一處理,請修改此處的key值和事務等級  -->
        <props>
             <prop key="insert*">PROPAGATION_REQUIRES_NEW</prop>            
             <prop key="save*">PROPAGATION_REQUIRED</prop>
             <prop key="add*">PROPAGATION_REQUIRED</prop>
			 <prop key="update*">PROPAGATION_REQUIRED</prop>
			 <prop key="upadate*">PROPAGATION_REQUIRED</prop>
			 <prop key="delete*">PROPAGATION_REQUIRED</prop>
			 <prop key="import*">PROPAGATION_REQUIRED</prop>
			 <prop key="remove*">PROPAGATION_REQUIRED</prop>
			 <prop key="cancel*">PROPAGATION_REQUIRED</prop>
			 <prop key="create*">PROPAGATION_REQUIRED</prop>
			 <prop key="download*">PROPAGATION_REQUIRED</prop>
			 <prop key="upload*">PROPAGATION_REQUIRED</prop>
			 <prop key="doProcessor*">PROPAGATION_REQUIRED</prop>
			 <prop key="approve*">PROPAGATION_REQUIRED</prop>
			 <prop key="doVerfy*">PROPAGATION_REQUIRED,readOnly</prop>
			 <prop key="list*">PROPAGATION_REQUIRED,readOnly</prop>
			 <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
			 <prop key="query*">PROPAGATION_REQUIRED,readOnly</prop>
			 <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
			 <prop key="search*">PROPAGATION_REQUIRED,readOnly</prop>
			 <prop key="is*">PROPAGATION_REQUIRED,readOnly</prop>
			 <prop key="has*">PROPAGATION_REQUIRED,readOnly</prop>
        </props>
     </property>
   </bean>

	<!-- DBCP資料源 -->
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
		<property name="driverClassName" value="${driverClassName}" />
        <property name="url" value="${url}" />
        <property name="username" value="${username}" />
        <property name="password" value="${password}" />
		<!-- 初始化個數 可修改數量 -->
		<property name="initialSize" value="${initialSize}" />
		<!-- 最大連接配接資料庫連接配接數,設定為0時,表示沒有限制 可修改數量 -->
		<property name="maxActive" value="${maxActive}" />
		<!-- 最大等待秒數,機關為毫秒, 超過時間會報出錯誤資訊 -->
		<property name="maxWait" value="1" />
		<!-- 最大等待連接配接中的數量,設定為0時,表示沒有限制 -->
		<property name="maxIdle" value="1" />
		<!-- 是否自我中斷,預設是 false  -->
		<property name="removeAbandoned" value="true" />
		<!-- 幾秒後資料連接配接會自動斷開,在removeAbandoned為true,提供該值 -->
		<property name="removeAbandonedTimeout" value="150" />
		<!-- 是否記錄中斷事件, 預設為 false -->
		<property name="logAbandoned" value="true" />
  	</bean>
  	
  	<!-- DBCP資料源 -->
	<bean id="dataSourceTwo" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
		<property name="driverClassName" value="${dbTwo.driverClassName}" />
        <property name="url" value="${dbTwo.url}" />
        <property name="username" value="${dbTwo.username}" />
        <property name="password" value="${dbTwo.password}" />
		<!-- 初始化個數 可修改數量 -->
		<property name="initialSize" value="${dbTwo.initialSize}" />
		<!-- 最大連接配接資料庫連接配接數,設定為0時,表示沒有限制 可修改數量 -->
		<property name="maxActive" value="${dbTwo.maxActive}" />
		<!-- 最大等待秒數,機關為毫秒, 超過時間會報出錯誤資訊 -->
		<property name="maxWait" value="1" />
		<!-- 最大等待連接配接中的數量,設定為0時,表示沒有限制 -->
		<property name="maxIdle" value="1" />
		<!-- 是否自我中斷,預設是 false  -->
		<property name="removeAbandoned" value="true" />
		<!-- 幾秒後資料連接配接會自動斷開,在removeAbandoned為true,提供該值 -->
		<property name="removeAbandonedTimeout" value="150" />
		<!-- 是否記錄中斷事件, 預設為 false -->
		<property name="logAbandoned" value="true" />
  	</bean>
  	
	
	<bean id="dynamicDataSource" class="com.siit.digital.framework.common.datasourceswitch.impl.DynamicDataSource" >
	    <!-- 通過key-value的形式來關聯資料源 -->
		<property name="targetDataSources">
			<map>
				<entry value-ref="dataSource" key="dataSource"></entry>
				<entry value-ref="dataSourceTwo" key="dataSourceTwo"></entry>
			</map>
		</property>
        <!-- 預設資料源 -->
		<property name="defaultTargetDataSource" ref="dataSource" >
		</property>
	</bean>
  	
  	<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
       <property name="dataSource">
           <ref local="dynamicDataSource" />
       </property>
       <property name="mappingLocations">
       		<list>
	       		<value>classpath*:modelConfig/db1/${dataSource}/*.hbm.xml</value>
	       		<value>classpath*:modelConfig/db2/${dbTwo.dataSource}/*.hbm.xml</value>
       		</list>		
	   </property>
     <property name="hibernateProperties">
	    <props>
	       <prop key="hibernate.dialect">${hibernate.dialect}</prop>
	       <prop key="hibernate.show_sql">true</prop>
	    </props>
	</property>
  </bean>
  
  <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
       <property name="sessionFactory">
           <ref local="sessionFactory" />
       </property>
  </bean>
  
</beans>
           

properties配置

driverClassName=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@192.168.2.112:1521:ORCL
username=imssc5
password=sa
initialSize=5
maxActive=50
hibernate.dialect=org.hibernate.dialect.Oracle10gDialect
dataSource=oracle
jndiName=image

dbTwo.driverClassName=com.mysql.cj.jdbc.Driver
dbTwo.url=jdbc\:mysql\://localhost\:3306/zgh?serverTimezone=GMT&autoReconnect=true&characterEncoding=utf-8&useSSL=false
dbTwo.username=root
dbTwo.password=gao24
dbTwo.initialSize=5
dbTwo.maxActive=50
dbTwo.dataSource=mysql
dbTwo.hibernate.dialect=org.hibernate.dialect.MySQLDialect
           
DynamicDataSource類      
public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        // 擷取資料源辨別
        return DynamicDataSourceHolder.getDataSource();
    }

}
           
DynamicDataSourceHolder類      
public class DynamicDataSourceHolder {
    // 線程本地環境  
    private static final ThreadLocal contextHolder = new ThreadLocal();  
      
    // 設定資料源類型  
    public static void setDataSourceType(String dataSourceType) {  
        contextHolder.set(dataSourceType);  
    }  
  
    // 擷取資料源類型  
    public static String getDataSourceType() {  
        return (String) contextHolder.get();  
    }  
  
    // 清除資料源類型  
    public static void clearDataSourceType() {  
        contextHolder.remove();  
    }  

}
           

切換可以直接根據注冊進動态資料源的

key

值進行選擇。

需要注意的是,切換資料源要在事務之前就可以了。否則不生效。

@Controller
public class Test {
    @Autowired
    private DynDataSourceService dataSourceService;
    @RequestMapping("/Test")
    public String test() {
        DynamicDataSourceHolder.setDataSource("dataSourceTwo");
        return dataSourceService.find();
    }
}
           

參考:

https://blog.csdn.net/qq_35830949/article/details/80885745

https://www.cnblogs.com/kongpeng/p/6483568.html