Spring多数据源解决方案

简介: 在很多大型应用中都会对数据进行切分,并且采用多个数据库实例进行管理,这样可以有效提高系统的水平伸缩性。而这样的方案就会不同于常见的单一数据实例的方案,这就要程序在运行时根据当时的请求及系统状态来动态的决定将数据存储在哪个数据库实例中,以及从哪个数据库提取数据。

在很多大型应用中都会对数据进行切分,并且采用多个数据库实例进行管理,这样可以有效提高系统的水平伸缩性。而这样的方案就会不同于常见的单一数据实例的方案,这就要程序在运行时根据当时的请求及系统状态来动态的决定将数据存储在哪个数据库实例中,以及从哪个数据库提取数据。

<a class=common href='http://www.soidc.net/search_article.shtml?wo=Spring' target='_blank'>Spring</a>多<a class=common href='http://www.soidc.net/search_article.shtml?wo=%CA%FD%BE%DD%D4%B4' target='_blank'>数据源</a><a class=common href='http://www.soidc.net/search_article.shtml?wo=%BD%E2%BE%F6%B7%BD%B0%B8' target='_blank'>解决方案</a>

  Figure 1 数据分割及多数据库架构

   通常这种多数据源的逻辑会渗透到业务逻辑中,同时也会给我们使用的数据访问API诸如Hibernate和iBatis等带来不便(需要指定多个SessionFactory或SqlMapClient实例来对应多个DataSource)。

<a class=common href='http://www.soidc.net/search_article.shtml?wo=Spring%B6%E0%CA%FD%BE%DD%D4%B4%BD%E2%BE%F6%B7%BD%B0%B8' target='_blank'>Spring多数据源解决方案</a>

  图片看不清楚?请点击这里查看原图(大图)。

  Figure 2 多数据源的选择逻辑渗透至客户端

   解决方案

Spring多数据源解决方案

  图片看不清楚?请点击这里查看原图(大图)。

  Figure 3 采用Proxy模式来封装数据源选择逻辑

   通过采用Proxy模式我们在方案中实现一个虚拟的数据源,并且用它来封装数据源选择逻辑,这样就可以有效地将数据源选择逻辑从Client中分离出来。

   Client提供选择所需的上下文(因为这是Client所知道的),由虚拟的DataSource根据Client提供的上下文来实现数据源的选择。

Spring2.0.1以后的版本已经支持配置多数据源,并且可以在运行的时候动态加载不同的数据源。通过继承 AbstractRoutingDataSource就可以实现多数据源的动态转换。目前做的项目就是需要访问12个数据源,每个数据源的表结构都是相同的,所以要求数据源的变动对于编码人员来说是透明,也就是说同样SQL语句在不同的环境下操作的数据库是不一样的。具体的配置如下:
一、首先需要写一个静态的键值对照类:
package cn.com.xinli.ccp.dynamicds;                                                                                       

public class DataSourceMap {
    public static final String Admin = "Admin";
    public static final String Yxh = "Yxh";
}

这个类主要在使用的时候当作获得数据源的标志使用。

二、建立一个获得和设置上下文的类:
package cn.com.xinli.ccp.dynamicds;

public class CustomerContextHolder {
    private static final ThreadLocal contextHolder = new ThreadLocal();

    public static void setCustomerType(String customerType) {
        contextHolder.set(customerType);
    }

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

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

}


这个主要负责设置上下文环境和获得上下文环境。
三、建立动态数据源类,这个类必须继承AbstractRoutingDataSource:

package cn.com.xinli.ccp.dynamicds;

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

public class DynamicDataSource extends AbstractRoutingDataSource {

    protected Object determineCurrentLookupKey() {
        // TODO Auto-generated method stub
        return CustomerContextHolder.getCustomerType();
    }

}

这个类实现了determineCurrentLookupKey方法,该方法返回一个Object,一般是返回字符串,也可以是枚举类型。该方法中直接使用了CustomerContextHolder.getCustomerType()方法获得上下文环境并直接返回。
四、编写spring的配置文件配置数据源
<bean id="parentDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>COM.ibm.db2.jdbc.net.DB2Driver</value>
</property>
<property name="url">
<value>jdbc:db2:127.0.0.1:TEST</value>
</property>
</bean>

