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

AntV G6避坑指南:折叠树状图那些意想不到的BUG(附解决方案) 本文深入剖析了在React项目中使用AntV G6实现折叠树状图时,从图标错乱、数据同步到状态管理的常见BUG与解决方案。文章基于实战经验,详细解读了G6的内部机制,提供了从环境配置、自定义节点绘制到事件处理与性能优化的完整避坑指南,帮助开发者彻底解决折叠展开功能的疑难杂症。 阅读详情

说明

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

 

YOLOv12 改进 | Backbone改进 3 将CSP中的简单拼接改为可学习的特征选择门控,动态决定哪些特征流向下一层,同样再写这篇。:相比静态CSP的固定50/50分割,门控机制可学习0.3:0.7等最优比例。在输入端加入轻量SR模块,对下采样后的特征进行超分恢复,提升小目标检测能力。(小目标): 从 0.51 AP → 0.63 AP (+24%):采用ESPCN的高效亚像素卷积,避免传统插值的信息损失。:从通道级(SE)到空间级(Spatial)的多粒度控制。:结合浅层细节和深层语义,恢复小目标的纹理信息。 阅读详情

相关推荐

关于MII、RMII、GMII、RGMII、PHY、网络变压器、RJ45的硬件总结

文章目录前言一、网络传输结构及原理1.以太网的工作原理2.TCP/IP协议3.数据链路层(MAC)二、介质独立接口MII,RMII,GMII,RGMII1.MII(Media Independent interface)2.RMII(Reduced Media Independent Interface)3.GMII(Gigabit Medium Independent)4.RGMII(Reduced Gigabit Media Independent Interface)三、物理层芯片(PHY)二、使用步

weixin_44415816的博客 3万+

proxool连接池

Spring一、Proxool连接池简介及其配置属性概述  Proxool是一种Java数据库连接池技术。是sourceforge下的一个开源项目,这个项目提供一个健壮、易用的连接池,最为关键的是这个连接池提供监控的功能,方便易用,便于发现连接泄漏的情况。目前是和DBCP以及C3P0一起,最为常见的三种JDBC连接池技术。日前,Hibernate官方宣布由于Bug太多不再支持DBCP,而推荐使...

accphc的专栏 507

单细胞分析进阶:sctransform标准化在Seurat中的实战解析

本文深入解析了sctransform标准化方法在Seurat单细胞分析中的实战应用。通过对比传统对数标准化,sctransform能更有效地建模并剔除技术噪音,提升数据质量。文章提供了从环境配置、数据准备、核心参数解析到完整流程整合的详细指南,并针对常见问题给出解决方案,帮助研究者获得更清晰的细胞分群和更可靠的差异表达结果。

weixin_29248313的博客 150

Proxool连接池 使用

