DynamicDatabaseSource,在应用端支持数据库的主从

3 篇文章 0 订阅
2 篇文章 0 订阅

说明

通过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>

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值