溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

spring中怎么通過(guò)注解切換多數(shù)據(jù)源

發(fā)布時(shí)間:2021-06-18 17:37:52 來(lái)源:億速云 閱讀:268 作者:Leah 欄目:大數(shù)據(jù)

spring中怎么通過(guò)注解切換多數(shù)據(jù)源,針對(duì)這個(gè)問(wèn)題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問(wèn)題的小伙伴找到更簡(jiǎn)單易行的方法。

第一步,配置數(shù)據(jù)源

<bean id="masterDataSource" class="com.alibaba.druid.pool.DruidDataSource">
   <property name="username" value="root" />
   <property name="password" value="spring" />
   <property name="url" value="jdbc:mysql://localhost:3306/taotao?characterEncoding=utf-8" />
   <!-- 最大并發(fā)連接數(shù) -->
   <property name="maxActive" value="30" />
   <!-- 最小空閑連接數(shù) -->
   <property name="minIdle" value="5" />
   <!-- 用于顯示數(shù)據(jù)源監(jiān)控中的sql語(yǔ)句監(jiān)控 -->
   <property name="filters" value="stat" />
</bean>
 
<bean id="slaveDataSource" class="com.alibaba.druid.pool.DruidDataSource">
   <property name="username" value="root" />
   <property name="password" value="spring" />
   <property name="url" value="jdbc:mysql://localhost:3306/taobao?characterEncoding=utf-8" />
   <!-- 最大并發(fā)連接數(shù) -->
   <property name="maxActive" value="30" />
   <!-- 最小空閑連接數(shù) -->
   <property name="minIdle" value="5" />
   <!-- 用于顯示數(shù)據(jù)源監(jiān)控中的sql語(yǔ)句監(jiān)控 -->
   <property name="filters" value="stat" />
</bean>

第二步,定義用來(lái)切庫(kù)的注解,和枚舉類(lèi)

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Dataswitch {
    Datatype value() default Datatype.master;
}
public enum Datatype {
    master("masterDataSource"),slave("slaveDataSource");
    private String value;
    Datatype(String name){
        this.value = name;
    }
 
    public String getValue() {
        return value;
    }
 
    public void setValue(String value) {
        this.value = value;
    }
}

第三步,定義一個(gè)當(dāng)前線程的變量的工具類(lèi),用于設(shè)置對(duì)應(yīng)的數(shù)據(jù)源名稱(chēng)

public  class DynamicDataSourceHolder {
    private static final ThreadLocal<String> threadLocal = new ThreadLocal<String>();
 
    public static String getThreadLocal() {
        return threadLocal.get();
    }
 
    public static void setThreadLocal(String name) {
        threadLocal.set(name);
    }
    public static void clear(){
        threadLocal.remove();
    }
}

第四步,創(chuàng)建AbstactRoutingDataSource的子類(lèi),重寫(xiě)determineCurrentLockupKey方法

public class DynamicDataSource extends AbstractRoutingDataSource{
    protected Object determineCurrentLookupKey() {
        System.out.println(DynamicDataSourceHolder.getThreadLocal());
        return DynamicDataSourceHolder.getThreadLocal();
    }
}

第五步,將多數(shù)據(jù)源配置到用我們創(chuàng)建的DynamicDataSource

<bean id="dynamicDataSource" class="xin.youhuila.sorceswitch.process.DynamicDataSource">
   <property name="targetDataSources">
      <map key-type="java.lang.String">
         <entry key="masterDataSource" value-ref="masterDataSource"></entry>
         <entry key="slaveDataSource" value-ref="slaveDataSource"></entry>
      </map>
   </property>
   <property name="defaultTargetDataSource" ref="masterDataSource"></property>
</bean>

第六步,配置切面,在操作數(shù)據(jù)庫(kù)方法之前,獲取注解配置的數(shù)據(jù)源名稱(chēng),返回

