基於注解的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] 找不到數據源錯誤


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM