DynamicDatabaseSource,在應用端支持數據庫的主從

說明

通過AOP的方式,根據當前操作的讀寫類型,自動切換數據源爲主庫還是從庫,配置和使用都很簡單,減少支持讀寫分離中間的引入,避免性能損失。

項目地址:https://gitee.com/laofeng/DynamicDatabaseSource

一、介紹

生產環境下,單個MySQL在小業務量下,支持讀寫是沒有問題的,但是隨着業務量的增加,至少此時需要做的就是將數據庫的讀寫進行分離,以便於支撐更高的流量。

目前有一些中間件可以做無感知的支持讀寫分離,如MyCAT,在後端配置好主庫和重庫,其會自動路由寫操作到主庫,讀操作到從庫,減少了開發人員的工作量,特別對於舊項目升級,非常的方便。但是引入了中間層,也就意味着處理的流程就變長了,出問題的機率也增加了,響應時間也會加長,其本身也可能隨着業務量的增加,成爲性能瓶頸。同了爲了避免單點,至少得兩臺服務器搭建高可用集羣,前面得再放一層LVS和HAPROXY等,這裏又是幾臺服務器的開銷,並且增加了運維成本和工作量。對於追到極致的程序員來說,還是想盡可能的再減少處理環節,提高工作效率。

DynamicDatabaseSource,通過在應用層支持主從的動態路由,其擴展自Spring動態數據源的支持,在主從環境數據環境中,支持自動根據操作的類型切換爲不同的數據源,如寫操作(Insert、Update、Delete)會自動切換爲主庫操作,讀和查操作,則會使用配置的從庫。

主要功能:

1、支持配置一主多從,寫走主庫,讀從多個從庫中隨機選擇一個數據源;

2、支持配置多主多從,寫操作從多個庫中隨機選擇一個,不過此時需要當前MySQL集羣支持多主,,讀從多個從庫中隨機選擇一個數據源;(注:多主目前不支持跨數據庫的事務)

3、支持通過方法名稱的前綴判斷是讀操作還是寫操作,如以delete、update、insert爲前綴的操作,則判斷爲寫操作,將其路由到主庫操作,如果是以select、query等爲前綴,則判斷爲讀操作,將其路徑到從庫進行操作;

4、支持通過註解的方式,指定當前操作是讀操作還是還寫操作,目前支持的註解:

@DataSourceMaster:指定當前操作爲寫操作

@DataSourceSlave:指定當前操作爲讀操作

@DataSource:通過Value的方式,指定DataOperateType的操作方式來判斷是寫操作還是讀操作,目前支持的類型爲:INSERT("insert"), UPDATE("update"), DELETE("delete"), SELECT("select"), GET("get"),QUERY("query")

5、支持多個分庫、每個分庫中多個分表的自動路由,使用場景用戶需要對抽象net.xiake6.orm.datasource.sharding.ShardingCondition進行實現,自定義數據路由到不同分庫、路由到不同分表的規則的實現,可以參看默認的實現示例類:

net.xiake6.orm.datasource.sharding.DefaultTableShardingCondition

net.xiake6.orm.datasource.sharding.DefaultDatabaseShardingCondition

6、包含有相應的單元測試,test/resources下面的test.sql爲用於測試的SQL語句,jdbc-sharding.properties爲測試數據源的配置,測試類在測試工程下,可以根據實際情況增減測試類。

二、使用說明-主從數據源配置(applicationContext-db-masterslave-context.xml)

