天天看點

spring無事務的資料源切換,和帶事務的資料源切換

最近在配置spring架構時需要使用多資料源,其中遇到一些問題,特此記錄

無事務資料源切換

見 http://blog.csdn.net/shadowsick/article/details/8878448 

主要說一下帶事務資料源切換的配置

首先在spring-database.xml中配置兩個資料源(預設資料源),和應用的切面

<!-- backend資料源  --> 
    <bean id="dataSourceBackend" class="org.springframework.jdbc.datasource.DriverManagerDataSource" >  
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>  
        <property name="url" value="${backend.url}"></property>  
        <property name="username" value="${backend.username}"></property>  
        <property name="password" value="${backend.password}"></property>  
    </bean>
    <!-- pi資料源  --> 
    <bean id="dataSourcePIDB" class="org.springframework.jdbc.datasource.DriverManagerDataSource" >  
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>  
        <property name="url" value="${pi.url}"></property>  
        <property name="username" value="${pi.username}"></property>  
        <property name="password" value="${pi.password}"></property>  
    </bean>  
    
    <!-- 多資料源配置  --> 
    <bean id="dynamicDataSource" class="com.test.base.dao.DynamicDataSource">  
        <property name="targetDataSources">  
            <map key-type="java.lang.String">  
                <entry value-ref="dataSourceBackend" key="dataSourceBackend"></entry>  
            	<entry value-ref="dataSourcePIDB" key="dataSourcePIDB"></entry>
            </map>  
        </property>  <!--預設資料源-->
        <property name="defaultTargetDataSource" ref="dataSourceBackend">  
        </property>  
    </bean>
    <aop:config><!--切面-->  
        <aop:aspect id="dataSourceAspect" ref="dataSourceInterceptor">
            <aop:pointcut id="daoBackend" expression="execution(* com.test.backend.service.ReportService.*(..))" />
            <aop:before pointcut-ref="daoBackend" method="setdataSourceBackend" />
            
            <aop:pointcut id="daopidb" expression="execution(* com.test.backend.service.MacIpService.*(..))" />
            <aop:before pointcut-ref="daopidb" method="setdataSourcePIDB" /><!--切面before調用的方法-->
            <aop:after pointcut-ref="daopidb" method="cleardataSource" /><!--切面after調用的方法-->

        </aop:aspect>  
    </aop:config> 
           

多資料源route類

public class DynamicDataSource extends AbstractRoutingDataSource{

	@Override  
    protected Object determineCurrentLookupKey() {  
        return DatabaseContextHolder.getCustomerType();   
    }
	
}
           

資料源内容配置類

public class DatabaseContextHolder {
	
	private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();  
	  
    public static void setCustomerType(String customerType) {
        contextHolder.set(customerType);  
    }  
  
    public static String getCustomerType() {  
        return contextHolder.get();  
    }  
  
    public static void clearCustomerType() {  
        contextHolder.remove();  
    } 
	
}
           
@Component
public class DataSourceInterceptor {
	
    public void setdataSourceBackend(JoinPoint jp) {  
        DatabaseContextHolder.setCustomerType("dataSourceBackend");  
    }
    public void setdataSourcePIDB(JoinPoint jp) {  
    	DatabaseContextHolder.setCustomerType("dataSourcePIDB");  
    }
    
    public void cleardataSource(JoinPoint jp){
    	DatabaseContextHolder.clearCustomerType();
    }
    
}
           

上邊xml中配置的 dataSourceInterceptor 會找到class DataSourceInterceptor,并執行set**方法和clear**方法,并設定CustomerType(資料源)給contextHolder,以便于

在determineCurrentLookupKey方法中可以獲得到改變後的資料源.

然後是事務的配置

在spring-application.xml中

加上如下配置

</pre></p><p><pre name="code" class="html"> <import resource="spring-database.xml"/>
 
    
    
    <!-- 配置SessionFactory -->  
    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">  
        <property name="dataSource" ref="dynamicDataSource" />  
        <property name="hibernateProperties">  
            <props>  
            	<prop key="hibernate.autoReconnect">true</prop>
            	<prop key="hibernate.connection.autocommit">true</prop>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>  
                <prop key="hibernate.show_sql">true</prop>  
            </props>  
        </property>  
        <property name="packagesToScan" value="com.test.backend.entity" />
    </bean>  
    
    <!-- 配置一個事務管理器 -->  
    <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">  
        <property name="sessionFactory" ref="sessionFactory"/>  
    </bean>  
    
    <!-- 事務管理  start-->
    <tx:annotation-driven transaction-manager="transactionManager" />
    
    <tx:advice id="txAdvice" transaction-manager="transactionManager">  
        <tx:attributes>  
            <tx:method name="add*" propagation="REQUIRED" rollback-for="java.lang.Exception"/> 
            <tx:method name="update*" propagation="REQUIRED" rollback-for="java.lang.Exception"/> 
            <tx:method name="del*" propagation="REQUIRED" rollback-for="java.lang.Exception"/> 
            <tx:method name="find*" propagation="REQUIRED" rollback-for="java.lang.Exception"/> 
            <tx:method name="save*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
        </tx:attributes>  
    </tx:advice>  
    
	<aop:config>  
        <!-- 實施事務 -->  
        <aop:pointcut id="txPointcut" expression="execution(* com.test.backend.service.*.*(..))" />  
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" />  
    </aop:config>
    <!-- 事務管理  end-->
           

在web.xml中加上了spring管理hibernate的session

<filter>
		<filter-name>openSessionInView</filter-name>
		<filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
		<init-param>
			<param-name>sessionFactoryBeanName</param-name>
			<param-value>sessionFactory</param-value>
		</init-param>
	</filter>

	<filter-mapping>
		<filter-name>openSessionInView</filter-name> 
		<url-pattern>/*</url-pattern>
	</filter-mapping>
           

注意:加上事務時候,我這的切面切的是service層,當切換資料源時,一定要把所有的方法加到你要實施事務的attributes中,或者寫成*(任何方法都實施事務)也可以.否則不能切換資料源,詳情可見http://blog.csdn.net/wangpeng047/article/details/43450189的部落格

這裡一句話帶過,事務和資料源是綁定的,當你在service層加上事務,你想在dao層切換資料源是不可以的,由于在進入該層之前事務已經通過攔截器開啟,是以在該層切換資料源也是不行的.

以上是我本地配置的帶事務管理的資料源切換執行個體,如有問題感謝大家提出指正互相學習.

繼續閱讀