spring切换多数据源


应用场景:在一个项目需要用到两个或两个以上的数据库时,要进行切换数据库,来操作相应的表。

框架:用的是spring 的org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource 这个类 实现determineCurrentLookupKey() 方法来切换数据源

1. 配置文件,配置多个数据源。

    <bean id="dataSource1" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="driverClassName" value="${datasource.driverClassName}" />
        <property name="url" value="${datasource.url}" />
        <property name="username" value="${datasource.username}" />
        <property name="password" value="${datasource.password}" />
        <property name="filters" value="stat" />
    </bean>
    <bean id="dataSource2" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="driverClassName" value="${datasource2.driverClassName}" />
        <property name="url" value="${datasource2.url}" />
        <property name="username" value="${datasource2.username}" />
        <property name="password" value="${datasource2.password}" />
        <property name="maxWait" value="${datasource2.maxWait}"/>
        <property name="filters" value="stat" />
    </bean>
    <bean id="multipleDataSource" class="com.ds.basic.util.MultipleDataSource">
        <property name="defaultTargetDataSource" ref="dataSource1"/>
        <property name="targetDataSources">
            <map>
                <entry key="dataSource1" value-ref="dataSource1"/>
                <entry key="dataSource2" value-ref="dataSource2"/>
            </map>
        </property>
    </bean>

多了个multipleDataSource 来把多个数据源组合在一起,其他配置记得ref="multipleDataSource" 这个切换到这个来。

还有事务管理器,

<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" order="2"/>

order = '2',增加个这个,下面会用到。

添加aop 依赖包,

    <!-- 配置自动扫描的包 -->
    <context:component-scan base-package="com.ds.basic.aop"></context:component-scan>
    <!-- 自动为切面方法中匹配的方法所在的类生成代理对象。 -->
    <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>

截止,配置文件完成。

com.ds.basic.util.MultipleDataSource ,切换数据源核心,就是要实现determineCurrentLookupKey ,来切换数据源

public class MultipleDataSource extends AbstractRoutingDataSource {
    
    private static final ThreadLocal<String> dataSourceKey = new InheritableThreadLocal<String>();

    public static void setDataSourceKey(String dataSource) {
        dataSourceKey.set(dataSource);
    }

    @Override
    protected Object determineCurrentLookupKey() {
        return dataSourceKey.get();
    }
}
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSource {
    /*
            自定义个注解来做个标识,好切换数据源
        */
    
    String value();
    
}
    
/**
* order(1) 是为了要在事务之前就切换数据源,不然应该会有问题,大家可以试一试
*/
@Order(1) @Component @Aspect public class DataSourceAspect { /** * 拦截,获取由@DataSource指定的数据源标识,设置到线程存储中以便切换数据源 * * @param point * @throws Exception * @annotation使用这个表达式来切,却一直没起作用,有大佬知道请评论告知。 */ // @Before("@annotation(com.ds.basic.util.DataSource)") @Before(value="execution(* com.shop.*.*.service.*.*(..))") public void intercept(JoinPoint point) throws Exception { // 下面的注释是在生产环境下切到第二个数据源时总是不能切回来,加个这个就好了,很奇怪,其实没必要添加这个。 // MultipleDataSource.setDataSourceKey("dataSource1"); Class<?> target = point.getTarget().getClass(); MethodSignature signature = (MethodSignature) point.getSignature(); // 默认使用目标类型的注解,如果没有则使用其实现接口的注解 for (Class<?> clazz : target.getInterfaces()) { resolveDataSource(clazz, signature.getMethod()); } resolveDataSource(target, signature.getMethod()); } /** * 提取目标对象方法注解和类型注解中的数据源标识 * 这个方法是在一个博客上复制下来的,原来的网址不记得在哪里了 * @param clazz * @param method */ private void resolveDataSource(Class<?> clazz, Method method) { try { Class<?>[] types = method.getParameterTypes(); // 默认使用类型注解 if (clazz.isAnnotationPresent(DataSource.class)) { DataSource source = clazz.getAnnotation(DataSource.class); MultipleDataSource.setDataSourceKey(source.value()); } // 方法注解可以覆盖类型注解 Method m = clazz.getMethod(method.getName(), types); if (m != null && m.isAnnotationPresent(DataSource.class)) { DataSource source = m.getAnnotation(DataSource.class); MultipleDataSource.setDataSourceKey(source.value()); } } catch (Exception e) { // 可以不做这个异常捕捉。 MultipleDataSource.setDataSourceKey("dataSource1"); } } }

配置完成,大家可以试下,欢迎评论。 

 使用 @DataSource("dataSource2") 在service 上加上这个就能切换了,没有加,默认是第一个的,

看了网上很多方法 比如用做两个事务管理器来指定不同的数据源,这样在切换事务管理器时就切换了数据源,但是我的配置只是连上了,却无法切换 一直用的还是第一个数据源。


					


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM