zoukankan      html  css  js  c++  java
  • 基于注解的Spring多数据源配置和使用(非事务)

    原文:基于注解的Spring多数据源配置和使用

    1。创建DynamicDataSource类,继承AbstractRoutingDataSource

    package com.rps.dataSource;
    
    import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
    
    public class DynamicDataSource extends AbstractRoutingDataSource {
    
        @Override
        protected Object determineCurrentLookupKey() {
            return DynamicDataSourceHolder.getDataSource();
        }
    
    }

      创建DynamicDataSourceHolder类

    package com.rps.dataSource;
    
    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();
        }
    }

    2.配置多数据源

    <util:properties id="jdbc"
            location="classpath:etc/mybatis/db.properties" />
    
        <!-- 连接池配置开始 -->
        <!-- Druid连接池 -->
        <bean id="druidDataSourceAccount" class="com.alibaba.druid.pool.DruidDataSource"
            destroy-method="close" lazy-init="true">
            <property name="driverClassName" value="#{jdbc.driverClassName}" />
            <property name="url" value="#{jdbc.account_url}" />
            <property name="username" value="#{jdbc.username}" />
            <property name="password" value="#{jdbc.password}" />
        </bean>
        <bean id="druidDataSourceCommon" class="com.alibaba.druid.pool.DruidDataSource"
            destroy-method="close" lazy-init="true">
            <property name="driverClassName" value="#{jdbc.driverClassName}" />
            <property name="url" value="#{jdbc.common_url}" />
            <property name="username" value="#{jdbc.username}" />
            <property name="password" value="#{jdbc.password}" />
        </bean>
        <bean id="druidDataSourceData" class="com.alibaba.druid.pool.DruidDataSource"
            destroy-method="close" lazy-init="true">
            <property name="driverClassName" value="#{jdbc.driverClassName}" />
            <property name="url" value="#{jdbc.data_url}" />
            <property name="username" value="#{jdbc.username}" />
            <property name="password" value="#{jdbc.password}" />
        </bean>
    
        <!-- 连接池配置结束 -->
    
        <!-- MyBatis整合开始 -->
        <bean id="dynamicDataSource" class="com.rps.dataSource.DynamicDataSource">
            <property name="targetDataSources">
                <map key-type="java.lang.String">
                    <entry key="account" value-ref="druidDataSourceAccount"></entry>
                    <entry key="common" value-ref="druidDataSourceCommon"></entry>
                    <entry key="data" value-ref="druidDataSourceData"></entry>
                </map>
            </property>
        </bean>
    
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> 
            <property name="dataSource" ref="dynamicDataSource"/>
             <property name="mapperLocations" value="classpath:com/rps/**/*.xml"/> 
             <property name="configLocation" value="classpath:etc/mybatis/mybatis-config.xml"/> 
        </bean> 
    
    
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="com.rps" />
            <property name="annotationClass" value="com.rps.annotations.MyBatisRepository" />
        </bean>
        <!-- MyBatis整合结束 -->
    
    
        <!-- 配置数据库事务开始 -->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
            <property name="dataSource" ref="dynamicDataSource"/> 
        </bean>
        <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
        <!-- 配置数据库事务结束 -->

    3.在使用数据源前,选择数据源:

      

    DynamicDataSourceHolder.setDataSource("account");

      或:使用spring aop 动态切换:

    package com.rps.aspect;
    
    import java.lang.annotation.Annotation;
    import java.lang.reflect.Method;
    
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.springframework.stereotype.Component;
    
    import com.rps.annotations.DataSource;
    import com.rps.dataSource.DynamicDataSourceHolder;
    
    @Component
    @Aspect
    public class DataSourceAspect {
        /**
         * 拦截目标方法,获取由@DataSource指定的数据源标识,设置到线程存储中以便切换数据源
         * 
         * @param point
         * @throws Exception
         */
        @Before("execution(* com.rps.*.model.dao.*.*(..))")
        public void intercept(JoinPoint point) throws Exception {
            System.out.println("*****************************");
            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((Class<? extends Annotation>) 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) {
                System.out.println(clazz + ":" + e.getMessage());
            }
        }
    }

    注:事务管理配置一定要配置在往DynamicDataSourceHolder 中注入数据源key之前 ,否则会报 Could not open JDBC Connection for transaction; nested exception is java.lang.IllegalStateException: Cannot determine target DataSource for lookup key [null] 找不到数据源错误

  • 相关阅读:
    matplotlib
    CNN中feature map、卷积核、卷积核个数、filter、channel的概念解释,以及CNN 学习过程中卷积核更新的理解
    Batch Normlization原理
    pycharts
    stm 32 LED(寄存器版本)
    stm32 滴答时钟实现较准时延时功能
    LFS笔记一:从LFS网站获取资源
    ubuntu 12.04编译安装linux3.6.10内核笔记
    stm32 外部事件<按键>中断输入实现过程<寄存器>
    stm32 中断几个库函数实现过程分析。
  • 原文地址:https://www.cnblogs.com/qingyibusi/p/6590489.html
Copyright © 2011-2022 走看看