需要在應用方增加類似如下的數據源配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:jee="http://www.springframework.org/schema/jee" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
				        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
				        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.3.xsd
				        http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd
				        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
				        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd
				        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
				        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
	<context:property-placeholder location="classpath:jdbc.properties" ignore-unresolvable="true"/>
	<!-- proxool連接池 -->
	<bean id="dataSourceMaster" class="org.logicalcobwebs.proxool.ProxoolDataSource">
		<property name="alias" value="${alias}" />
		<property name="driver" value="${driver}" />
		<property name="driverUrl" value="${driverUrl}" />
		<property name="user" value="${db_user}" />
		<property name="password" value="${db_password}" />
		<property name="houseKeepingTestSql" value="${house-keeping-test-sql}" />
		<property name="maximumConnectionCount" value="${maximum-connection-count}" />
		<property name="minimumConnectionCount" value="${minimum-connection-count}" />
		<property name="prototypeCount" value="${prototype-count}" />
		<property name="simultaneousBuildThrottle" value="${simultaneous-build-throttle}" />
		<property name="trace" value="${trace}" />
	</bean>
	<bean id="dataSourceSlave1" class="org.logicalcobwebs.proxool.ProxoolDataSource">
		<property name="alias" value="${alias_slave1}" />
		<property name="driver" value="${driver}" />
		<property name="driverUrl" value="${driverUrl_slave1}" />
		<property name="user" value="${db_user_slave1}" />
		<property name="password" value="${db_password_slave1}" />
		<property name="houseKeepingTestSql" value="${house-keeping-test-sql}" />
		<property name="maximumConnectionCount" value="${maximum-connection-count}" />
		<property name="minimumConnectionCount" value="${minimum-connection-count}" />
		<property name="prototypeCount" value="${prototype-count}" />
		<property name="simultaneousBuildThrottle" value="${simultaneous-build-throttle}" />
		<property name="trace" value="${trace}" />
	</bean>
	<bean id="dataSourceSlave2" class="org.logicalcobwebs.proxool.ProxoolDataSource">
		<property name="alias" value="${alias_slave2}" />
		<property name="driver" value="${driver}" />
		<property name="driverUrl" value="${driverUrl_slave2}" />
		<property name="user" value="${db_user_slave2}" />
		<property name="password" value="${db_password_slave2}" />
		<property name="houseKeepingTestSql" value="${house-keeping-test-sql}" />
		<property name="maximumConnectionCount" value="${maximum-connection-count}" />
		<property name="minimumConnectionCount" value="${minimum-connection-count}" />
		<property name="prototypeCount" value="${prototype-count}" />
		<property name="simultaneousBuildThrottle" value="${simultaneous-build-throttle}" />
		<property name="trace" value="${trace}" />
	</bean>
	<bean id="targetDataSources" class="java.util.HashMap">  
		<constructor-arg>  
	    	<map>
	    		<!-- 
	    		注:master數據源的key一定要以master開頭,slave數據源的key一定要以slave開頭。
	    		master和slave都可以配置多個,框架會根據要執行的操作是數據修改還是查詢操作,
	    		分別從master及slave中隨機獲取一個。
	    		-->
				<entry key="master" value-ref="dataSourceMaster" />
				<entry key="slave1" value-ref="dataSourceSlave1"/>
				<entry key="slave2" value-ref="dataSourceSlave2"/>
	    	</map>  
	    </constructor-arg>
	</bean>
	<bean id="dataSource" class="net.xiake6.orm.datasource.DynamicDataSource">
		<property name="targetDataSources" ref="targetDataSources"/>
		<property name="defaultTargetDataSource" ref="dataSourceMaster" />
	</bean>
	<!-- 對數據源進行事務管理 -->
	<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>
	<!-- 事務註解配置 -->
	<tx:annotation-driven transaction-manager="transactionManager" />
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="*" rollback-for="***Exception"
				propagation="REQUIRED" isolation="DEFAULT" />
		</tx:attributes>
	</tx:advice>

	<aop:config>
		<aop:pointcut id="interceptorPointCuts"
			expression="execution(* net.xiake6.biz.service..*.*(..))" />
		<aop:advisor advice-ref="txAdvice" pointcut-ref="interceptorPointCuts" />
	</aop:config>

	<!-- 通過切面的方式控制在執行數據庫方法之前,切換主從 -->
	<bean id="dataSourceAspect"	class="net.xiake6.orm.datasource.DataSourceAspect" >
		<property name="targetDataSources" ref="targetDataSources"/>
	</bean>
	<aop:config proxy-target-class="true">
		<aop:aspect id="dataSourceAspect" ref="dataSourceAspect"
			order="1">
			<aop:pointcut id="tx"
				expression="execution(* net.xiake6.orm.persistence.mapper.*.*(..)) " />
			<aop:before pointcut-ref="tx" method="before" />
		</aop:aspect>
	</aop:config>


	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
	</bean>
	<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
		<constructor-arg index="0" ref="sqlSessionFactory" />
		<!-- 
		指定用戶執行的Executor,默認爲SimpleExecutor. 
		SIMPLE表示SimpleExecutor,REUSE表示ResueExecutor,BATCH表示BatchExecutor,CLOSE表示CloseExecutor
		-->
		<constructor-arg index="1" value="REUSE" />
	</bean>
	<!-- mybatis文件配置,掃描所有mapper文件 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage"
			value="net.xiake6.orm.persistence.mapper" />
		<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
		<property name="sqlSessionTemplateBeanName" value="sqlSessionTemplate"></property>
	</bean>
</beans>

