Spring多データソースの配置


大きなアプリケーションでは、データベースの水平伸縮性を向上させるために、複数のデータベース例を管理するために、多データソースを配置する必要がある.Springフレームが広く使われている今日は、Springの特性配置の動的多データを簡単に活用できます.
1.まずc 3 p 0.compboPooled DataSourceに基づくデータソースAを配置する.
daoContect.xml

	<bean id="dataSourceA" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
		<property name="driverClass" value="${jdbc.driver}"></property>
		<property name="jdbcUrl" value="${jdbc.url.a}?zeroDateTimeBehavior=convertToNull&amp;characterEncoding=utf8"></property>
		<property name="user" value="${jdbc.user}"></property>
		<property name="password" value="${jdbc.password}"></property>
		<property name="minPoolSize" value="${jdbc.miniPoolSize}" />
		<property name="maxPoolSize" value="${jdbc.maxPoolSize}"/>  
		<property name="initialPoolSize" value="${jdbc.initialPoolSize}"/>
		<property name="maxIdleTime" value="${jdbc.maxIdleTime}"/>
		<property name="acquireIncrement" value="${jdbc.acquireIncrement}"/>
		<property name="acquireRetryAttempts" value="${jdbc.acquireRetryAttempts}"/>
		<property name="acquireRetryDelay" value="${jdbc.acquireRetryDelay}"/>
		<property name="idleConnectionTestPeriod" value="${jdbc.idleConnectionTestPeriod}"/>
		<property name="checkoutTimeout" value="${jdbc.checkoutTimeout}"/>
	</bean>
2.次にデータソースBを追加します.
daoContect.xml

	<bean id="dataSourceB" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
		<property name="driverClass" value="${jdbc.driver}"></property>
		<property name="jdbcUrl" value="${jdbc.url.b}?zeroDateTimeBehavior=convertToNull&amp;characterEncoding=utf8"></property>
		<property name="user" value="${jdbc.user}"></property>
		<property name="password" value="${jdbc.password}"></property>
		<property name="minPoolSize" value="${jdbc.miniPoolSize}" />
		<property name="maxPoolSize" value="${jdbc.maxPoolSize}"/>  
		<property name="initialPoolSize" value="${jdbc.initialPoolSize}"/>
		<property name="maxIdleTime" value="${jdbc.maxIdleTime}"/>
		<property name="acquireIncrement" value="${jdbc.acquireIncrement}"/>
		<property name="acquireRetryAttempts" value="${jdbc.acquireRetryAttempts}"/>
		<property name="acquireRetryDelay" value="${jdbc.acquireRetryDelay}"/>
		<property name="idleConnectionTestPeriod" value="${jdbc.idleConnectionTestPeriod}"/>
		<property name="checkoutTimeout" value="${jdbc.checkoutTimeout}"/>
	</bean>
3.次にSpringから提供されるAbstractRoutingDataSourceを拡張し、Overrideの中のdetermine Currennt Look ukey方法でデータソースのrouteを実現する.

package datasource;

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

public class DynamicDataSource extends AbstractRoutingDataSource{

	@Override
	protected Object determineCurrentLookupKey() {
		return CustomerContextHolder.getCustomerType();
	}
}
その中のCustoomerContect Holderは開発者自身が実現したThreadLocalタイプのConttext Holderを封入したものです.

package datasource;

public class CustomerContextHolder {

	public static final String DATA_SOURCE_A = "dataSourceA";
	
	public static final String DATA_SOURCE_B = "dataSourceB";
	
	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();
	}
}
次は私達の上のdaoContect.xmlでこのDynamicData Source Beanを入れて、ターゲットData SourcesのMapマッピングを配置します.

	<bean id="dynamicDataSource" class="datasource.DynamicDataSource" >
     <!--   key-value          -->
		<property name="targetDataSources">
			<map key-type="java.lang.String">
				<entry value-ref="dataSourceA" key="dataSourceA"></entry>
				<entry value-ref="dataSourceB" key="dataSourceB"></entry>
			</map>
		</property>
		<property name="defaultTargetDataSource" ref="dataSourceA" >
		</property>
	</bean> 
4.どうやってこのダイナミックなマルチソースを使うのですか?実はとても簡単です.私達のDynamicDataSourceはAbstractRoutingDataSourceと継承しています.一方、AbstractRoutingDataSourceはorg.springframe ork.jdbc.datasource.AbstractDatasourceと同じように、明らかにAbstractDataSourceと同じように使いやすいです.ハイベルナーを例に挙げます.

	<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
     <!--          dataSource     -->
		<property name="dataSource" ref="dynamicDataSource" />
		<property name="configLocations" value="classpath:hibernate.cfg.xml" />
		<property name="hibernateProperties">
			<props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>	
		</property>
	</bean>
私たちが使っているのはまだsession Factoryです.事務管理の配置も以前と同じです.

	<tx:annotation-driven transaction-manager="transactionManager"/>
	
	<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
		<property name="sessionFactory" ref="sessionFactory" />
	</bean>
DynamicDataSource Beanも容器の中にあります.残りはプログラムの中でどうやってコントロールしますか?欲しいデータソースを選んだらどうすればいいですか?

		//              dataSourceB.
CustomerContextHolder.setCustomerType(CustomerContextHolder.DATA_SOURCE_B);
またはAOPを使って実現する

package datasource;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class DynamicDataSourceAspect {
	@Pointcut("execution (public service.impl..*.*(..))")
	public void serviceExecution(){}
	
	@Before("serviceExecution()")
	public void setDynamicDataSource(JoinPoint jp) {
		for(Object o : jp.getArgs()) {
			//        ,       CustomerContextHolder.setCustomerType()  DataSource
		}
	}
}
5.まとめ:AbstractRoutingDataSourceを使って、多くのデータソースを実現することができます.これからもっと多くのデータソースを拡張する時もとても簡単です.データソースを追加して、DynamicData Source BenのターゲットDataSources配置を修正すればいいです.あるデータソースの選択については、@AsppectでServiceの入り口にカットめん@Pointcutを追加し、@BeforeでJoinPointのクラス容が特定のデータソースを選択すると判断できます.
実際の応用を究めて確かめる.以前は多くの応用が展開されていました.writeDataSourceとreadDataSourceとslaaveDataBaseの実現が、現在の大部分の応用は構造体にあまり適していません.ますますユーザとの相互性が重視され、データベース間の同期がますます複雑になり、メンテナンスが難しくなりました.もちろんこのような開発には、業務分野を分析する時間が必要です.どのような配置のデータ源を選ぶかは、業務と密接な関係があります.