Spring动态配置多数据源--多mysql从库

来源:互联网 发布:淘宝是第三方活动平台 编辑:程序博客网 时间:2024/06/16 15:28

一直做了互联网的小项目,感觉小公司的性能瓶颈主要在数据库端。大公司没去过,不清楚鄙视~

一般用MySQL数据库做主从,读写分离,减少主库的压力。假设1主4从。4个从库每次的访问是随机,压力平摊。

先把搜来的贴出来。先记录下,再去code实验~

采用spring的AbstractRoutingDataSource就可以简单的解决这个问题。下面是用ibatis的。单独的spring mvc 实现也是用AbstractRoutingDataSource类

AbstractRoutingDataSource实现了javax.sql.DataSource接口,因此可以理解为一个虚拟的动态DataSource,在需要的时候根据上下文Context动态决定使用哪个数据源。

                                              strut2 spring ibatis整合项目代码下载

下面这个是ibatis 的 没实验只是简单看看,不过每次 service都要

  1. DbContextHolder.setDbType("2");  
从库多了哥们都设置晕了。稍后学习奉上根据事务管理直接动态随机分配的~
(9.21更新 。在最下面的第2部分是根据公司的项目整理出来的。测试通过,可以动态分配)

/******************************一 、复制来的例子 开始**********************************************/

Xml代码 复制代码
  1. <beans xmlns="http://www.springframework.org/schema/beans"  
  2.         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  3.         xmlns:aop="http://www.springframework.org/schema/aop"  
  4.         xmlns:tx="http://www.springframework.org/schema/tx"  
  5.         xmlns:jee="http://www.springframework.org/schema/jee"  
  6.         xsi:schemaLocation="   
  7.             http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd   
  8.             http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd   
  9.             http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd   
  10.             http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd">  
  11.   
  12.   
  13.     <!-- ========================= GENERAL DEFINITIONS ========================= -->  
  14.     <jee:jndi-lookup id="ds0" jndi-name="jdbc/ds0"/>  
  15.     <jee:jndi-lookup id="ds1" jndi-name="jdbc/ds1"/>  
  16.     <jee:jndi-lookup id="ds2" jndi-name="jdbc/ds2"/>  
  17.        
  18.     <bean id="dataSource" class="com.xxx.xxx.util.DynamicDataSource">     
  19.             <property name="targetDataSources">     
  20.                <map key-type="java.lang.String">     
  21.                   <entry key="0" value-ref="ds0"/>  
  22.                   <entry key="1" value-ref="ds1"/>  
  23.                   <entry key="2" value-ref="ds2"/>     
  24.                </map>     
  25.             </property>     
  26.             <property name="defaultTargetDataSource" ref="1"/>     
  27.     </bean>  
  28.         <!-- SqlMap setup for iBATIS Database Layer -->  
  29.     <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">  
  30.         <property name="dataSource" ref="dataSource"/>  
  31.         <property name="configLocation" value="classpath:com/xxx/xxx/dao/sqlmap/sql-map-config.xml"/>  
  32.     </bean>  
  33.         <bean id="testDAO" class="com.xxx.xxx.dao.impl.TestDAO">  
  34.         <property name="sqlMapClient" ref="sqlMapClient"/>  
  35.     </bean>  
  36.         <bean id="testService" class="com.xxx.xxx.service.impl.TestService">  
  37.         <property name="testDAO" ref="testDAO"/>  
  38.     </bean>  
  39. </beans>  

其核心是DynamicDataSource,代码如下

Java代码 复制代码
  1. package com.xxx.xxx.util;   
  2.   
  3. import org.apache.log4j.Logger;   
  4. import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;   
  5.   
  6. public class DynamicDataSource extends AbstractRoutingDataSource {   
  7.   
  8.     static Logger log = Logger.getLogger("DynamicDataSource");   
  9.     @Override  
  10.     protected Object determineCurrentLookupKey() {   
  11.         // TODO Auto-generated method stub  
  12.         return DbContextHolder.getDbType();   
  13.     }   
  14.   
  15. }  