該配置中的關鍵點: 1、配置多個數據源,並將其存在Map中

	<bean id="targetDataSources" class="java.util.HashMap">  
		<constructor-arg>  
	    	<map>
	    		<!-- 
	    		注:master數據源的key一定要以master開頭,slave數據源的key一定要以slave開頭。
	    		master和slave都可以配置多個,框架會根據要執行的操作是數據修改還是查詢操作,
	    		分別從master及slave中隨機獲取一個。
	    		-->
				<entry key="master" value-ref="dataSourceMaster" />
				<entry key="slave1" value-ref="dataSourceSlave1"/>
				<entry key="slave2" value-ref="dataSourceSlave2"/>
	    	</map>  
	    </constructor-arg>
	</bean>

2、指定數據源爲動態數據源net.xiake6.orm.datasource.DynamicDataSource:

	<bean id="dataSource" class="net.xiake6.orm.datasource.DynamicDataSource">
		<property name="targetDataSources" ref="targetDataSources"/>
		<property name="defaultTargetDataSource" ref="dataSourceMaster" />
	</bean>

3、通過切面的方式控制在執行數據庫方法之前,切換主從

<!-- 通過切面的方式控制在執行數據庫方法之前,切換主從 -->
<bean id="dataSourceAspect"	class="net.xiake6.orm.datasource.DataSourceAspect" >
    <property name="targetDataSources" ref="targetDataSources"/>
</bean>