<bean id="adminDataSource" parent="parentDataSource">
<property name="username" value="admin"/>
<property name="password" value="master997mb"/>
</bean>

<bean id="yxhDataSource" parent="parentDataSource">
<property name="username" value="yxh"/>
<property name="password" value="yxh"/>
</bean>


在这个配置中可以看到首先有个parentDataSource,这个主要配置一些数据源的公用信息,项目中都是链接DB2数据库;adminDataSource和yxhDataSource是根据不同需要配置的个性化信息,但都必须加parent属性,值为 parentDataSource。这样就配置好了2个数据源信息。当然如果链接的多数据源是不同类型的两个数据库,那么 parentDataSource就可以不要了,直接配置两个不同的数据源链接就可以了。
五、编写spring配置文件配置多数据源映射关系
<bean id="dataSource" class="cn.com.xinli.ccp.dynamicds.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="Yxh" value-ref="yxhDataSource"/>
</map>
</property>
<property name="defaultTargetDataSource" ref="adminDataSource"/>
</bean>


在这个配置中第一个property属性配置目标数据源,<map key-type="java.lang.String">中的key-type必须要和静态键值对照类DataSourceMap中的值的类型相同;<entry key="Yxh" value-ref="yxhDataSource"/>中key的值必须要和静态键值对照类中的值相同,如果有多个值,可以配置多个< entry>标签。第二个property属性配置默认的数据源。
六、配置hibernate。
Hibernate的配置和普通的hibernate、spring结合的配置一样
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <!-- to override, use the "SpringDatasourceConfig" snippet in your project -->
    <property name="dataSource">
        <ref local="dataSource" />
    </property>
    <property name="mappingResources">
        <list>
            <value>
                cn/com/xinli/ccp/entity/User.hbm.xml
</value>
            <value>
                cn/com/xinli/ccp/entity/Test.hbm.xml
</value>
        </list>
    </property>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">
                org.hibernate.dialect.DB2Dialect
</prop>

            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.use_outer_join">true</prop>
            <prop key="hibernate.jdbc.batch_size">50</prop>
            <prop key="hibernate.jdbc.fetch_size">5</prop>
            <prop key="hibernate.connection.pool_size">2</prop>
            <prop key="hibernate.connection.autocommit">false</prop>
            <prop key="hibernate.cache.use_query_cache">false</prop>
            <prop key="hibernate.max_fetch_depth">1</prop>
            <prop key="hibernate.bytecode.use_reflection_optimizer">true</prop>
        </props>
    </property>
</bean>

<bean id="mydao" class="cn.com.xinli.ccp.dao.HibernateBaseDao">
    <property name="sessionFactory">
        <ref local="sessionFactory" />
    </property>
</bean>


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

七、配置结束,可以使用了。
public class DaoTest extends TestCase {

public void testSave() throws Exception{
CustomerContextHolder.setCustomerType(DataSourceMap.Admin);//设置数据源
//hibernate创建实体
Test test = new Test();
test.setTest("22222222");

mydao.save(test);//使用dao保存实体

CustomerContextHolder.setCustomerType(DataSourceMap.Yxh);//设置为另一个数据源

mydao.save(test);//使用dao保存实体到另一个库中

}
}

在项目中对于编码人员对多数据源的切换可以做成透明的,操作同样的dao,就可以访问不同的数据库了。

