spring配置多数据源研究与实例

 近期由于业务需求需在在项目中配置多一个db链接,项目的的架构是ssh,需要在spring中配置多数据源,废话不多说。

先看配置文件spring配置文件applicationContext.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:tx="http://www.springframework.org/schema/tx"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
 <!-- 定义父数据源指定公共的属性 -->
 <bean id="parentDataSource"    class="org.apache.commons.dbcp.BasicDataSource"> 
             <property name="driverClassName">  
                 <value>com.mysql.jdbc.Driver</value>  
             </property>  
    <property name="maxActive" value="25000"></property>
    <property name="maxIdle" value="30"></property>
    <property name="maxWait" value="300"></property>              
 </bean>  
 <!-- 定义数据源1指定私有的属性 -->
 <bean id="adminDataSource" parent="parentDataSource">
  <property name="url"
   value="jdbc:mysql://192.168.1.8:3306/hyi?characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&autoReconnect=true&noAccessToProcedureBodies=true&useCompression=true">
  </property>
  <property name="username" value="root"></property>
  <property name="password" value="henyep"></property>
 </bean>
 <!-- 定义数据源2指定私有的属性 -->
 <bean id="userDataSource" parent="parentDataSource">
  <property name="url"
   value="jdbc:mysql://192.168.1.210:3306/INFORMATION_RELEASE?characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&autoReconnect=true&noAccessToProcedureBodies=true&useCompression=true">
  </property>
  <property name="username" value="development"></property>
  <property name="password" value="2011dev"></property>
 </bean> 
 <!-- 动态数据源 -->
 <bean id="dataSource" class="com.infoCollect.common.DynamicDataSource">   //注意这个类是我们自定义的重写了spring封装类的一个方法,具体的看后续类介绍
    <property name="defaultTargetDataSource" ref="adminDataSource"/>  <!-- 默认使用admin的数据源 -->
       <property name="targetDataSources">  
        <map key-type="java.lang.String">
         <entry key="user" value-ref="userDataSource"></entry> <!-- 加载user的数据源,可以添加更多 -->
        </map>
       </property>  
    </bean>  
 <bean id="sessionFactory"
  class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
  <property name="dataSource">
   <ref bean="dataSource" />
  </property>
  <!-- 给hibernate配置属性 -->
  <property name="hibernateProperties">
   <props>
    <prop key="hibernate.dialect">
    org.hibernate.dialect.MySQLDialect
    </prop>
    <prop key="hibernate.show_sql">false</prop>
    <prop key="hibernate.jdbc.fetch_size">25</prop>
    <prop key="hibernate.jdbc.batch_size">50</prop>
   </props>
  </property>
  <!-- 映射文件 下面两个文件分别是两个db中的表 -->
  <property name="mappingResources">
   <list>
    <value>com/infoCollect/hbm/country.hbm.xml</value>
    <value>com/infoCollect/hbm/TbUserManager.hbm.xml</value>
   </list>
  </property>
 </bean> 
<!-- 配置HIBERNATE基本的dao操作方法 -->
<bean id="ShareDao" class="com.infoCollect.common.ShareDao" abstract="true">
  <property name="sessionFactory">
   <ref bean="sessionFactory" />
  </property>
</bean> 
<bean id="sdaobean" class="com.infoCollect.common.ShareDao">
  <property name="sessionFactory">
   <ref bean="sessionFactory" />
  </property>
</bean> 
    <!-- 使用annotation 自动注册bean,并保证@Required,@Autowired的属性被注入 -->
<!-- 引入对应的关联注入文件 -->
<import resource="/com/infoCollect/springXml/applicationContext-test.xml"/>
<!-- 事物管理 -->
<bean id="transactionManager"
    class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- 给事物添加的属性 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">   
        <tx:attributes>   
             <!--  methods starting with 'save', 'update' or 'remove' use the default transaction settings -->
            <tx:method name="save*" propagation="REQUIRED"/> 
            <tx:method name="update*" propagation="REQUIRED"/>   
            <tx:method name="remove*" propagation="REQUIRED"/> 
        </tx:attributes>   
    </tx:advice>   
     <!--  ensure that the above transactional advice runs for any execution   
    of an operation defined by specified interface  -->  
    <aop:config>   
        <aop:pointcut id="daoOperation"  
            expression="execution(* com.infoCollect.common.ShareDao.*(..))"/>   
        <aop:advisor advice-ref="txAdvice" pointcut-ref="daoOperation"/>   
    </aop:config>  
</beans>


 

接下来创建一个数据源切换类,获得和设置上下文,主要负责设置上下文环境和获得上下文环境。