simultaneous-build-throttle: 是指在任一时刻,可以(同时)建立的最大连接数,也就是说,就是已经请求的、但还没可用的新连接数量。因为连接可以用多线程建立,从决定要建立连接到连接可用是需要一定时间的,所以我们需要一些方式来避免大量的线程想同时建立连接。(我们本应该找一个...

chuncui2576的博客 465

Basilisk库教程

要在仿真中执行模块,其调度由Basilisk的[Process]和[Task]容器控制。BSK[Task]包含一系列模块,这些模块都以相同的更新频率执行。一个[Process]本质上是一个任务组,可以包含多个相关的任务。例如,在多星仿真中,你可以为每颗卫星创建一个[Process],以便将相关任务和嵌入式模块有序地组织起来。下图展示了一个示例布局,其中bskSat卫星的动力学被添加到与飞行软件(FSW)算法分开的进程中,这些算法在该卫星上执行。在每个进程中,设置了若干任务,这些任务以指定的频率进行评估。

weixin_57997461的博客 1135

SpringCloud2025+SpringBoot3.5.0+gateway+webflux子服务路由报503

本来昨天就应该也记录下,免得忘记的,但是有点晚了,酒没写,真的是被坑惨了。当然这也是追求最新的代价,也是对新技术、老知识点的重温。依赖更粒度让架构的知识面更高,需要非常清楚另外说不定是有新的负载均衡要出现了,就想当初loadbalancer取代Ribbon一样好了,真是坑了半夜,昨晚都没有写,今天才复盘,希望能帮到大家,让更多在坑里的技术人爬出来。

zwrlj527的专栏 1996

通过压力测试提升服务器并发性能实例

前言前一段时间应领导要求,对公司服务端代码进行简单的压力测试。测试发现,并发数只能维持在很小的值以内,比如模拟并发数超过100,失败率就会大大提高。在咨询完后端搭建过程后发现,基本上所有的配置参数全部采用了默认处理,包括:数据库、服务器、应用程序。然后就是各种查资料,发现上述提到的各个模块都有很大的提升空间,需要开发人员自己配置。这一块网上众说纷纭:有的说改tomcat配置的(配置堆内存大小,jvm

高远的博客 1万+

C#上位机性能优化全攻略:彻底解决界面卡顿+多线程死锁+PLC数据延迟,产线实测稳定运行2年

一开始我们用的是网上找的零散优化代码,根本满足不了要求,后来花了2个月的时间,把之前27条产线的代码整理、重构、优化,做了一套这套方案上线后,连续稳定运行2年零3个月:界面响应时间稳定在50ms以内,多线程死锁率持续为0,PLC数据延迟稳定在150ms以内,系统可用率≥99.99%,帮客户一年省下了超过480万的停线损失、罚款损失和人工成本,客户第二年就把剩下的22条产线也全部交给我们做了,还介绍了3家同行。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 293

We are already in the process of making 11 connections and the number of simultaneous builds has been throttled to 10

 Caused by: java.sql.SQLException: We are already in the process of making 11 connections and the number of simultaneous builds has been throttled to 10情况一但是我的最大值都是120了,是非常大的,不知道怎么回事提示了一

swandragon的专栏 1万+

杰理-tone

低音质格式切换高音质格式:切换提示音格式,未导出,编译下载没有提示音;提示音导出,再次编译下载,提示音正常高音质格式切换低音质格式:不需要导出,直接编译下载,提示音正常。

m0_67447112的博客 954

点云从入门到精通技术详解100篇-基于 CBCT 与口内扫描数据的牙齿点云配准

口扫生成的三维牙模型只包含牙冠结构,容易受到唾液、食物残留等杂质的干扰。像精度,但其扫描成本较高,在公立医院的普及率较低。此外,口扫探入式的体。完整、精确的牙齿信息,有助于医生更好地进行数字化辅助诊疗,提高手术的预。可以表示上颌骨、下颌骨、牙冠以及牙根的位置和形状,但其扫描分辨率较低,精配准前实现粗略的预配准来确定点云间的初始位置,为精配准提供良好的配准。该算法通过计算点对间的距离确定源点云中的某一点在目标点云中的对应。算两点之间的欧氏距离,运算量较大,而且由于算法只考虑点集间的距离而忽略。

getusushu的博客 1640

proxool配置详解

搞了一天的在hibernate中配置proxool,终于算是调通过了,其中遇到了许多问题,在这里和大家分享一下. 1.官网下载地址: http://sourceforge.net/projects/proxool/files/ 2.说明一下我的配置环境 JRE1.6, tomcat6.0,hibernate3.1, proxool-0.9.0RC3 数据库为MSSQL2005 JDB

huangzclovetingzi的专栏 631

反应动力学仿真软件:Kintecus_(3).Kintecus安装与配置

在本节中,我们将详细介绍如何安装和配置Kintecus反应动力学仿真软件。Kintecus是一款功能强大的工具,用于模拟和分析化学反应的动力学过程。正确安装和配置软件是开始使用它的第一步。我们将分步骤介绍软件的安装过程,并提供一些基本配置的示例。

kkchenjj的博客 1552

项目中用到的Proxool0.9.1数据连接池配置实践

1:先是配置文件: &lt;?xml version="1.0" encoding="gb2312"?&gt; &lt;!-- the proxool configuration can be embedded within your own application's. Anything outside the "proxool" tag is ignored. --&gt; &lt;...

gaile的专栏 370

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

proxool

Proxool是一种Java数据库连接池技术。是sourceforge下的一个开源项目,这个项目提供一个健壮、易用的连接池,最为关键的是这个连接池提供监控的功能,方便易用,便于发现连接泄漏的情况。   目前是和DBCP以及C3P0一起,最为常见的三种JDBC连接池技术。   日前,Hibernate官方宣布由于Bug太多不再支持DBCP,而推荐使用 Proxool或C3P0。 ...

weixin_34037173的博客 160

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Spring学习11-Spring使用proxool连接池 管理数据源

Spring 一、Proxool连接池简介及其配置属性概述   Proxool是一种Java数据库连接池技术。是sourceforge下的一个开源项目,这个项目提供一个健壮、易用的连接池,最为关键的是这个连接池提供监控的功能,方便易用,便于发现连接泄漏的情况。 目前是和DBCP以及C3P0一起,最为常见的三种JDBC连接池技术。 日前,Hibernate官方宣布由于Bug太多不再...

weixin_33739646的博客 147

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

【Spring】调用有参构造实例化对象的constructor-arg子标签如何配置构造函数的参数值

constructor-arg子标签:指定创建类对象时使用哪个构造函数,每一对或每一个constructor-arg子标签配置一个参数列表中的参数值;如果不配置该子标签,则默认使用无参构造函数实例化对象 调用多参构造方法实例化对象是如何确定调用哪个多参构造函数和如何确定给哪个参数传值的? 如果需要实例化的类中有多参构造方法,那么需要用到name、type或index等属性来指定调用哪个多参构造方法...

景谦Nice的博客 3690

proxool配置文件中用户和密码加密

Proxool是一种Java数据库连接池技术。sourceforge下的一个开源项目,这个项目提供一个健壮、易用的连接池,最为关键的是这个连接池提供监控的功能,方便易用,便于发现连接泄漏的情况。 Proxool是一种Java数据库连接池技术。sourceforge下的一个开源项目,这个项目提供一个健壮、易用的连接池,最为关键的是这个连接池提供监控的功能,方便易用,便于发现连接泄漏的情况。

4056

DynamicDataBase多数据源

我们来撸下有哪些位置我们可以扩展,下面是我总结这些扩展点,希望能帮助到你。// 从ThreadLocal中获取路由key,来切换数据源的。到此,多数据源的路由key查找和切换就完成了,让我们来总结下[外链图片转存中…(img-1Psaxq3M-1721626925386)][外链图片转存中…(img-CudyJOEG-1721626925386)]我们来撸下有哪些位置我们可以扩展,下面是我总结这些扩展点,希望能帮助到你。

Java资料站 1113

spring连接池配置详解

一、连接池概述  数据库连接池概述:   数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出。对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标。数据库连接池正是针对这个问题提出来的。   数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而再不是重新建立一个;释放空闲时间超过最大...

Hello World 636

在Spring中配置连接池

在Spring中配置连接池 一、连接池概述 数据库连接池概述:  数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出。对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标。数据库连接池正是针对这个问题提出来的。  数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而再不是重新建立一个;释放空闲时间

HAPP NEW JAVA 883

spring连接池

1、连接池概念 数据库链接是一种关键的有限的昂贵的资源,在一点在多用户的网页应用程序中体现的尤为突出。对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标,数据连接池正是针对这个问题提出来的。 数据库连接池负责分配、管理和释放数据库连接,他允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个,释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接遗漏,这项技术明显能提高对数据库操作的性能。 数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,

qq_52052392的博客 1131

proxool详细配置

http://www.2cto.com/database/201110/109272.html   proxool一个数据库连接池框架,提供了对你选择的其它类型的驱动程序的连接池封装。可以非常简单的移植到现存的代码中。完全可配置。快速,成熟,健壮。可以透明地为你现存的JDBC驱动程序增加连接池功能。到目前为止最新版本是proxool 0.9.1,可从官网下载最新版本http://proxool

586

Java框架数据库连接池比较

现在常用的开源数据连接池主要有c3p0,dbcp和proxool三种,其中:¨         hibernate开发组推荐使用c3p0;¨         spring开发组推荐使用dbcp (dbcp连接池有weblogic连接池同样的问题,就是强行关闭连接或数据库重启后,无法reconnect ,告诉连接被重置,这个设置可以解决);¨        

dukongting的专栏 892

使用Spring实现读写分离(MySQL实现主从复制)

1. 背景 我们一般应用对数据库而言都是“读多写少”,也就说对数据库读取数据的压力比较大,有一个思路就是说采用数据库集群的方案, 其中一个是主库,负责写入数据,我们称之为:写库; 其它都是从库,负责读取数据,我们称之为:读库; 那么,对我们的要求是: 1、 读库和写库的数据一致; 2、 写数据必须写到写库; 3、 读数据必须到读库; 2. 方案

小飞侠的博客 946

基于dynamic-datasource多数据源自由切换--多租户

前面做了一个基于dynamic-datasource实现读写分离的实现,基于dynamic-datasource实现多数据源的读写分离_邋遢道的博客-优快云博客 最近公司遇到一个多租户的的需求,刚好就继续使用dynamic-datasource来做多数据源的切换 多租户 多租户就是说多个租户共用一个实例,租户的数据既有隔离又有共享,从而解决数据存储的问题,其实我们常用的权限那种也可以理解为多租户 多租户的三种实现方案: 1.独立数据库 即一个租户...

邋遢道的博客 3334
上一篇: Redis中的Multi事务
下一篇: Async-profiler介绍
冯立彬
冯立彬 优质创作者: 编程框架技术领域 优质创作者: 编程框架技术领域
博客等级 码龄21年 5458粉丝 593原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值