`

利用AbstractRoutingDataSource实现动态数据源切换

 
阅读更多
现在大型的电子商务系统,在数据库层面大都采用读写分离技术,就是一个Master数据库,多个Slave数据库。Master库负责数据更新和实时数据查询,Slave库当然负责非实时数据查询。因为在实际的应用中,数据库都是读多写少(读取数据的频率高,更新数据的频率相对较少),而读取数据通常耗时比较长,占用数据库服务器的CPU较多,从而影响用户体验。我们通常的做法就是把查询从主库中抽取出来,采用多个从库,使用负载均衡,减轻每个从库的查询压力。

  采用读写分离技术的目标:有效减轻Master库的压力,又可以把用户查询数据的请求分发到不同的Slave库,从而保证系统的健壮性。我们看下采用读写分离的背景。

  随着网站的业务不断扩展,数据不断增加,用户越来越多,数据库的压力也就越来越大,采用传统的方式,比如:数据库或者SQL的优化基本已达不到要求,这个时候可以采用读写分离的策 略来改变现状。

  具体到开发中,如何方便的实现读写分离呢?目前常用的有两种方式:

  1 第一种方式是我们最常用的方式,就是定义2个数据库连接,一个是MasterDataSource,另一个是SlaveDataSource。更新数据时我们读取MasterDataSource,查询数据时我们读取SlaveDataSource。这种方式很简单,我就不赘述了。

  2 第二种方式动态数据源切换,就是在程序运行时,把数据源动态织入到程序中,从而选择读取主库还是从库。主要使用的技术是:annotation,Spring AOP ,反射。下面会详细的介绍实现方式。

   在介绍实现方式之前,我们先准备一些必要的知识,spring 的AbstractRoutingDataSource

     AbstractRoutingDataSource这个类 是spring2.0以后增加的,我们先来看下AbstractRoutingDataSource的定义:

AbstractRoutingDataSource这个类 是spring2.0以后增加的,我们先来看下AbstractRoutingDataSource的定义:

public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {  
  
    private Map<Object, Object> targetDataSources;  
  
    private Object defaultTargetDataSource;  
  
    private DataSourceLookup dataSourceLookup = new JndiDataSourceLookup();  
  
    private Map<Object, DataSource> resolvedDataSources;  
  
    private DataSource resolvedDefaultDataSource;  


AbstractRoutingDataSource继承了AbstractDataSource ,而AbstractDataSource 又是DataSource 的子类。
DataSource   是javax.sql 的数据源接口,定义如下:

public interface DataSource  extends CommonDataSource,Wrapper {  
  
  Connection getConnection() throws SQLException;  
   
  Connection getConnection(String username, String password)  
    throws SQLException;  
}  


DataSource 接口定义了2个方法,都是获取数据库连接。我们在看下AbstractRoutingDataSource 如何实现了DataSource接口:

public Connection getConnection() throws SQLException {  
    return determineTargetDataSource().getConnection();  
}  
  
public Connection getConnection(String username, String password) throws SQLException {  
    return determineTargetDataSource().getConnection(username, password);  
}  


很显然就是调用自己的determineTargetDataSource()  方法获取到connection。determineTargetDataSource方法定义如下:

protected DataSource determineTargetDataSource() {  
        Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");  
        Object lookupKey = determineCurrentLookupKey();  
        DataSource dataSource = this.resolvedDataSources.get(lookupKey);  
        if (dataSource == null && (this.lenientFallback || lookupKey == null)) {  
            dataSource = this.resolvedDefaultDataSource;  
        }  
        if (dataSource == null) {  
            throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");  
        }  
        return dataSource;  
    }  


我们最关心的还是下面2句话:
  Object lookupKey = determineCurrentLookupKey();
    DataSource dataSource = this.resolvedDataSources.get(lookupKey);

    determineCurrentLookupKey方法返回lookupKey,resolvedDataSources方法就是根据lookupKey从Map中获得数据源。resolvedDataSources 和determineCurrentLookupKey定义如下:

  private Map<Object, DataSource> resolvedDataSources;
  protected abstract Object determineCurrentLookupKey()

  看到以上定义,我们是不是有点思路了,resolvedDataSources是Map类型,我们可以把MasterDataSource和SlaveDataSource存到Map中,如下:

    key        value
    master           MasterDataSource
    slave              SlaveDataSource

  我们在写一个类DynamicDataSource  继承AbstractRoutingDataSource,实现其determineCurrentLookupKey() 方法,该方法返回Map的key,master或slave。


  好了,说了这么多,有点烦了,下面我们看下怎么实现。

 上面已经提到了我们要使用的技术,我们先看下annotation的定义:

@Retention(RetentionPolicy.RUNTIME)  
@Target(ElementType.METHOD)  
public @interface DataSource {  
    String value();  
}  


我们还需要实现spring的抽象类AbstractRoutingDataSource,就是实现determineCurrentLookupKey方法:

public class DynamicDataSource extends AbstractRoutingDataSource {  
  
    @Override  
    protected Object determineCurrentLookupKey() {  
        // TODO Auto-generated method stub  
        return DynamicDataSourceHolder.getDataSouce();  
    }  
  
}  
  
  
public class DynamicDataSourceHolder {  
    public static final ThreadLocal<String> holder = new ThreadLocal<String>();  
  
    public static void putDataSource(String name) {  
        holder.set(name);  
    }  
  
    public static String getDataSouce() {  
        return holder.get();  
    }  
}  


从DynamicDataSource 的定义看出,他返回的是DynamicDataSourceHolder.getDataSouce()值,我们需要在程序运行时调用DynamicDataSourceHolder.putDataSource()方法,对其赋值。下面是我们实现的核心部分,也就是AOP部分,DataSourceAspect定义如下:

public class DataSourceAspect {  
  
    public void before(JoinPoint point)  
    {  
        Object target = point.getTarget();  
        String method = point.getSignature().getName();  
  
        Class<?>[] classz = target.getClass().getInterfaces();  
  
        Class<?>[] parameterTypes = ((MethodSignature) point.getSignature())  
                .getMethod().getParameterTypes();  
        try {  
            Method m = classz[0].getMethod(method, parameterTypes);  
            if (m != null && m.isAnnotationPresent(DataSource.class)) {  
                DataSource data = m  
                        .getAnnotation(DataSource.class);  
                DynamicDataSourceHolder.putDataSource(data.value());  
                System.out.println(data.value());  
            }  
              
        } catch (Exception e) {  
            // TODO: handle exception  
        }  
    }  
}  


转自:http://uule.iteye.com/blog/2126533

      http://www.cnblogs.com/davidwang456/p/4318303.html

      http://dsbjoe.iteye.com/blog/1176779
分享到:
评论

相关推荐

    spring+druid+AtomikosDataSource实现多数据源切换及分布式事务控制

    综上所述,"spring+druid+AtomikosDataSource"的组合为开发者提供了一套强大的工具,用于实现多数据源切换和分布式事务控制。在实际项目中,通过合理的配置和编码,可以构建出高效、健壮的分布式系统。在`mult-table...

    Spring(AbstractRoutingDataSource)实现动态数据源切换示例

    【Spring 动态数据源切换】使用 `AbstractRoutingDataSource` 的详细实现在处理多数据库环境时,Spring 提供了一个强大的工具 `AbstractRoutingDataSource`,它允许我们根据特定条件动态地切换数据源。本文将深入...

    Spring+SpringMvc+MybatisPlus+Aop(自定义注解)动态切换数据源

    - AOP切面的Java类,实现了方法执行前后的拦截和数据源切换。 - 数据源相关的Java配置类,用于配置Spring的DataSource和MybatisPlus。 - Mapper接口和对应的XML文件,定义数据库操作。 - 业务逻辑层的Java类,其中的...

    mybatis+spring实现动态切换数据源

    通过以上步骤,我们就实现了MyBatis与Spring配合下的动态数据源切换。这种机制有助于在多租户系统、读写分离或者高可用架构中灵活地管理数据库访问,提高了系统的可扩展性和灵活性。在实际应用中,还需要考虑数据源...

    根据用户动态切换数据源java代码 dynamicds

    在Java开发中,特别是在SpringBoot框架下,动态数据源是一个重要的功能,它允许应用程序根据不同的业务需求或用户权限切换到不同的数据库。动态数据源的实现能够极大地提高系统的灵活性和可扩展性,使得一个应用可以...

    SpringBoot整合Sharding-JDBC,实现从数据库加载sharding-jdbc数据源,实现多种数据库数据源切换,数据库方言动态切换

    这可以通过监听数据库表的变化,获取最新的数据源配置,然后通过Spring的`DataSourceProxy`或`AbstractRoutingDataSource`实现动态数据源切换。 3. **数据库方言动态切换** Sharding-JDBC支持多种数据库,如MySQL...

    spring boot动态切换多数据源

    - 可以编写单元测试或集成测试,模拟不同场景下的数据源切换,确保功能正确无误。 - 使用日志记录数据源切换的过程,以便于调试和监控。 8. **最佳实践** - 避免在业务代码中直接切换数据源,最好通过服务层的...

    Spring Boot整合Mybatis使用druid实现多数据源自动切换

    4. 配置数据源切换:在`@Configuration`注解的类中,使用`@Bean`注解创建一个`PrimaryDataSourceBean`和`SecondaryDataSourceBean`,返回DruidDataSource实例。同时,创建一个`DataSource`的`@Bean`,返回`...

    动态创建和切换数据源

    在日志中记录数据源切换的信息,便于追踪和调试。 8. **挑战与注意事项**:动态数据源虽然提供了灵活性,但也会增加系统的复杂性,可能导致性能开销。此外,正确处理数据源之间的隔离性和安全性,以及在切换时的...

    真正意义的spring动态切换数据源源码

    1. **Spring的AbstractRoutingDataSource**:这是Spring提供的核心类,用于实现动态数据源切换。这个抽象类维护了一个数据源路由决策表,可以根据特定的规则(如事务上下文、线程局部变量等)来决定使用哪个数据源。...

    springboot 1.5.9+mybatis动态指定数据源

    本文将深入探讨如何在Spring Boot 1.5.9版本中结合MyBatis实现动态指定数据源,并通过自定义注解来实现这一功能。 首先,我们需要理解动态数据源的概念。动态数据源是指在运行时可以动态切换或选择的数据源,这在多...

    多数据源切换

    多数据源切换的核心在于动态选择和切换数据源,这通常通过配置或编程方式实现。在Java中,我们可以利用Spring框架的强大功能来轻松实现这一目标。Spring提供了多种数据源切换的解决方案,如...

    spring 动态切换数据源

    以下将详细介绍如何实现Spring的动态数据源切换以及相关知识点。 1. **数据源配置** - `jdbc.properties`: 这个文件通常包含了数据库连接的相关配置,如URL、用户名、密码、驱动类名等。Spring通过`Properties`类...

    springboot连接池、动态配置多数据源连接池,特别适合大数据部门、数据中台服务的多数据源连接池.zip

    Spring Boot通过DataSourceProperties和AbstractRoutingDataSource等组件,可以实现动态数据源的配置。通过编程或配置文件的方式,我们可以设置数据源的优先级、权重以及自动切换规则。 接下来,我们关注如何在...

    详解利用Spring的AbstractRoutingDataSource解决多数据源的问题

    总结来说,通过使用Spring的`AbstractRoutingDataSource`,我们可以方便地实现多数据源的动态切换。关键步骤包括: 1. 配置多个实际数据源。 2. 创建自定义的`DynamicDataSource`类并实现`...

    mybatis-plus多数据源/动态数据源配置示例代码

    本示例代码将介绍如何在项目中配置和使用MyBatis-Plus实现多数据源和动态数据源切换。 首先,我们需要理解多数据源的概念。多数据源意味着系统中存在不止一个数据存储,每个数据源可能对应不同的数据库,如MySQL、...

    Mybatis+Spring+SpringMVC+quartz多数据源切换

    在多数据源切换的场景下,Mybatis可以配置多个数据源,根据业务需求动态选择执行SQL的数据库。 **Spring** 是一个全面的企业级应用开发框架,它为依赖注入(DI)、面向切面编程(AOP)以及事务管理等提供了强大的...

    Springcloud 多数库 多数据源整合,查询动态切换数据库

    创建一个自定义的数据源切换注解,比如`@SwitchDataSource`,并在需要切换数据源的方法上使用。通过AspectJ的切面处理,我们可以在方法执行前后动态改变ThreadLocal中的数据源引用。 3. **Spring Cloud Config ...

    spring 3.29+struts2.3.15.1+hibernate3 动态切换数据源

    此外,为了便于测试和调试,可以创建一个简单的Web界面,允许用户选择不同的数据源,通过Ajax请求触发数据源切换,观察实际效果。 总结起来,这个项目展示了如何在Spring 3.29、Struts2.3.15.1和Hibernate3的环境下...

    Spring+SpringMVC+Mybatis动态链接多数据源

    本项目“Spring+SpringMVC+Mybatis动态链接多数据源”旨在实现一个灵活、可扩展的数据源切换机制,以适应复杂的业务场景。 Spring框架作为Java领域中最广泛使用的轻量级框架,它提供了强大的依赖注入和AOP(面向切...

Global site tag (gtag.js) - Google Analytics