博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一个Web项目中实现多个数据库存储数据并相互切换用过吗?
阅读量:5787 次
发布时间:2019-06-18

本文共 4750 字,大约阅读时间需要 15 分钟。

最近公司一个项目需要连接多个数据库(A和B)操作,根据不同的业务模块查询不同的数据库,因此需要改造下之前的spring-mybatis.xml配置文件以及jdbc.properties配置文件,项目后台用的是SpringMVC+Mybatis+MySQL架构,折腾了一两天算是搞定了,在这里记录过改造过程。

使用场景

多数据源的使用的场景一般有:

  1. 主从数据库切换
  2. 读写分离
  3. 兼容旧库

实现原理

    Spring2.x的版本中采用Proxy模式,就是在方案中实现一个虚拟的数据源,并且用它来封装数据源选择逻辑,这样就可以有效地将数据源选择逻辑从Client中分离出来。Client提供选择所需的上下文,由虚拟的DynamicDataSource根据Client提供的上下文来实现数据源的选择。

具体的实现是虚拟的DynamicDataSource仅需继承AbstractRoutingDataSource实现determineCurrentLookupKey(),该方法返回需要使用的DataSource的key值,然后根据这个key从resolvedDataSources这个map里取出对应的DataSource,如果找不到则用默认的resolvedDefaultDataSource。

详细实现过程

  1:修改jdbc.properties的配置文件

  #A 数据源A库

  jdbc.a.driverClassName=com.mysql.jdbc.Driver
  jdbc.a.url=jdbc:mysql://localhost:3306/exam_zhaosq?useUnicode=true&characterEncoding=utf-8
  jdbc.a.username=root
  jdbc.a.password=root

  #B  数据源B库

  jdbc.b.driverClassName=com.mysql.jdbc.Driver
  jdbc.b.url=jdbc:mysql://localhost:3306/myshop?useUnicode=true&characterEncoding=utf-8
  jdbc.b.username=root
  jdbc.b.password=root

  2:修改spring-mybatis.xml的配置文件 配置文件里需要配置多个数据源,改造后主要配置如

<!-- 引入jdbc.properties文件 -->

<context:property-placeholder location="classpath:jdbc.properties" />

<bean id="dataSourceTargetA" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close" scope="singleton">

  <property name="driverClass" value="${jdbc.a.driverClassName}" />
  <property name="jdbcUrl" value="${jdbc.a.url}" />
  <property name="user" value="${jdbc.a.username}" />
  <property name="password" value="${jdbc.a.password}" />
</bean>

<bean id="dataSourceTargetB" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close" scope="singleton">

  <property name="driverClass" value="${jdbc.b.driverClassName}" />
  <property name="jdbcUrl" value="${jdbc.b.url}" />
  <property name="user" value="${jdbc.b.username}" />
  <property name="password" value="${jdbc.b.password}" />
</bean>
<!-- 动态数据源 -->
<bean id="dynamicDataSource" class="com.test.util.DynamicDataSource" >
  <property name="targetDataSources">
    <map key-type="java.lang.String">
      <entry value-ref="dataSourceTargetA" key="dataSourceTargetA"></entry>
      <entry value-ref="dataSourceTargetB" key="dataSourceTargetB"></entry>
     </map>
   </property>
   <property name="defaultTargetDataSource" ref="dataSourceTargetA" >
   </property>
</bean>

<bean id="txManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dynamicDataSource" />
</bean>

<!-- MyBatis ORM operation class -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dynamicDataSource" />
  <property name="mapperLocations">
    <list>
      <value>classpath*:com/test/**/*Mapper.xml</value>
    </list>
  </property>
  <property name="configLocation" value="classpath:provider-sql-map-config.xml" />
</bean>

 2.添加动态数据源管理类

 DynamicDataSource类继承AbstractRoutingDataSource,实现determineCurrentLookupKey()方法。

package com.test.util;

import com.test.util.CustomerContextHolder;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**

* 动态数据源管理类
*
*/
public class DynamicDataSource extends AbstractRoutingDataSource {

   @Override

   protected Object determineCurrentLookupKey() {
    return CustomerContextHolder.getCustomerType();
  }
}

3. 数据源切换类

CustomerContextHolder类可以实现数据源A和B的切换,数据源标识保存在线程变量中,避免多线程操作数据源时互相干扰。

package com.test.util;

/**
* 数据源切换类
*
*/
public class CustomerContextHolder {
  public static final String DATA_SOURCE_DEFAULT = "dataSourceTargetA";
  public static final String DATA_SOURCE_B = "dataSourceTargetB";
  private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
  

  public static void setCustomerType(String customerType) {

      contextHolder.set(customerType);
  }

  public static String getCustomerType() {
    return contextHolder.get();
  }

  public static void clearCustomerType() {
    contextHolder.remove();
  }
}

4. 使用多数据源代码

下面是Controller层代码,需要查询B数据源,查询完成后切换为默认数据源A,具体代码如下:

/**

* 订单列表查询,查询B数据源
*
* @param request
* @return
*/
@Controller
@RequestMapping(value="/customer")
public class CustomerController
{

  @RequestMapping(value = "/list")

  public String list(HttpServletRequest request, Integer cId) {
    //设置数据源B
    CustomerContextHolder.setCustomerType(CustomerContextHolder.DATA_SOURCE_B);
    List<Order> orderList = orderService.getListByCid(cId);
    request.setAttribute("orderList", orderList);

    //切换回默认数据源A

    CustomerContextHolder.setCustomerType(CustomerContextHolder.DATA_SOURCE_DEFAULT);
    return "/jsp/order";
}

   当进入customer方法的时候,会先从数据库B中的表进行查询数据,查询完成后,会切换到默认的数据库A,然后再从数据库A中的表查询数据,这样就达到了在一个Web项目中,根据不用的模块和业务需求,实现多个数据库存储数据和它们之间的切换了。

上述四步操作完成后即可实现SpringMVC+Mybatis配置多个数据源(库)并切换,有问题欢迎留言指教!

 好文转载学习自:

转载于:https://www.cnblogs.com/zhaosq/p/10616244.html

你可能感兴趣的文章
Scrapy基本用法
查看>>
PAT A1030 动态规划
查看>>
自制一个 elasticsearch-spring-boot-starter
查看>>
软件开发学习的5大技巧,你知道吗?
查看>>
【人物志】美团前端通道主席洪磊:一位产品出身、爱焊电路板的工程师
查看>>
一份关于数据科学家应该具备的技能清单
查看>>
机器学习实战_一个完整的程序(一)
查看>>
Web框架的常用架构模式(JavaScript语言)
查看>>
如何用UPA优化性能?先读懂这份报告!
查看>>
这些Java面试题必须会-----鲁迅
查看>>
Linux 常用命令
查看>>
CSS盒模型
查看>>
ng2路由延时加载模块
查看>>
使用GitHub的十个最佳实践
查看>>
脱离“体验”和“安全”谈盈利的游戏运营 都是耍流氓
查看>>
慎用!BLEU评价NLP文本输出质量存在严重问题
查看>>
JAVA的优势就是劣势啊!
查看>>
ELK实战之logstash部署及基本语法
查看>>
帧中继环境下ospf的使用(点到点模式)
查看>>
BeanShell变量和方法的作用域
查看>>