美文网首页
spring3.0 多数据源的实现(跨数据库)

spring3.0 多数据源的实现(跨数据库)

作者: setone | 来源:发表于2019-08-26 10:37 被阅读0次

    先上xml配置 ps:实际上你可以选择java注解的方式

        <bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
              init-method="init" destroy-method="close">
            <property name="driverClassName" value="${jdbc.driverClassName}" />
            <property name="url" value="${jdbc.url}" />
            <property name="username" value="${jdbc.username}" />
            <property name="password" value="${jdbc.password}" />
         
        </bean>
    
        <bean name="dataSource2" class="com.alibaba.druid.pool.DruidDataSource"
              init-method="init" destroy-method="close">
            <property name="driverClassName" value="com.mysql.jdbc.Driver" />
            <property name="url" value="jdbc:mysql://127.0.0.1:39000/apptest?useUnicode=true" />
            <property name="username" value="root" />
            <property name="password" value="root" />
        </bean>
    
    <!-- 动态数据源配置,这个class要实现 -->
        <bean id="dynamicDataSource" 
                      class="com.data.util.jdbcutil.DynamicDataSource">
            <property name="targetDataSources">
                <map key-type="java.lang.String">
                    <!-- 指定lookupKey和与之对应的数据源,切换时使用的为key -->
                    <entry key="dataSource1" value-ref="dataSource"></entry>
                    <entry key="dataSource2" value-ref="dataSource2"></entry>
                </map>
            </property>
            <!-- 这里可以指定默认的数据源 -->
            <property name="defaultTargetDataSource" ref="dataSource" />
        </bean>
    
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="dynamicDataSource" />
            <!-- 自动扫描mapping.xml文件 -->
            <property name="mapperLocations" value="classpath:com/*/mapping/**/*.xml">
            </property>
            <property name="configLocation" value="classpath:mybatis-config.xml">
            </property>
    </bean>
        <bean id="dataSourceAspect" class="com.data.util.jdbcutil.DataSourceAspect" />
        <aop:config>
            <aop:aspect ref="dataSourceAspect">
    <!--            拦截所有service方法,切面插入拦截的方法,获取注解-->
                <aop:pointcut id="dataSourcePointcut" expression="@annotation(com.data.util.jdbcutil.DataSource)" />
                <aop:around pointcut-ref="dataSourcePointcut" method="intercept" />
            </aop:aspect>
        </aop:config>
    
    image.png

    如图所示四个类实现了切换数据源

    DataSource ---注解,实现标记功能
    DataSourceAspect ---实现切换数据源功能
    DynamicDataSource --- 实现AbstractRoutingDataSource的模板方法
    DynamicDataSourceHolder --- 使用线程储存数据源的key
    
    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface DataSource {
        String value();
    }
    
    public class DataSourceAspect {
        /**
         * 拦截目标方法,获取由@DataSource指定的数据源标识,设置到线程存储中以便切换数据源
         *
         * @param point
         * @throws Exception
         */
        public Object intercept(ProceedingJoinPoint point)  {
            try{
                Class<?> target = point.getTarget().getClass();
                MethodSignature signature = (MethodSignature) point.getSignature();
                // 默认使用目标类型的注解,如果没有则使用其实现接口的注解
                for (Class<?> clazz : target.getInterfaces()) {
                    resolveDataSource(clazz, signature.getMethod());
                }
                resolveDataSource(target, signature.getMethod());
                return point.proceed();
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            } finally {
                DynamicDataSourceHolder.clearDataSource();
            }
            return null;
        }
    
        /**
         * 提取目标对象方法注解和类型注解中的数据源标识
         *
         * @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);
                    DynamicDataSourceHolder.setDataSource(source.value());
                }
                // 方法注解可以覆盖类型注解
                Method m = clazz.getMethod(method.getName(), types);
                if (m != null && m.isAnnotationPresent(DataSource.class)) {
                    DataSource source = m.getAnnotation(DataSource.class);
                    DynamicDataSourceHolder.setDataSource(source.value());
                }
            } catch (Exception e) {
            }
        }
    }
    
    public class DynamicDataSource extends AbstractRoutingDataSource {
        @Override
        protected Object determineCurrentLookupKey() {
            return DynamicDataSourceHolder.getDataSource();
        }
    }
    
    public class DynamicDataSourceHolder {
        /**
         * 注意:数据源标识保存在线程变量中,避免多线程操作数据源时互相干扰
         */
        private static final ThreadLocal<String> THREAD_DATA_SOURCE = new ThreadLocal<String>();
    
        public static String getDataSource() {
            return THREAD_DATA_SOURCE.get();
        }
    
        public static void setDataSource(String dataSource) {
            THREAD_DATA_SOURCE.set(dataSource);
        }
    
        public static void clearDataSource() {
            THREAD_DATA_SOURCE.remove();
        }
    }
    

    使用案例

        @Autowired
        private MXGLMapper mapper;
        @DataSource("dataSource2")
        public List<Map<String,Object>>  getmodel_table_prvd(){
         return mapper.getList();
        }
        @DataSource("dataSource")
        public List<Map<String, Object>> getmodel_table_prvd1() {
            return mapper.getList();
        }
    
    

    相关文章

      网友评论

          本文标题:spring3.0 多数据源的实现(跨数据库)

          本文链接:https://www.haomeiwen.com/subject/kfxrectx.html