A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

spring和mybatis分库查询


    对于mysql,可以使用一主多从模式,主从之间实现同步,如果mybatis sql是select,自动选择从库查询,如果是insert, update, delete,自动选择主库操作。首先在spring定义数据源,主库数据源:

[Java] 纯文本查看 复制代码
<bean id="MasterDataSource" ........>		<property name="driverClassName" value="${master.jdbc.driverClassName}"/>		<property name="url" value="${master.jdbc.url}"/>		<property name="username" value="${master.jdbc.username}"/>		<property name="password" value="${master.jdbc.password}"/>	</bean>

主库增加事物:

[Java] 纯文本查看 复制代码
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">                     <property name="dataSource" ref="MasterDataSource"/>	 </bean>

从库数据源如下,只定义了一个:

[Java] 纯文本查看 复制代码
<bean id="Slave1DataSource" ......>		<property name="driverClassName" value="${slave1.jdbc.driverClassName}"/>		<property name="url" value="${slave1.jdbc.url}"/>		<property name="username" value="${slave1.jdbc.username}"/>		<property name="password" value="${slave1.jdbc.password}"/>	</bean>

其中type包含两种:一个是master,另一个slave定义好数据源好,利用spring做动态数据源:

[Java] 纯文本查看 复制代码
	<bean id="dataSource" class="net.xway.base.database.source.impl.DynamicDataSource" >
		<property name="dataSources">
			<list>
				<ref bean="MasterDataSource"/>
				<ref bean="Slave1DataSource"/>
			</list>
		</property>
		<property name="defaultTargetDataSource" ref="MasterDataSource" />
	</bean>

并增加对dao的拦截

[Java] 纯文本查看 复制代码
	<bean id="DAOMethodAdvice" class="net.xway.base.database.source.DAOMethodAdvice">
		<property name="dataSource" ref="dataSource" />
		<property name="factory" ref="SqlSessionFactory" />
	</bean>
 
	<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
		<property name="beanNames">
			<list>
				<value>*DAO</value>
		</list>
		</property>
		
		<property name="interceptorNames">
			<list>
				<value>DAOMethodAdvice</value>
			</list> 
		</property>
	</bean>

其中DAOMethodAdvice中的factory定义为:

[Java] 纯文本查看 复制代码
	<bean id="SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="configLocation"  value="classpath:sqlMapConfig.xml" />
		<property name="mapperLocations" value="classpath:/net/xway/**/mysql-*.xml" />
		<property name="dataSource" ref="dataSource" />
		<property name="plugins">
			<list>
				<ref bean="PagingInterceptor"/>
			</list>
		</property>
	</bean>

net.xway.base.database.source.impl.DynamicDataSource类中主要方法为determineCurrentLookupKey:

[Java] 纯文本查看 复制代码
	@Override
	protected Object determineCurrentLookupKey() {
		DAOMethodType type = local.get();
		if (type == null) {
			return null;
		}
		
		String key = null;
		
		if (type.getId() != null && type.getId().length() > 0) {
			key = type.getId();
		}
		else if (type.getType() != null && type.getType().length()>0) {
			key = master.equals(type.getType()) ? master : randomSlaveKey();
		}
		else if (type.getMethod() != null) {
			key = SqlCommandType.SELECT.equals(type.getMethod() ) ? randomSlaveKey() : master;
		}
		
		removeDAOMethodType();
		return key;
	}
 	private String randomSlaveKey() {
		switch (slaves.size()) {
			case 0: 
				return master;
			case 1: 
				return slaves.get(0);
			default:
				int c = r.nextInt(slaves.size());
				return slaves.get(c);
		}
 
	}

net.xway.base.database.source.DAOMethodAdvice用于拦截dao方法,拦截方法如下:

[Java] 纯文本查看 复制代码
	@Override
	public void before(Method method, Object[] params, Object object) throws Throwable {
		String type = null;
		String id = null;
		
		Annotation[] as = method.getAnnotations();
		for (Annotation a : as) {
			if (a instanceof DataSourceTarget) {
				type = ((DataSourceTarget) a).type();
				id = ((DataSourceTarget) a).id();
				break ;
			}
		}
		
		DAOMethodType dsType = null;
		
		if (type != null || id != null) {
			dsType = new DAOMethodType(id, type, null);
		}
		else {
			MappedStatement statement = factory.getConfiguration().getMappedStatement(method.getName());
			dsType = new DAOMethodType(null, null, statement.getSqlCommandType());
		}
		
		if (dsType != null) {
			dataSource.setDAOMethodType(dsType);
		}
		
	}

至此完成了拦截操作,并可为dao方法利用注释指定数据源:

[Java] 纯文本查看 复制代码
@Retention(RetentionPolicy.RUNTIME)
@Target( ElementType.METHOD)
public @interface DataSourceTarget {
 
	String id() default "";
	
	String type() default "";
}

DAOMethodType定义如下:

[Java] 纯文本查看 复制代码
public class DAOMethodType {
	
 
	private final String id;
	private final String type;
	private final SqlCommandType method;
 get................... set ...........}




1 个回复

倒序浏览
奈斯
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马