@Component
@Aspect
@Order(0)
public class DataSourceAspect {
    @Pointcut("execution (* xin.youhuila.sorceswitch.service..*(..))")
    public void aspect(){
 
    }
    @Before("aspect()")
    public void before(JoinPoint joinPoint){
        Class<?> clazz = joinPoint.getTarget().getClass();
        Method[] method = clazz.getMethods();
        Dataswitch dataswitch = null;
        boolean is = false;
        for(Method m:method){//此處最好改成通過(guò)簽名獲取調(diào)用方法是否含有注解,而不是遍歷每個(gè)方法,可參考http://www.gitout.cn/?p=2398
            if(m.isAnnotationPresent(Dataswitch.class)){
                dataswitch = m.getAnnotation(Dataswitch.class);
                DynamicDataSourceHolder.setThreadLocal(dataswitch.value().getValue());
                is = true;
            }
        }
        if(!is){
            DynamicDataSourceHolder.setThreadLocal(Datatype.master.getValue());
        }
    }
    @After("aspect()")
    public void after(){
        DynamicDataSourceHolder.clear();
    }
}

第七步,使用

@Service
public class DemoService {
    @Autowired
    DemoMapper demoMapper;
    @Dataswitch(Datatype.master)
    public void select(){
        List<Demo> d = demoMapper.select();
        for(Demo demo:d){
            System.out.println(demo);
        }
    }
}

--------------------------------http://www.gitout.cn/?p=2398文章實(shí)現(xiàn)-----------------------

/**
 * 數(shù)據(jù)源切面
 */
@Aspect
@Component
public class DynamicDataSourceAspect {
	
	@Pointcut("@annotation(com...datasource.DynamicDataSourceAnnotation)") 
	public void pointCut() {
	}
	
	@Before("pointCut()")
	public void testBefore(JoinPoint point) {
		// 獲得當(dāng)前訪問(wèn)的class
		Class<?> className = point.getTarget().getClass();
		DynamicDataSourceAnnotation dataSourceAnnotation = className.getAnnotation(DynamicDataSourceAnnotation.class);
		String dataSource = DataSourceConst.DB_ACTIVITY;
		// 優(yōu)先級(jí): 方法 > 類(lèi)  > DB_ACTIVITY
		if(dataSourceAnnotation != null) {
			dataSource = dataSourceAnnotation.dataSource();
		}
		String methodName = point.getSignature().getName();
		// 得到方法的參數(shù)的類(lèi)型
		Class<?>[] argClass = ((MethodSignature) point.getSignature()).getParameterTypes();
		try {
			Method method = className.getMethod(methodName, argClass);
			if (method.isAnnotationPresent(DynamicDataSourceAnnotation.class)) {
				DynamicDataSourceAnnotation annotation = method.getAnnotation(DynamicDataSourceAnnotation.class);
				dataSource = annotation.dataSource();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		DataSourceContextHolder.setDataSourceType(dataSource);

	}

	@After("pointCut()")
	public void testAfter(JoinPoint point) {
		// 獲得當(dāng)前訪問(wèn)的class
		Class<?> className = point.getTarget().getClass();
		DynamicDataSourceAnnotation dataSourceAnnotation = className.getAnnotation(DynamicDataSourceAnnotation.class);
		if (dataSourceAnnotation != null) {
			// 獲得訪問(wèn)的方法名
			String methodName = point.getSignature().getName();
			// 得到方法的參數(shù)的類(lèi)型
			Class<?>[] argClass = ((MethodSignature) point.getSignature()).getParameterTypes();
			String dataSource = DataSourceConst.DB_ACTIVITY;
			try {
				Method method = className.getMethod(methodName, argClass);
				if (method.isAnnotationPresent(DynamicDataSourceAnnotation.class)) {
					DynamicDataSourceAnnotation annotation = method.getAnnotation(DynamicDataSourceAnnotation.class);
					dataSource = annotation.dataSource();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
			if (dataSource != null && !DataSourceConst.DB_ACTIVITY.equals(dataSource)) {
				DataSourceContextHolder.clearDataSourceType();
			}
		}
	}
}

關(guān)于spring中怎么通過(guò)注解切換多數(shù)據(jù)源問(wèn)題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒(méi)有解開(kāi),可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識(shí)。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI