目前有两种思路:
1.动态切换数据源,需要自定义一个数据源类继承自AbstractRoutingDataSource抽象类,这种方式有弊端,如果是并发系统中,当你把数据源改了,系统中所有的操作数据源都改了,即使你立马再改回去,还是有风险;
2.建立两套数据源,在spring加载Mapper时关联不同的数据源。
以下仅介绍第二种方式:
(1)新建两套数据源:
数据源一:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!-- 配置DataSource数据源 --> <bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close"> <!-- 数据库驱动 --> <property name="driverClass" value="${jdbc_driverClassName}" /> <!-- 相应驱动的jdbcUrl --> <property name="jdbcUrl" value="${jdbc_url}" /> <!-- 数据库的用户名 --> <property name="username" value="${jdbc_username}" /> <!-- 数据库的密码 --> <property name="password" value="${jdbc_password}" /> <!-- /** Maximum age of an unused connection before it is closed off. */ --> <!-- 设置分区个数。这个参数默认为1,建议3-4(根据特定应用程序而定)。 为了减少锁竞争和改善性能,从当前线程分区(thread-affinity)中获取一个connection, 也就是这个样子:partitions[Thread.currentThread().getId() % partitionCount]。 当拥有充足的短期(short-lived)的线程时候,这个参数设置越大,性能越好。 当超过一定的阀值时,连接池的维护工作就可能对性能造成一定的负面影响(仅当分区上的connection使用耗尽时) --> <property name="partitionCount" value="${db.partitionCount}" /> <!-- 设置每个分区含有connection最大个数。这个参数默认为2。如果小于2,BoneCP将设置为50。 比如:partitionCount设置为3,maxConnectionPerPartition设置为5,你就会拥有总共15个connection。 注意:BoneCP不会将这些connection一起创建出来,而是说在需要更多connection的时候从minConnectionsPerPartition参数开始逐步地增长connection数量。 --> <property name="maxConnectionsPerPartition" value="${db.maxConnectionsPerPartition}" /> <!-- 设置每个分区含有connection最大小个数。这个参数默认为0。 --> <property name="minConnectionsPerPartition" value="${db.minConnectionsPerPartition}" /> <!-- 设置分区中的connection增长数量。这个参数默认为1。 当每个分区中的connection大约快用完时,BoneCP动态批量创建connection, 这个属性控制一起创建多少个connection(不会大于maxConnectionsPerPartition)。 注意:这个配置属于每个分区的设置。 --> <property name="acquireIncrement" value="${db.acquireIncrement}" /> <!-- 设置连接池阀值。这个参数默认为20。如果小于0或是大于100,BoneCP将设置为20。 连接池观察线程(PoolWatchThread)试图为每个分区维护一定数量的可用connection。 这个数量趋于maxConnectionPerPartition和minConnectionPerPartition之间。这个参数是以百分比的形式来计算的。 例如:设置为20,下面的条件如果成立:Free Connections / MaxConnections < poolAvailabilityThreshold;就会创建出新的connection。 换句话来说连接池为每个分区至少维持20%数量的可用connection。 设置为0时,每当需要connection的时候,连接池就要重新创建新connection,这个时候可能导致应用程序可能会为了获得新connection而小等一会。 --> <property name="poolAvailabilityThreshold" value="${db.poolAvailabilityThreshold}" /> <!-- 设置获取connection超时的时间。这个参数默认为Long.MAX_VALUE;单位:毫秒。 在调用getConnection获取connection时,获取时间超过了这个参数,就视为超时并报异常。 --> <property name="connectionTimeoutInMs" value="${db.connectionTimeoutInMs}" /> <!-- /** A connection older than maxConnectionAge will be destroyed and purged from the pool. */ --> <!-- 设置connection的存活时间。这个参数默认为0,单位:毫秒。设置为0该功能失效。 通过ConnectionMaxAgeThread观察每个分区中的connection,不管connection是否空闲, 如果这个connection距离创建的时间大于这个参数就会被清除。当前正在使用的connection不受影响,直到返回到连接池再做处理。 --> <!-- 48小时关闭一个链接 --> <property name="maxConnectionAgeInSeconds" value="${db.maxConnectionAgeInSeconds}" /> <!-- /** SQL statement to use for keep-alive/test of connection. */ --> <property name="connectionTestStatement" value="${db.connectionTestStatement}" /> <!-- 设置connection的空闲存活时间。这个参数默认为60,单位:分钟。设置为0该功能失效。 通过ConnectionTesterThread观察每个分区中的connection,如果这个connection距离最后使用的时间大于这个参数就会被清除。 注意:这个参数仅和idleConnectionTestPeriodInSeconds搭配使用,而且不要在这里设置任何挑衅的参数! --> <!-- 1小时回收空闲链接 --> <property name="idleMaxAgeInMinutes" value="${db.idleMaxAgeInMinutes}" /> <!-- /** Connections older than this are sent a keep-alive statement. */ --> <!-- 设置测试connection的间隔时间。这个参数默认为240*60,单位:分钟。设置为0该功能失效。 通过ConnectionTesterThread观察每个分区中的connection, 如果这个connection距离最后使用的时间大于这个参数并且距离上一次测试的时间大于这个参数就会向数据库发送一条测试语句,如果执行失败则将这个connection清除。 注意:这个值仅和idleMaxAge搭配使用,而且不要在这里设置任何挑衅的参数! --> <!-- 4小时检测一次空闲链接 --> <property name="idleConnectionTestPeriodInMinutes" value="${db.idleConnectionTestPeriodInMinutes}" /> <!-- /** After attempting to acquire a connection and failing, try to connect these many times before giving up. */ --> <!-- 设置重新获取连接的次数。这个参数默认为5。 获取某个connection失败之后会多次尝试重新连接,如果在这几次还是失败则放弃。 --> <property name="acquireRetryAttempts" value="${db.acquireRetryAttempts}" /> <!-- 设置重新获取连接的次数间隔时间。这个参数默认为7000,单位:毫秒。如果小于等于0,BoneCP将设置为1000。 获取connection失败之后再次尝试获取connection的间隔时间。 --> <property name="acquireRetryDelayInMs" value="${db.acquireRetryDelayInMs}" /> <!-- 设置连接池初始化功能。这个参数默认为false。 设置为true,连接池将会初始化为空,直到获取第一个connection。 --> <property name="lazyInit" value="${db.lazyInit}" /> <!-- 设置是否关闭JMX功能。这个参数默认为false。 --> <property name="disableJMX" value="${db.disableJMX}" /> <!-- 设置连接池名字。用于当作JMX和助手线程名字的后缀。 --> <property name="poolName" value="${db.poolName}" /> <!-- /** Min no of prepared statements to cache. */ --> <!-- 设置statement缓存个数。这个参数默认为0。 --> <property name="statementsCacheSize" value="${db.statementsCacheSize}" /> <!-- 设置是否开启记录SQL语句功能。这个参数默认是false。 将执行的SQL记录到日志里面(包括参数值)。 --> <property name="logStatementsEnabled" value="${db.logStatementsEnabled}" /> <!-- 设置执行SQL的超时时间。这个参数默认为0;单位:毫秒。 当查询语句执行的时间超过这个参数,执行的情况就会被记录到日志中。 设置为0时,该功能失效。 --> <property name="queryExecuteTimeLimitInMs" value="${db.queryExecuteTimeLimit}" /> </bean> <!-- 对数据源进行事务管理 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 配置SqlSessionFactoryBean --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <!-- mapper和resultmap配置路径 --> <property name="mapperLocations"> <list> <value>classpath:mapper/*Mapper.xml</value> </list> </property> </bean> <tx:annotation-driven transaction-manager="transactionManager" /> </beans>
数据源二:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!-- 配置DataSource数据源 --> <bean id="dataSource2" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close"> <!-- 数据库驱动 --> <property name="driverClass" value="${jdbc_driverClassName}" /> <!-- 相应驱动的jdbcUrl --> <property name="jdbcUrl" value="${jdbc_url2}" /> <!-- 数据库的用户名 --> <property name="username" value="${jdbc_username2}" /> <!-- 数据库的密码 --> <property name="password" value="${jdbc_password2}" /> <!-- /** Maximum age of an unused connection before it is closed off. */ --> <!-- 设置分区个数。这个参数默认为1,建议3-4(根据特定应用程序而定)。 为了减少锁竞争和改善性能,从当前线程分区(thread-affinity)中获取一个connection, 也就是这个样子:partitions[Thread.currentThread().getId() % partitionCount]。 当拥有充足的短期(short-lived)的线程时候,这个参数设置越大,性能越好。 当超过一定的阀值时,连接池的维护工作就可能对性能造成一定的负面影响(仅当分区上的connection使用耗尽时) --> <property name="partitionCount" value="${db.partitionCount}" /> <!-- 设置每个分区含有connection最大个数。这个参数默认为2。如果小于2,BoneCP将设置为50。 比如:partitionCount设置为3,maxConnectionPerPartition设置为5,你就会拥有总共15个connection。 注意:BoneCP不会将这些connection一起创建出来,而是说在需要更多connection的时候从minConnectionsPerPartition参数开始逐步地增长connection数量。 --> <property name="maxConnectionsPerPartition" value="${db.maxConnectionsPerPartition}" /> <!-- 设置每个分区含有connection最大小个数。这个参数默认为0。 --> <property name="minConnectionsPerPartition" value="${db.minConnectionsPerPartition}" /> <!-- 设置分区中的connection增长数量。这个参数默认为1。 当每个分区中的connection大约快用完时,BoneCP动态批量创建connection, 这个属性控制一起创建多少个connection(不会大于maxConnectionsPerPartition)。 注意:这个配置属于每个分区的设置。 --> <property name="acquireIncrement" value="${db.acquireIncrement}" /> <!-- 设置连接池阀值。这个参数默认为20。如果小于0或是大于100,BoneCP将设置为20。 连接池观察线程(PoolWatchThread)试图为每个分区维护一定数量的可用connection。 这个数量趋于maxConnectionPerPartition和minConnectionPerPartition之间。这个参数是以百分比的形式来计算的。 例如:设置为20,下面的条件如果成立:Free Connections / MaxConnections < poolAvailabilityThreshold;就会创建出新的connection。 换句话来说连接池为每个分区至少维持20%数量的可用connection。 设置为0时,每当需要connection的时候,连接池就要重新创建新connection,这个时候可能导致应用程序可能会为了获得新connection而小等一会。 --> <property name="poolAvailabilityThreshold" value="${db.poolAvailabilityThreshold}" /> <!-- 设置获取connection超时的时间。这个参数默认为Long.MAX_VALUE;单位:毫秒。 在调用getConnection获取connection时,获取时间超过了这个参数,就视为超时并报异常。 --> <property name="connectionTimeoutInMs" value="${db.connectionTimeoutInMs}" /> <!-- /** A connection older than maxConnectionAge will be destroyed and purged from the pool. */ --> <!-- 设置connection的存活时间。这个参数默认为0,单位:毫秒。设置为0该功能失效。 通过ConnectionMaxAgeThread观察每个分区中的connection,不管connection是否空闲, 如果这个connection距离创建的时间大于这个参数就会被清除。当前正在使用的connection不受影响,直到返回到连接池再做处理。 --> <!-- 48小时关闭一个链接 --> <property name="maxConnectionAgeInSeconds" value="${db.maxConnectionAgeInSeconds}" /> <!-- /** SQL statement to use for keep-alive/test of connection. */ --> <property name="connectionTestStatement" value="${db.connectionTestStatement}" /> <!-- 设置connection的空闲存活时间。这个参数默认为60,单位:分钟。设置为0该功能失效。 通过ConnectionTesterThread观察每个分区中的connection,如果这个connection距离最后使用的时间大于这个参数就会被清除。 注意:这个参数仅和idleConnectionTestPeriodInSeconds搭配使用,而且不要在这里设置任何挑衅的参数! --> <!-- 1小时回收空闲链接 --> <property name="idleMaxAgeInMinutes" value="${db.idleMaxAgeInMinutes}" /> <!-- /** Connections older than this are sent a keep-alive statement. */ --> <!-- 设置测试connection的间隔时间。这个参数默认为240*60,单位:分钟。设置为0该功能失效。 通过ConnectionTesterThread观察每个分区中的connection, 如果这个connection距离最后使用的时间大于这个参数并且距离上一次测试的时间大于这个参数就会向数据库发送一条测试语句,如果执行失败则将这个connection清除。 注意:这个值仅和idleMaxAge搭配使用,而且不要在这里设置任何挑衅的参数! --> <!-- 4小时检测一次空闲链接 --> <property name="idleConnectionTestPeriodInMinutes" value="${db.idleConnectionTestPeriodInMinutes}" /> <!-- /** After attempting to acquire a connection and failing, try to connect these many times before giving up. */ --> <!-- 设置重新获取连接的次数。这个参数默认为5。 获取某个connection失败之后会多次尝试重新连接,如果在这几次还是失败则放弃。 --> <property name="acquireRetryAttempts" value="${db.acquireRetryAttempts}" /> <!-- 设置重新获取连接的次数间隔时间。这个参数默认为7000,单位:毫秒。如果小于等于0,BoneCP将设置为1000。 获取connection失败之后再次尝试获取connection的间隔时间。 --> <property name="acquireRetryDelayInMs" value="${db.acquireRetryDelayInMs}" /> <!-- 设置连接池初始化功能。这个参数默认为false。 设置为true,连接池将会初始化为空,直到获取第一个connection。 --> <property name="lazyInit" value="${db.lazyInit}" /> <!-- 设置是否关闭JMX功能。这个参数默认为false。 --> <property name="disableJMX" value="${db.disableJMX}" /> <!-- 设置连接池名字。用于当作JMX和助手线程名字的后缀。 --> <property name="poolName" value="${db.poolName}" /> <!-- /** Min no of prepared statements to cache. */ --> <!-- 设置statement缓存个数。这个参数默认为0。 --> <property name="statementsCacheSize" value="${db.statementsCacheSize}" /> <!-- 设置是否开启记录SQL语句功能。这个参数默认是false。 将执行的SQL记录到日志里面(包括参数值)。 --> <property name="logStatementsEnabled" value="${db.logStatementsEnabled}" /> <!-- 设置执行SQL的超时时间。这个参数默认为0;单位:毫秒。 当查询语句执行的时间超过这个参数,执行的情况就会被记录到日志中。 设置为0时,该功能失效。 --> <property name="queryExecuteTimeLimitInMs" value="${db.queryExecuteTimeLimit}" /> </bean> <!-- 配置SqlSessionFactoryBean --> <bean id="sqlSessionFactory2" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource2" /> <!-- mapper和resultmap配置路径 --> <property name="mapperLocations"> <list> <value>classpath:mapper2/*Mapper.xml</value> </list> </property> </bean> </beans>注意:(1)sqlSessionFactory2关联的Mapper.xml的映射地址;(2)数据源2中去除了事务管理的配置,否则使用事务时会找到两个事务管理器,有兴趣的可以研究下怎么控制事务。
(2)在spring中扫描Mapper.java文件:
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.alan.test.mapper" /> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property> </bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.alan.test.mapper2" /> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory2"></property> </bean>
注意:关联不同的包和sqlSessionFactory,这里使用sqlSessionFactoryBeanName,而不是sqlSessionFactory;
如果只是关联一个Mapper,则可以使用如下方式
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"> <property name="mapperInterface" value="com.alan.test.mapper2.UserMapper" /> <property name="sqlSessionFactory" ref="sqlSessionFactory2" /> </bean>
注意:mapper和mapper2中不能有相同的类名,因为扫描的时候会根据类名来新建bean托管给spring。
其它的Dao层等不用修改,在需要调用新数据库的地方,调用对应的mapper就可以了。