上下文DbContextHolder为一线程安全的ThreadLocal,如下

Java代码 复制代码
  1. package com.xxx.xxx.util;   
  2.   
  3. public class DbContextHolder {   
  4.     private static final ThreadLocal contextHolder = new ThreadLocal();   
  5.   
  6.     public static void setDbType(String dbType) {   
  7.         contextHolder.set(dbType);   
  8.     }   
  9.   
  10.     public static String getDbType() {   
  11.         return (String) contextHolder.get();   
  12.     }   
  13.   
  14.     public static void clearDbType() {   
  15.         contextHolder.remove();   
  16.     }   
  17. }  

sql-map-config.xml如下

Xml代码 复制代码
  1. <?xml version="1.0" encoding="UTF-8" standalone="no"?>  
  2. <!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"   
  3.         "http://www.ibatis.com/dtd/sql-map-config-2.dtd">  
  4.   
  5. <sqlMapConfig>  
  6.   
  7.     <sqlMap resource="com/xxx/xxx/dao/sqlmap/Object.xml"/>  
  8.   
  9. </sqlMapConfig>  

这样在调用service之前只需要设置一下上下文即可调用相应的数据源,如下:

Java代码 复制代码
  1. DbContextHolder.setDbType("2");   
  2. //execute services   
  3. //.........  

dao如下

Java代码 复制代码
  1. package com.xxx.xxx.dao.impl;   
  2.   
  3. import java.util.HashMap;   
  4. import java.util.List;   
  5. import java.util.Map;   
  6.   
  7. import org.apache.log4j.Logger;   
  8. import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;   
  9.   
  10. import com.xxx.xxx.vo.TestObj;   
  11.   
  12. public class TestDAO extends SqlMapClientDaoSupport implements ITestDAO {   
  13.   
  14.     static Logger log = Logger.getLogger(TestDAO.class);   
  15.   
  16.     public TestObj getTestObj(String objID) throws Exception {   
  17.         return (TestObj) getSqlMapClientTemplate().queryForObject("getTestObj", objID);   
  18.     }   
  19. }  

 

 /******************************一 、复制来的例子 结束**********************************************/

