读写分离一

随着系统用户越来越庞大,对应的数据库也将越来越庞大。对应就要求我们的技术对性能越来越高。今天我们一起探讨下读写分离的实现步骤

步骤一:

读写分离之多数据源

思路:我们把项目写入的操作保存在主库。然后使用mha对主从数据库进行实时同步。(mha后期讨论)

目标:多数据源的实现

spring的核心配置:

	<!-- 开启注解事务支持 -->	
	<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		 <property name="dataSource" ref="dataSourcejdbc"/>
	</bean>	
	<!--定义 sqlSessionTemplate -->
	<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
		<constructor-arg index="0">
			<bean class="org.mybatis.spring.SqlSessionFactoryBean">
				<property name="dataSource" ref="dataSourcejdbc"></property>
				<property name="configLocation" value="classpath:/mybatis-config.xml"></property>
			</bean>
		</constructor-arg>
		<constructor-arg index="1" value="SIMPLE" />
		<constructor-arg index="2">
			<null />
		</constructor-arg>
	</bean> 
	
	<bean id="dataSourcejdbc" class="com.ffzx.commerce.framework.dao.DynamicRoutingDataSource">
		<property name="defaultTargetDataSource">
			<bean parent="abstractDataSource" p:url="${jdbc.url.slave}" />
		</property>
		<property name="targetDataSources">
			<map key-type="java.lang.String" value-type="javax.sql.DataSource">
				<entry key="#{T(com.ffzx.commerce.framework.dao.DynamicRoutingDataSource).MASTER_DATA_SOURCE}">
					<bean parent="abstractDataSource" p:url="${jdbc.url.master}" />
				</entry>
			</map>
		</property>
	</bean>


动态数据源的切换类:

package com.ffzx.commerce.framework.dao;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.NamedThreadLocal;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.transaction.interceptor.TransactionInterceptor;
import org.springframework.transaction.support.TransactionSynchronizationManager;

/**
 * 
 * @author cmm
 * 
 */
public class DynamicRoutingDataSource extends AbstractRoutingDataSource implements BeanPostProcessor {

	private static final Logger LOGGER = LoggerFactory.getLogger(DynamicRoutingDataSource.class);

	public static final String MASTER_DATA_SOURCE = "MASTER";

	public static final String SLAVE_DATA_SOURCE = "SLAVE";

	private static final ThreadLocal<Object> currentLookupKey = new NamedThreadLocal<Object>("Current lookup key");

	@Override
	protected Object determineCurrentLookupKey() {
		return DynamicRoutingDataSource.currentLookupKey.get();
	}

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		if (TransactionInterceptor.class.isInstance(bean)) {
			ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
			proxyFactoryBean.setInterfaces(MethodInterceptor.class);
			proxyFactoryBean.setTarget(bean);
			proxyFactoryBean.addAdvice(new TransactionInterceptorAdvice());
			proxyFactoryBean.setProxyTargetClass(true);
			return proxyFactoryBean.getObject();
		}
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	/**
	 * 事务数据源决策者
	 * 
	 * @author ching
	 * 
	 */
	public class TransactionInterceptorAdvice implements MethodInterceptor {

		@Override
		public Object invoke(MethodInvocation invocation) throws Throwable {
			try {
				if (!TransactionSynchronizationManager.isSynchronizationActive()) {
					DynamicRoutingDataSource.currentLookupKey.set(MASTER_DATA_SOURCE);
					if (LOGGER.isDebugEnabled()) {
						LOGGER.debug("Current lookup key is '{}'", MASTER_DATA_SOURCE);
					}
				}
				return invocation.proceed();
			} finally {
				DynamicRoutingDataSource.currentLookupKey.remove();
			}
		}
	}
	
	/** 
     *  
     * 设置本线程的dbtype 
     *  
     * @param str 
     */  
    public static void setDbMaster() {  
    	DynamicRoutingDataSource.currentLookupKey.set(MASTER_DATA_SOURCE); 
    }  
  
    /** 
     * clearDBType 
     *  
     * @Title: clearDBType 
     * @Description: 清理连接类型 
     */  
    public static void clearDBType() {  
    	DynamicRoutingDataSource.currentLookupKey.remove();
    }
}
相关文章
相关标签/搜索