package com.infoCollect.common;
/*** 
 * 项目名称:hym2.0
 * <p>
 * 功能模块名称:
 * <p>
 * 文件名称为:ConfigSource.java
 * <p>
 * 文件功能简述:获得和设置上下文,主要负责设置上下文环境和获得上下文环境
 * <p>
 * 开发者:——张建明
 * <p>
 * 联系QQ:78098702
 * <p>
 * 联系电话:13418583587
 * <p>
 * 电子邮件:shenhua_66666@126.com
 * <p>
 * 备注:
 * @version v1.0
 * @copyright henyep
 */
public class ConfigSource {
 public static  final ThreadLocal contextHolder = new ThreadLocal();
 /**
  * 
  * 功能描述:设置数据源
  * @param datasource
  */
 public static  void useDataSource(String datasource){
  contextHolder.set(datasource);
 }
 /**
  * 
  * 功能描述:获取数据源
  * @return
  */
 public static String getDataSourceType(){
  return (String)contextHolder.get();
 }
 /**
  * 
  * 功能描述:移除数据源
  */
 public static void clearDataSource(){
  contextHolder.remove();
 }
}


 

继续创建一个类DataSourceMap主要为为了配置数据源常量

package com.infoCollect.common;

public class DataSourceMap {
 public static String datasource1="admin";   //这里的值 要跟 配置文件中的key value-ref对应起来 需谨慎
 public static String datasource2="user";
}


 

然后就是核心的原理了,了解过spring获取sessionfactroy机制的都清楚 spring能维护数据源和db事物是因为spring封装了AbstractRoutingDataSource这个类。spring功过这个类来获取具体该使用哪个数据源,所以我们要重写AbstractRoutingDataSource中的一个方法determineCurrentLookupKey() ,看下面的类

package com.infoCollect.common;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

public class DynamicDataSource extends AbstractRoutingDataSource {
/**
 * 这个类实现了determineCurrentLookupKey方法,该方法返回一个Object,
 * 一般是返回字符串,也可以是枚举类型。该方法中直接使用了ConfigSource.getCustomerType()方法获得上下文环境并直接返回。
 * 
 */
 @Override
 protected Object determineCurrentLookupKey() {
  // TODO Auto-generated method stub
  return ConfigSource.getDataSourceType();
 }

}


 

做到这里多数据源的配置已经完成,这里我只配置了两个数据源 分别连接了2个mysql,具体怎么使用呢,下面我觉个实例来测试一下是否能按切换数据源来分别的操作两个db。其实最关键的是dao类。action service 以及层层注入跟ssh耦合方式是一样的。

下面给出两个dao,分别是操作两个db中的表

第一个 查询db1中Hyicountry表

package com.infoCollect.dao;

import java.util.ArrayList;
import java.util.List;

import com.infoCollect.bean.Hyicountry;//实体bean
import com.infoCollect.common.ConfigSource;//数据源配置类 上面提到过
import com.infoCollect.common.DataSourceMap;//数据源常量类
import com.infoCollect.common.ShareDao;//底层的dao用来 crud

public class TestCountryDao extends ShareDao<Hyicountry, Integer> implements InterTestCountryDao{
 
 public List<Hyicountry> getList(){
  ConfigSource.useDataSource(DataSourceMap.datasource1); //这句最主要,告诉spring来使用第一个数据源
  List<Hyicountry> list = new ArrayList<Hyicountry>();
  String hql ="from Hyicountry";
  list = super.find(hql);
  return list;
 }
}


第二个dao  查询db2中TbUserManager表

package com.infoCollect.dao;

import java.util.ArrayList;
import java.util.List;

import com.infoCollect.bean.TbUserManager;
import com.infoCollect.common.ConfigSource;
import com.infoCollect.common.DataSourceMap;
import com.infoCollect.common.ShareDao;

public class UserManagerDao extends ShareDao<TbUserManager, Integer> implements InterUserManagerDao{
 public List<TbUserManager> getList(){
  ConfigSource.useDataSource(DataSourceMap.datasource2);
  List<TbUserManager> list = new ArrayList<TbUserManager>();
  String hql ="from TbUserManager";
  list = super.find(hql);
  return list;
 }
}


 

再贴出action吧

public class TestAction extends ActionSupport{
 private InterTestCountryDao zyDao;
 private InterUserManagerDao zyUserDao;

//从db1中取数据
 public String testhyi(){
  List<Hyicountry> list = zyDao.getList();  
  System.out.println("---"+list.size());
  return SUCCESS;
 }
 //从db2中取数据
 public String testNews(){
  List<TbUserManager> list = zyUserDao.getList();
  System.out.println("--+++-"+list.size());
  return SUCCESS;
 }


 

请求两次 结果如下
--+++-10
---237

 

到这里基本可用,至于性能,线程安全,事务处理是否完美 以及其他可优化的余地 仍需要研究,明天研究后再与同仁分享。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值