/********************************************二、动态分配数据源 spring2.5  +ibatis 开始*************************************************/
application中db的配置
[html] view plain copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"  
  4.        xmlns:aop="http://www.springframework.org/schema/aop"  
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">  
  6.     <!-- 数据库配置文件加载 -->  
  7.     <bean id="propertyConfigurer"  
  8.         class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
  9.         <property name="locations">  
  10.             <list>  
  11.                 <value>classpath:/jdbc.properties</value>  
  12.             </list>  
  13.         </property>  
  14.     </bean>  
  15.       
  16.     <!-- 数据源parent-->  
  17.     <bean id="parentDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"  
  18.         destroy-method="close" abstract="true">  
  19.         <property name="driverClass">  
  20.             <value>${jdbc.driverClassName}</value>  
  21.         </property>  
  22.         <property name="jdbcUrl">  
  23.             <value>${jdbc.url}</value>  
  24.         </property>  
  25.         <property name="user">  
  26.             <value>${jdbc.username}</value>  
  27.         </property>  
  28.         <property name="password">  
  29.             <value>${jdbc.password}</value>  
  30.         </property>  
  31.         <property name="maxPoolSize">  
  32.             <value>${jdbc.maxPoolSize}</value>  
  33.         </property>  
  34.         <property name="minPoolSize">  
  35.             <value>${jdbc.minPoolSize}</value>  
  36.         </property>  
  37.         <property name="initialPoolSize">  
  38.             <value>${jdbc.initialPoolSize}</value>  
  39.         </property>  
  40.         <property name="idleConnectionTestPeriod">  
  41.             <value>${jdbc.idleConnectionTestPeriod}  
  42.             </value>  
  43.         </property>  
  44.         <property name="maxIdleTime">  
  45.             <value>${jdbc.maxIdleTime}</value>  
  46.         </property>  
  47.     </bean>  
  48.     <!-- 主库数据源-->  
  49.     <bean id="writedb" parent="parentDataSource"></bean>  
  50.     <!-- 从库数据源-->  
  51.     <bean id="read02" destroy-method="close" parent="parentDataSource">  
  52.         <property name="jdbcUrl">  
  53.             <value>${jdbc.read.db02.url}</value>  
  54.         </property>  
  55.         <property name="user">  
  56.             <value>${jdbc.read.db02.username}</value>  
  57.         </property>  
  58.         <property name="password">  
  59.             <value>${jdbc.read.db02.password}</value>  
  60.         </property>  
  61.     </bean>  
  62.     <!-- 从库数据源-->  
  63.     <bean id="read03" destroy-method="close" parent="parentDataSource">  
  64.         <property name="jdbcUrl">  
  65.             <value>${jdbc.read.db03.url}</value>  
  66.         </property>  
  67.         <property name="user">  
  68.             <value>${jdbc.read.db03.username}</value>  
  69.         </property>  
  70.         <property name="password">  
  71.             <value>${jdbc.read.db03.password}</value>  
  72.         </property>  
  73.     </bean>  
  74.   
  75.       
  76.     <!-- 动态数据源 -->  
  77.     <bean id="dataSource" class="com.share.common.database.DataSourceRouter">  
  78.         <property name="targetDataSources">  
  79.             <map key-type="java.lang.String">  
  80.                 <entry key="writedb" value-ref="writedb" />  
  81.                 <entry key="read02" value-ref="read02" />  
  82.                 <entry key="read03" value-ref="read03" />  
  83.             </map>  
  84.         </property>  
  85.         <property name="defaultTargetDataSource" ref="writedb" />  
  86.         <property name="dataSourceKey">  
  87.             <ref local="dataSourceKey" />  
  88.         </property>  
  89.     </bean>  
  90.   
  91.     <!-- 读写管理 -->  
  92.     <bean id="dataSourceKey" class="com.share.common.database.DataSourceKeyImpl">  
  93.         <property name="readDateSourceMap">  
  94.             <map key-type="java.lang.String">  
  95.                 <entry key="read02" value="read02" />  
  96.                 <entry key="read03" value="read03" />  
  97.                   
  98.             </map>  
  99.         </property>  
  100.         <property name="writedbKey">  
  101.             <value>writedb</value>  
  102.         </property>  
  103.     </bean>  
  104.       
  105.     <!-- 事务配置 -->  
  106.     <bean id="transactionManager"  
  107.         class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
  108.         <property name="dataSource" ref="dataSource"></property>  
  109.     </bean>  
  110.   
  111.     <!-- 事务管理拦截器 -->  
  112.     <bean id="transactionInterceptor"  
  113.         class="org.springframework.transaction.interceptor.TransactionInterceptor">  
  114.         <property name="transactionManager" ref="transactionManager" />  
  115.         <property name="transactionAttributes">  
  116.             <props>  
  117.                 <prop key="query*">PROPAGATION_SUPPORTS,-Exception</prop>  
  118.                 <prop key="select*">PROPAGATION_SUPPORTS,-Exception</prop>  
  119.                 <prop key="find*">PROPAGATION_SUPPORTS,-Exception</prop>  
  120.                 <prop key="get*">PROPAGATION_SUPPORTS,-Exception</prop>  
  121.                   
  122.                 <prop key="save*">PROPAGATION_REQUIRED,-Exception</prop>  
  123.                 <prop key="update*">PROPAGATION_REQUIRED,-Exception</prop>  
  124.                 <prop key="delete*">PROPAGATION_REQUIRED,-Exception</prop>  
  125.                 <prop key="add*">PROPAGATION_REQUIRED,-Exception</prop>  
  126.                 <prop key="edit*">PROPAGATION_REQUIRED,-Exception</prop>  
  127.                 <prop key="*">PROPAGATION_SUPPORTS,-Exception</prop>  
  128.             </props>  
  129.         </property>  
  130.     </bean>  
  131.   
  132.   
  133.     <!-- 动态数据源拦截器 -->  
  134.     <bean id="dataSourceInterceptor" class="com.share.common.database.DataSourceInterceptor">  
  135.         <property name="attributes">  
  136.             <props>  
  137.                 <prop key="query*">readdb</prop>  
  138.                 <prop key="select*">readdb</prop>  
  139.                 <prop key="find*">readdb</prop>  
  140.                 <prop key="get*">readdb</prop>  
  141.                 <prop key="save*">writedb</prop>  
  142.                 <prop key="update*">writedb</prop>  
  143.                 <prop key="delete*">writedb</prop>  
  144.                 <prop key="add*">writedb</prop>  
  145.                 <prop key="edit*">writedb</prop>  
  146.                 <prop key="*">readdb</prop>  
  147.             </props>  
  148.         </property>  
  149.         <property name="dataSourceKey">  
  150.             <ref bean="dataSourceKey" />  
  151.         </property>  
  152.     </bean>  
  153.   
  154.     <!-- 根据service名称拦截 -->  
  155.     <bean  
  156.         class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">  
  157.         <property name="beanNames">  
  158.             <list>  
  159.                 <value>*Service</value>  
  160.             </list>  
  161.         </property>  
  162.         <property name="interceptorNames">  
  163.             <list>  
  164.                 <value>dataSourceInterceptor</value>  
  165.             </list>  
  166.         </property>  
  167.     </bean>  
  168.     <!-- ibatis  sqlMapClient-->  
  169.     <bean id="sqlMapClient"  
  170.           class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">  
  171.         <property name="configLocation"  
  172.                   value="classpath:/config/ibatis/SqlMapConfig.xml"/>  
  173.         <property name="dataSource" ref="dataSource"/>  
  174.     </bean>  
  175.     <!-- dao  基类 -->  
  176.     <bean id="simpleDao" class="com.share.common.dao.IbatisSimpleDaoImpl">  
  177.         <property name="sqlMapClient" ref="sqlMapClient"/>  
  178.     </bean>  
  179.       
  180. </beans>  