三、使用說明-分庫分表數據源配置(applicationContext-db-sharding-context.xml)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:jee="http://www.springframework.org/schema/jee" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
				        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
				        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.3.xsd
				        http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd
				        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
				        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd
				        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
				        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
	<!-- 啓用aop -->
	<aop:aspectj-autoproxy expose-proxy="true"></aop:aspectj-autoproxy>
	<!-- 開啓註解配置,使Spring關注Annotation -->
	<context:annotation-config />
	<!-- 啓用aop -->
	<aop:aspectj-autoproxy expose-proxy="true"></aop:aspectj-autoproxy>
	<context:component-scan base-package="net.xiake6.orm.datasource">
	</context:component-scan>
	<!-- jdbc配置文件 -->
	<context:property-placeholder location="classpath:jdbc-sharding.properties" ignore-unresolvable="true"/>
	<bean id="logFilter" class="com.alibaba.druid.filter.logging.Slf4jLogFilter"> 
		<property name="statementExecutableSqlLogEnable" value="true" /> 
	</bean>
	<!-- Druid連接池 -->
	<bean id="dataSource_1" class="com.alibaba.druid.pool.DruidDataSource">
		<property name="username" value="${db_user_master_1}"></property>
		<property name="password" value="${db_password_master_1}"></property>
		<property name="url" value="${driverUrl_master_1}"></property>
		<property name="driverClassName" value="${driver}"></property>
		<!-- 初始化連接大小 -->
		<property name="initialSize" value="${initialSize}"></property>
		<!-- 連接池最大使用連接數量 -->
		<property name="maxActive" value="${maxActive}"></property>
		<!-- 連接池最小空閒 -->
		<property name="minIdle" value="${minIdle}" />
		<!-- 獲取連接最大等待時間 -->
		<property name="maxWait" value="${maxWait}" />
		
		<!-- 打開PSCache,並且指定每個連接上PSCache的大小 --> 
		<property name="poolPreparedStatements" value="true" /> 
		<property name="maxPoolPreparedStatementPerConnectionSize" value="20" />
		<!-- 這裏配置提交方式,默認就是TRUE,可以不用配置 -->
		<property name="defaultAutoCommit" value="true" />

		<property name="validationQuery">
			<value>${validationQuery}</value>
		</property>
		<!-- 這裏建議配置爲TRUE,防止取到的連接不可用 --> 
  		<property name="testOnBorrow" value="${testOnBorrow}" />
		<property name="testOnReturn" value="${testOnReturn}" />
		<property name="testWhileIdle" value="${testWhileIdle}" />

		<!-- 配置間隔多久才進行一次檢測,檢測需要關閉的空閒連接,單位是毫秒 -->
		<property name="timeBetweenEvictionRunsMillis" value="${timeBetweenEvictionRunsMillis}" />
		<!-- 配置一個連接在池中最小生存的時間,單位是毫秒 -->
		<property name="minEvictableIdleTimeMillis" value="${minEvictableIdleTimeMillis}" />

		<!-- 打開removeAbandoned功能 -->
		<property name="removeAbandoned" value="${removeAbandoned}" />
		<!-- 移除被拋棄的鏈接的超時時間,單位爲秒 -->
		<property name="removeAbandonedTimeout" value="${removeAbandonedTimeout}" />
		<!-- 關閉abanded連接時輸出錯誤日誌 -->
		<property name="logAbandoned" value="${logAbandoned}" />

		<!-- 監控數據庫 -->
		<!-- <property name="filters" value="stat" /> -->
		<property name="filters" value="${druid-filter}" />
		<property name="proxyFilters"> 
			<list>
				<ref bean="dynamicTableFilter"/>
				<ref bean="logFilter" />
			</list> 
		</property>
	</bean>
	<bean id="dataSource_2" class="com.alibaba.druid.pool.DruidDataSource">
		<property name="username" value="${db_user_master_2}"></property>
		<property name="password" value="${db_password_master_2}"></property>
		<property name="url" value="${driverUrl_master_2}"></property>
		<property name="driverClassName" value="${driver}"></property>
		<!-- 初始化連接大小 -->
		<property name="initialSize" value="${initialSize}"></property>
		<!-- 連接池最大使用連接數量 -->
		<property name="maxActive" value="${maxActive}"></property>
		<!-- 連接池最小空閒 -->
		<property name="minIdle" value="${minIdle}" />
		<!-- 獲取連接最大等待時間 -->
		<property name="maxWait" value="${maxWait}" />
		
		<!-- 打開PSCache,並且指定每個連接上PSCache的大小 --> 
		<property name="poolPreparedStatements" value="true" /> 
		<property name="maxPoolPreparedStatementPerConnectionSize" value="20" />
		<!-- 這裏配置提交方式,默認就是TRUE,可以不用配置 -->
		<property name="defaultAutoCommit" value="true" />

		<property name="validationQuery">
			<value>${validationQuery}</value>
		</property>
		<!-- 這裏建議配置爲TRUE,防止取到的連接不可用 --> 
  		<property name="testOnBorrow" value="${testOnBorrow}" />
		<property name="testOnReturn" value="${testOnReturn}" />
		<property name="testWhileIdle" value="${testWhileIdle}" />

		<!-- 配置間隔多久才進行一次檢測,檢測需要關閉的空閒連接,單位是毫秒 -->
		<property name="timeBetweenEvictionRunsMillis" value="${timeBetweenEvictionRunsMillis}" />
		<!-- 配置一個連接在池中最小生存的時間,單位是毫秒 -->
		<property name="minEvictableIdleTimeMillis" value="${minEvictableIdleTimeMillis}" />

		<!-- 打開removeAbandoned功能 -->
		<property name="removeAbandoned" value="${removeAbandoned}" />
		<!-- 移除被拋棄的鏈接的超時時間,單位爲秒 -->
		<property name="removeAbandonedTimeout" value="${removeAbandonedTimeout}" />
		<!-- 關閉abanded連接時輸出錯誤日誌 -->
		<property name="logAbandoned" value="${logAbandoned}" />

		<!-- 監控數據庫 -->
		<!-- <property name="filters" value="stat" /> -->
		<property name="filters" value="${druid-filter}" />
		<property name="proxyFilters"> 
			<list>
				<ref bean="dynamicTableFilter"/>
				<ref bean="logFilter" />
			</list> 
		</property>
	</bean>
	<bean id="targetDataSources" class="java.util.HashMap">  
		<constructor-arg>  
	    	<map>
	    		<!-- 
	    		key一定是字符串+下劃線+DB序號,DB的序號從0開始,如有兩個DB,
	    		則序號分別爲0和1,有四個DB,則序號分別爲O,1,2,3。
	    		 -->
				<entry key="dataSource_0" value-ref="dataSource_1" />
				<entry key="dataSource_1" value-ref="dataSource_2"/>
	    	</map>  
	    </constructor-arg>
	</bean>
	
	<!-- Sharding數據庫規則實現配置 -->
	<bean id="databaseShardingCondition" class="net.xiake6.orm.datasource.sharding.DefaultDatabaseShardingCondition">
		<property name="dbNums" value="2"/>
	</bean>
	<!-- Sharding表規則實現配置 -->
	<bean id="tableShardingCondition" class="net.xiake6.orm.datasource.sharding.DefaultTableShardingCondition">
		<!-- 建立Sharding表時,須按照實際表名+下劃線+序號,且表的序號要從0開始,如apps分成4個分表,則每個表分別爲:
		apps_0、apps_1、apps_2、apps_3
		 -->
		<property name="tableNums" value="4" />
	</bean>
	<bean id="shardingConfig" class="net.xiake6.orm.datasource.sharding.ShardingConfig">
		<!-- 配置需要支持分表的表名 -->
		<property name="shardingTables">
			<set>
				<value>apps</value>
			</set>
		</property>
		<!-- 如果不需要配置多數據庫, databaseShardingCondition屬性可以不配置-->
		<property name="databaseShardingCondition" ref="databaseShardingCondition" />
		<property name="tableShardingCondition" ref="tableShardingCondition" />
	</bean>
	<bean id="dataSource" class="net.xiake6.orm.datasource.sharding.DynamicShardingDataSource">
		<property name="targetDataSources" ref="targetDataSources"/>
		<property name="defaultTargetDataSource" ref="dataSource_1" />
	</bean>

	<!-- 通過切面的方式控制在執行數據庫方法之前,切換多數據庫-->
	<!-- expression一定要指向mapper所在的包,且確保mapper裏面的都是數據庫操作方法 -->
	<!-- 如果不需要支持多數據庫,以下切面配置可以去掉 -->
	<aop:config proxy-target-class="true">
		<aop:aspect id="dataSourceAspect" ref="shardingDataSourceAspect"
			order="1">
			<aop:pointcut id="tx"				
				expression="execution(* net.xiake6.orm.persistence.mapper.*.*(..)) " />
			<aop:before pointcut-ref="tx" method="before" />
		</aop:aspect>
	</aop:config>

	<!-- 對數據源進行事務管理 -->
	<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>
	<!-- 事務註解配置 -->
	<tx:annotation-driven transaction-manager="transactionManager" />
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="*" rollback-for="***Exception"
				propagation="REQUIRED" isolation="DEFAULT" />
		</tx:attributes>
	</tx:advice>
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
	</bean>
	<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
		<constructor-arg index="0" ref="sqlSessionFactory" />
		<!-- 
		指定用戶執行的Executor,默認爲SimpleExecutor. 
		SIMPLE表示SimpleExecutor,REUSE表示ResueExecutor,BATCH表示BatchExecutor,CLOSE表示CloseExecutor
		-->
		<constructor-arg index="1" value="REUSE" />
	</bean>
	<!-- mybatis文件配置,掃描所有mapper文件 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage"
			value="net.xiake6.orm.persistence.mapper" />
		<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
		<property name="sqlSessionTemplateBeanName" value="sqlSessionTemplate"></property>
	</bean>