目录
相关文章
|
10月前
|
人工智能 监控 安全
智慧工地解决方案,Spring Cloud智慧工地源代码
智慧工地平台针对建筑工地人员管理难、机械设备繁多、用电安全及施工环境复杂等问题,通过集成应用和硬件设备,实现数据互联互通与集中展示。基于微服务架构(Java+Spring Cloud+UniApp+MySql),平台支持PC端、手机端、平板端、大屏端管理,涵盖人员实名制、工资考勤、视频AI监控、绿色施工、危大工程监测、物料管理和安全质量管理等功能,助力施工现场的数字化、智能化综合管理,提升效率与安全性。
216 15
|
6月前
|
druid Java 关系型数据库
Spring Boot与Druid升级解决方案
好的,我需要帮助用户解决他们遇到的数据库连接问题,并升级项目的依赖。首先,用户提供的错误信息是关于Spring Boot应用在初始化数据源时抛出的异常,具体是Druid连接池验证连接失败。同时,用户希望升级项目的依赖版本。
603 10
|
Dubbo Java 应用服务中间件
Spring Cloud Dubbo:微服务通信的高效解决方案
【10月更文挑战第15天】随着信息技术的发展,微服务架构成为企业应用开发的主流。Spring Cloud Dubbo结合了Dubbo的高性能RPC和Spring Cloud的生态系统,提供高效、稳定的微服务通信解决方案。它支持多种通信协议,具备服务注册与发现、负载均衡及容错机制,简化了服务调用的复杂性,使开发者能更专注于业务逻辑的实现。
247 2
|
7月前
|
监控 Java 关系型数据库
Spring Boot整合MySQL主从集群同步延迟解决方案
本文针对电商系统在Spring Boot+MyBatis架构下的典型问题(如大促时订单状态延迟、库存超卖误判及用户信息更新延迟)提出解决方案。核心内容包括动态数据源路由(强制读主库)、大事务拆分优化以及延迟感知补偿机制,配合MySQL参数调优和监控集成,有效将主从延迟控制在1秒内。实际测试表明,在10万QPS场景下,订单查询延迟显著降低,超卖误判率下降98%。
322 5
|
7月前
|
SQL 前端开发 Java
深入分析 Spring Boot 项目开发中的常见问题与解决方案
本文深入分析了Spring Boot项目开发中的常见问题与解决方案,涵盖视图路径冲突(Circular View Path)、ECharts图表数据异常及SQL唯一约束冲突等典型场景。通过实际案例剖析问题成因,并提供具体解决方法,如优化视图解析器配置、改进数据查询逻辑以及合理使用外键约束。同时复习了Spring MVC视图解析原理与数据库完整性知识,强调细节处理和数据验证的重要性,为开发者提供实用参考。
318 0
|
7月前
|
安全 前端开发 Java
Spring Boot 项目中触发 Circular View Path 错误的原理与解决方案
在Spring Boot开发中,**Circular View Path**错误常因视图解析与Controller路径重名引发。当视图名称(如`login`)与请求路径相同,Spring MVC无法区分,导致无限循环调用。解决方法包括:1) 明确指定视图路径,避免重名;2) 将视图文件移至子目录;3) 确保Spring Security配置与Controller路径一致。通过合理设定视图和路径,可有效避免该问题,确保系统稳定运行。
491 0
|
9月前
|
网络协议 Java Shell
java spring 项目若依框架启动失败,启动不了服务提示端口8080占用escription: Web server failed to start. Port 8080 was already in use. Action: Identify and stop the process that’s listening on port 8080 or configure this application to listen on another port-优雅草卓伊凡解决方案
java spring 项目若依框架启动失败,启动不了服务提示端口8080占用escription: Web server failed to start. Port 8080 was already in use. Action: Identify and stop the process that’s listening on port 8080 or configure this application to listen on another port-优雅草卓伊凡解决方案
574 7
|
11月前
|
Java Nacos Sentinel
Spring Cloud Alibaba:一站式微服务解决方案
Spring Cloud Alibaba(简称SCA) 是一个基于 Spring Cloud 构建的开源微服务框架,专为解决分布式系统中的服务治理、配置管理、服务发现、消息总线等问题而设计。
2356 13
Spring Cloud Alibaba:一站式微服务解决方案
|
druid Java 关系型数据库
Spring Boot2 系列教程(二十五)Spring Boot 整合 Jpa 多数据源
Spring Boot2 系列教程(二十五)Spring Boot 整合 Jpa 多数据源
1348 0
|
11月前
|
运维 监控 Java
为何内存不够用?微服务改造启动多个Spring Boot的陷阱与解决方案
本文记录并复盘了生产环境中Spring Boot应用内存占用过高的问题及解决过程。系统上线初期运行正常,但随着业务量上升,多个Spring Boot应用共占用了64G内存中的大部分,导致应用假死。通过jps和jmap工具排查发现,原因是运维人员未设置JVM参数,导致默认配置下每个应用占用近12G内存。最终通过调整JVM参数、优化堆内存大小等措施解决了问题。建议在生产环境中合理设置JVM参数,避免资源浪费和性能问题。
772 3