jdbc.properties
 
 
[html] view plain copy
  1. jdbc.driverClassName=com.mysql.jdbc.Driver  
  2. jdbc.url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull  
  3. jdbc.username=root  
  4. jdbc.password=root  
  5. jdbc.maxPoolSize=100  
  6. jdbc.minPoolSize=10  
  7. jdbc.initialPoolSize=10  
  8. jdbc.idleConnectionTestPeriod=900  
  9. jdbc.maxIdleTime=1800  
  10.   
  11. jdbc.read.db02.url=jdbc:mysql://127.0.0.1:3306/test02?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull  
  12. jdbc.read.db02.username=root  
  13. jdbc.read.db02.password=root  
  14.   
  15. jdbc.read.db03.url=jdbc:mysql://127.0.0.1:3306/test03?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull  
  16. jdbc.read.db03.username=root  
  17. jdbc.read.db03.password=root  
 
最近忙没时间都贴出来,有时间再上传下全部的。
主要原理:
1.写自己的Rout类继承AbstractRoutingDataSource类
@Override determineCurrentLookupKey()方法
此方法返回dataSource的key.我们只要控制这个key.(例子中有3个writedb、 readdb02、readdb03 ),就是控制了每次使用的那个数据源。
2.拦截器
写自己的拦截器实现MethodInterceptor。在此拦截器中根据请求的方法名字设置key.(例子中有3个writedb、 readdb02、readdb03 )
然后在自己的Rout类中返回就可以了。
最终执行测试的结果:
循环10次查询。10次读的库是随机的,我测的时候配置了10个从库.
 
/********************************************二、动态分配数据源 spring2.5  +ibatis*************************************************/
0 0
原创粉丝点击