</beans>

分庫分表的核心配置:

	<!-- Sharding數據庫規則實現配置 -->
	<bean id="databaseShardingCondition" class="net.xiake6.orm.datasource.sharding.DefaultDatabaseShardingCondition">
		<property name="dbNums" value="2"/>
	</bean>
	<!-- Sharding表規則實現配置 -->
	<bean id="tableShardingCondition" class="net.xiake6.orm.datasource.sharding.DefaultTableShardingCondition">
		<!-- 建立Sharding表時,須按照實際表名+下劃線+序號,且表的序號要從0開始,如apps分成4個分表,則每個表分別爲:
		apps_0、apps_1、apps_2、apps_3
		 -->
		<property name="tableNums" value="4" />
	</bean>
	<bean id="shardingConfig" class="net.xiake6.orm.datasource.sharding.ShardingConfig">
		<!-- 配置需要支持分表的表名 -->
		<property name="shardingTables">
			<set>
				<value>apps</value>
			</set>
		</property>
		<!-- 如果不需要配置多數據庫, databaseShardingCondition屬性可以不配置-->
		<property name="databaseShardingCondition" ref="databaseShardingCondition" />
		<property name="tableShardingCondition" ref="tableShardingCondition" />
	</bean>
	<bean id="dataSource" class="net.xiake6.orm.datasource.sharding.DynamicShardingDataSource">
		<property name="targetDataSources" ref="targetDataSources"/>
		<property name="defaultTargetDataSource" ref="dataSource_1" />
	</bean>

	<!-- 通過切面的方式控制在執行數據庫方法之前,切換多數據庫-->
	<!-- expression一定要指向mapper所在的包,且確保mapper裏面的都是數據庫操作方法 -->
	<!-- 如果不需要支持多數據庫,以下切面配置可以去掉 -->
	<aop:config proxy-target-class="true">
		<aop:aspect id="dataSourceAspect" ref="shardingDataSourceAspect"
			order="1">
			<aop:pointcut id="tx"				
				expression="execution(* net.xiake6.orm.persistence.mapper.*.*(..)) " />
			<aop:before pointcut-ref="tx" method="before" />
		</aop:aspect>
	</aop:config>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章