`

利用AbstractRoutingDataSource实现动态数据源切换 (一、Spring+Hibernate)

 
阅读更多

     在Spring 2.0.1中引入了AbstractRoutingDataSource, 该类充当了DataSource的路由中介, 能有在运行时, 根据某种key值来动态切换到真正的DataSource上。

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

 
Spring对于多数据源,以数据库表为参照,大体上可以分成两大类情况:
一是,表级上的跨数据库。即,对于不同的数据库却有相同的表(表名和表结构完全相同)。
二是,非表级上的跨数据库。即,多个数据源不存在相同的表。
Spring2.x的版本中采用Proxy模式,就是我们在方案中实现一个虚拟的数据源,并且用它来封装数据源选择逻辑,这样就可以有效地将数据源选择逻辑从Client中分离出来。Client提供选择所需的上下文(因为这是Client所知道的),由虚拟的DataSource根据Client提供的上下文来实现数据源的选择。
具体的实现就是,虚拟的DataSource仅需继承AbstractRoutingDataSource实现determineCurrentLookupKey()在其中封装数据源的选择逻辑。

 

一、原理

首先看下AbstractRoutingDataSource类结构,继承了AbstractDataSource


public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean

 

既然是AbstractDataSource,当然就是javax.sql.DataSource的子类,于是我们自然地回去看它的getConnection方法:


public Connection getConnection() throws SQLException {
		return determineTargetDataSource().getConnection();
	}

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

 

 原来关键就在determineTargetDataSource()里:


/**
	 * Retrieve the current target DataSource. Determines the
	 * {@link #determineCurrentLookupKey() current lookup key}, performs
	 * a lookup in the {@link #setTargetDataSources targetDataSources} map,
	 * falls back to the specified
	 * {@link #setDefaultTargetDataSource default target DataSource} if necessary.
	 * @see #determineCurrentLookupKey()
	 */
	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;
	}

 这里用到了我们需要进行实现的抽象方法determineCurrentLookupKey(),该方法返回需要使用的DataSource的key值,然后根据这个key从resolvedDataSources这个map里取出对应的DataSource,如果找不到,则用默认的resolvedDefaultDataSource。


public void afterPropertiesSet() {
		if (this.targetDataSources == null) {
			throw new IllegalArgumentException("Property 'targetDataSources' is required");
		}
		this.resolvedDataSources = new HashMap<Object, DataSource>(this.targetDataSources.size());
		for (Map.Entry entry : this.targetDataSources.entrySet()) {
			Object lookupKey = resolveSpecifiedLookupKey(entry.getKey());
			DataSource dataSource = resolveSpecifiedDataSource(entry.getValue());
			this.resolvedDataSources.put(lookupKey, dataSource);
		}
		if (this.defaultTargetDataSource != null) {
			this.resolvedDefaultDataSource = resolveSpecifiedDataSource(this.defaultTargetDataSource);
		}
	}

 

二、Spring配置多数据源的方式和具体使用过程


1、数据源的名称常量类

    public enum DynamicDataSourceGlobal {

	ORCL, 
	ISC
}
 

2、建立一个获得和设置上下文环境的类,主要负责改变上下文数据源的名称

    public class DynamicDataSourceHolder {

	// 线程本地环境
	private static final ThreadLocal<DynamicDataSourceGlobal> contextHolder = new ThreadLocal<DynamicDataSourceGlobal>();

	// 设置数据源类型
	public static void setDataSourceType(DynamicDataSourceGlobal dataSourceType) {
		Assert.notNull(dataSourceType, "DataSourceType cannot be null");
		contextHolder.set(dataSourceType);
	}

	// 获取数据源类型
	public static DynamicDataSourceGlobal getDataSourceType() {
		return (DynamicDataSourceGlobal) contextHolder.get();
	}

	// 清除数据源类型
	public static void clearDataSourceType() {
		contextHolder.remove();
	}
}
 

3、建立动态数据源类,注意,这个类必须继承AbstractRoutingDataSource,且实现方法 determineCurrentLookupKey,该方法返回一个Object,一般是返回字符串

    public class DynamicDataSource extends AbstractRoutingDataSource {

	@Override
	protected Object determineCurrentLookupKey() {
		return DynamicDataSourceHolder.getDataSourceType();
	}

}

4、编写spring的配置文件配置多个数据源

     <!-- 数据源相同的内容 -->

	<bean id="parentDataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClass"
			value="oracle.jdbc.pool.OracleConnectionPoolDataSource" />
		<property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl" />
		<property name="user" value="isc_v10" />
		<property name="password" value="isc" />
	</bean>

	<!-- 数据源 -->
	<bean id="orclDataSource" parent="parentDataSource">
		<property name="user" value="orcl" />
		<property name="password" value="orcl" />
	</bean>

	<!-- 数据源 -->
	<bean id="iscDataSource" parent="parentDataSource">
		<property name="user" value="isc_v10" />
		<property name="password" value="isc" />
	</bean>

	<!-- 编写spring 配置文件的配置多数源映射关系 -->
	<bean id="dataSource" class="com.wy.config.DynamicDataSource">
		<property name="targetDataSources">
			<map key-type="java.lang.String">
				<entry key="ORCL" value-ref="orclDataSource"></entry>
				<entry key="ISC" value-ref="iscDataSource"></entry>
			</map>
		</property>
		<property name="defaultTargetDataSource" ref="orclDataSource">
		</property>
	</bean>

	<bean id="sessionFactory"
		class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
</bean>

 

5、使用

   @Test

	public void testSave() {
		// hibernate创建实体
		DynamicDataSourceHolder.setDataSourceType(DynamicDataSourceGlobal.ORCL);// 设置为另一个数据源
		com.wy.domain.Test user = new com.wy.domain.Test();

		user.setName("WY");
		user.setAddress("BJ");

		testDao.save(user);// 使用dao保存实体

		DynamicDataSourceHolder.setDataSourceType(DynamicDataSourceGlobal.ISC);// 设置为另一个数据源

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

	}
 

 

 

 

 

 






 

分享到:
评论
3 楼 AKka 2014-07-10  
温柔的羊 写道
washingtin 写道
切换不了库啊,一直是一个。

这个只是实现了同一个数据库,不同数据库实例的切换

如果你的方法在事务监控中,这种方式是不能切换数据源的。
2 楼 温柔的羊 2013-10-23  
washingtin 写道
切换不了库啊,一直是一个。

这个只是实现了同一个数据库,不同数据库实例的切换
1 楼 washingtin 2013-10-18  
切换不了库啊,一直是一个。

相关推荐

    Spring+Hibernate多数据源

    Spring提供了AbstractRoutingDataSource类,允许我们根据某种规则(如事务、请求上下文等)动态切换数据源。我们需要扩展这个类,并实现determineCurrentLookupKey方法来决定当前应该使用哪个数据源。 接着,描述中...

    spring+hibernate和spring+myBatis实现连接多个数据库,同时操作的项目

    "spring+hibernate和spring+myBatis实现连接多个数据库,同时操作的项目"是针对这种需求的一个解决方案,旨在提供一种灵活且动态的数据源切换机制。 首先,Spring框架作为Java领域中最受欢迎的应用框架之一,其强大...

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

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

    Spring+Hibernate下的数据库连接动态切换

    在Spring配置文件中,我们可以通过配置`AbstractRoutingDataSource`类来实现动态数据源切换。这个类可以根据一定的规则动态选择数据源。例如: ```xml &lt;bean id="dataSource" class="org.springframework.jdbc....

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

    本项目“spring 3.29+struts2.3.15.1+hibernate3 动态切换数据源”正是针对这一需求,通过整合Spring、Struts2和Hibernate3这三大经典Java EE框架,实现了数据源的灵活配置和动态切换。 首先,Spring作为Java应用中...

    一套Spring+Hibernate的多个数据库切换的源码

    本项目"一套Spring+Hibernate的多个数据库切换的源码"提供了一个实现这一功能的示例,它利用了Spring框架的强大功能和Hibernate的持久化能力,实现了灵活的数据源切换。 首先,Spring框架是Java开发中最常用的应用...

    spring3+hibernate4+maven+junit 多库多数据源实现

    DataSourceTransactionManager用于管理数据库事务,而AbstractRoutingDataSource则允许动态选择数据源,从而实现切换到不同的数据库。 其次,Hibernate 4是一个流行的ORM(对象关系映射)工具,它简化了Java应用与...

    spring boot 2多数据源,里面有hibernate和mybatis的多数据源代码

    这些代码可以直接集成到你的项目中,只需要调整为匹配你的数据库配置,就可以实现Spring Boot 2下的多数据源支持,同时利用Hibernate和MyBatis的优势。 总之,多数据源的实现是Spring Boot 2应用中的高级特性,它...

    spring集合hibernate多数据切换

    本知识点主要探讨如何在Spring中集成Hibernate来实现多数据源的动态切换功能,这对于需要处理多种数据源的应用来说至关重要。 首先,我们需要理解什么是多数据源。多数据源意味着一个应用程序可以连接并操作多个...

    SpringBoot+hibernate+mysql+sqlserver双数据源

    2. 配置多数据源路由:SpringBoot提供了AbstractRoutingDataSource,可以根据业务逻辑动态切换数据源。例如,可以通过事务的隔离级别、方法的注解等方式决定使用哪个数据源。 3. 实现DAO层:在Hibernate的实体类和...

    SSH动态切换数据源

    SSH动态切换数据源是一种在Java Web开发中处理多数据库连接切换的技术,主要应用于Spring、Struts和Hibernate(SSH)这三大框架集成的项目。SSH框架是企业级应用开发的常用组合,提供了强大的业务逻辑处理和数据持久...

    springboot实现多数据源

    总结来说,Spring Boot实现多数据源的关键在于正确配置多个数据源,创建相应的事务管理器,并在业务代码中灵活地切换和使用这些数据源。通过这种方式,我们可以充分利用多个数据库的资源,提升系统的扩展性和可靠性...

    sping多数据源动态切换

    Spring框架的多数据源动态切换是一项关键功能,尤其在处理大型应用中,它允许系统根据需求灵活地在多个数据库之间切换,以实现更好的负载均衡和数据管理。在本文中,我们将深入探讨如何在Spring中配置和使用动态数据...

    多数据源配置demo

    5. **配置数据源路由**:使用Spring的AbstractRoutingDataSource实现动态数据源选择。根据业务逻辑,它可以在运行时决定使用哪个数据源。 ```java public class DynamicDataSource extends ...

    Spring 数据源不同配置

    Spring提供了一个名为`BasicDataSource`的类,它实现了`javax.sql.DataSource`接口,是最基础的数据源配置。在没有特殊需求的情况下,可以使用`BasicDataSource`。配置时,需要设置数据库URL、用户名、密码等属性。...

    spring2跨数据源访问

    也可以创建一个路由数据源(如`AbstractRoutingDataSource`),它可以根据特定的规则(如事务上下文、方法参数等)动态决定使用哪个实际的数据源。 4. **JdbcTemplate与NamedParameterJdbcTemplate**:Spring提供的...

    Spring多数据源解决方案

    Spring多数据源解决方案是针对大型应用中数据分片和分布式数据库管理的需求而设计的一种策略。在这样的场景下,为了提高系统的可扩展性和性能,数据通常会被分散到多个数据库实例上。这种架构如图1所示,每个数据库...

    通过识别方法注解,自动切换主备数据源DynamicDataSource

    `DynamicDataSource.java`文件可能是自定义的数据源切换器,它继承自Spring的`AbstractRoutingDataSource`,这个类允许我们在运行时根据某些条件(比如方法注解)动态选择数据源。你需要在这个类中实现`...

    spring如何实现注入多个数据源[归类].pdf

    在Spring框架中实现多个数据源的注入,主要是为了解决项目中需要连接并动态切换不同数据库的需求。这种需求通常出现在多租户系统或者需要对不同客户提供差异化服务的场景。以下是一种基于Decorator设计模式的解决...

    java多数据源

    总之,Java中的多数据源切换是一个复杂但重要的功能,它涉及到SpringMVC、MyBatis或Hibernate等技术的深度整合。通过合理配置和智能路由,我们可以实现数据库的动态切换,满足不同场景下的数据访问需求。在具体实现...

Global site tag (gtag.js) - Google Analytics