spring轻松实现Mysql数据源动态切换

实现功能

在dao层的不同接口可以调用不同的数据源,
更进一步,相同接口中的不同方法也可以调用不同的数据源

设计思想

要实现数据源动态切换,
首先要借助spring的数据源路由器AbstractRoutingDataSource的数据源路由功能。
看它的源码有这样一个方法

	/**
	 * Determine the current lookup key. This will typically be
	 * implemented to check a thread-bound transaction context.
	 * <p>Allows for arbitrary keys. The returned key needs
	 * to match the stored lookup key type, as resolved by the
	 * {@link #resolveSpecifiedLookupKey} method.
	 */
	protected abstract Object determineCurrentLookupKey();

其中的注释我们关心的就是前两句:
第一,这个方法是用来查找key的。
第二,用这个方法查到的事务上下文(可以理解为数据库连接)要是与线程绑定的。
也就是说我们继承AbstractRoutingDataSource,
重写determineCurrentLookupKey方法,
在我们的实现中返回一个与当前线程绑定的数据库key就可以了。(而这个key就是在targetDataSources属性中的key,也是配置下面配置文件中< map >中的key)
现在我们知道了如何设置数据源,那该在什么时候去设置呢?
因为要在调用不同的dao方法时使用不同的数据源,那就要在这些方法执行之前对数据源进行设置。
这里自然就想到了切面,把动态设置key的逻辑写在before切面中。
最后,要把方法和对应数据库的key做对应,使其可以在切面中进行配置。
参考spring的种种实现,想要把方法和配置进行关联时往往都会用到注解,所以我们可以自定义一个注解用来在dao方法上面配置数据源的key,然后在before切面中就可以使用反射读取到配置值了。

一 java代码

1.自定义注解实现具体方法和数据源别名对应。

@Retention(RetentionPolicy.RUNTIME)  
@Target(ElementType.METHOD)  
public @interface  DataSource {

	String value();  
}

2.自定义Constant保存当前线程的数据源的别名。

public class DataSourceConstant {
	public static final ThreadLocal<String> dataSourceKey = new ThreadLocal<String>();
}

2.使用Aspect在方法执行之前动态设置数据源别名。

@Component
@Aspect
public class DataSourceAspect {
	//扫描dao类所在包
	@Before("execution(* com.fxp.dao..*.*(..))")
	public void before(JoinPoint point) throws Exception {
		
		Object target = point.getTarget();
		String method = point.getSignature().getName();

		Class<?>[] classz = target.getClass().getInterfaces();

		Class<?>[] parameterTypes = ((MethodSignature) point.getSignature())
				.getMethod().getParameterTypes();
			Method m = classz[0].getMethod(method, parameterTypes);
			if (m != null && m.isAnnotationPresent(DataSource.class)) {
				DataSource data = m.getAnnotation(DataSource.class);
								DataSourceConstant.dataSourceKey.set(data.value());
			}
		}
}

3.继承AbstractRoutingDataSource重写determineCurrentLookupKey方法,取DataSourceConstant中保存的数据源别名。

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

public class DynamicRoutingDataSource extends AbstractRoutingDataSource{
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceConstant.dataSourceKey.get();
    }
	
}

二 xml配置

1.切面注解支持

    <aop:aspectj-autoproxy></aop:aspectj-autoproxy> 

2.配置数据源路由

	<bean id="multipleDataSource" class="com.fxp.dynamicdatasource.DynamicRoutingDataSource">
		<!-- 默认数据源 -->
        <property name="defaultTargetDataSource" ref="数据源1"/>
        <!-- 数据源路由 -->
        <property name="targetDataSources">
            <map>
                <entry key="datasource1" value-ref="数据源1"/>
                <entry key="datasource2" value-ref="数据源2"/>
            </map>
        </property>
    </bean>

3.数据源及其他配置略。

三 使用

mybatis示例。

public interface UserMapper {
	@DataSource("datasource1")
	List<User> selectAll();
	@DataSource("datasource2")
	void insertOne(User user);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值