spring 多數據源切換


spring配置管理多數據源,方便服務訪問不同數據庫時,數據源切換。多少無意,直接上代碼。

1.定義數據源key枚舉值(可以直接使用字符串代替,為了代碼的整潔及易讀性,這里使用枚舉)

public enum DataSourceEnum {
	anquan,
	publ,
	tlshow,
}

2.定義數據源持有者,切換數據源使用

public final class DataSourceHolder {
	private static ThreadLocal<DataSourceEnum> currentDBName = new ThreadLocal<DataSourceEnum>();
	
	private static DataSourceEnum DEFAULT_HASH = DataSourceEnum.anquan;

	public static DataSourceEnum determineDefault() {
		return determineDS(DEFAULT_HASH);
	}

	public static DataSourceEnum determineDS(DataSourceEnum key) {
		currentDBName.set(key);
		log.debug("determineDS:" + key);
		return key;
	}
	
	
	public static DataSourceEnum getCurrentDBName() {
		return currentDBName.get();
	}
}

3.實現數據源路由接口

public class DBRoutingDataSource extends AbstractRoutingDataSource {

	@Override
	protected Object determineCurrentLookupKey() {
		return DataSourceHolder.getCurrentDBName();
	}

	@Override
	public void setTargetDataSources(Map targetDataSources) {
		super.setTargetDataSources(targetDataSources);
	}
	
	@Override
	public Object unwrap(Class iface) throws SQLException {
		return null;
	}

	@Override
	public boolean isWrapperFor(Class iface) throws SQLException {
		return false;
	}
}

4.定義spring 切面,在執行service方法前,切換數據源。(首先要保證spring支持注解)

@Aspect
@lombok.extern.log4j.Log4j
public class DetermineAspect {
	@Pointcut("within(com.changyou.*.service.impl.*)")
	public void withController() {}

	@Before("withController()")
	public void beforeAdvice(JoinPoint jp) {
		if(log.isDebugEnabled()) {
			log.debug("Reset db router before " + jp.getSignature().getDeclaringType().getSimpleName() + "." + jp.getSignature().getName() + "()");
		}
		DataSourceMethod datasourceMethod = ((MethodSignature)jp.getSignature()).getMethod().getAnnotation(DataSourceMethod.class);
		DataSourceFile datasourceFile = ((MethodSignature)jp.getSignature()).getMethod().getDeclaringClass().getAnnotation(DataSourceFile.class);
		
		if(datasourceMethod!=null){
			DataSourceHolder.determineDS(datasourceMethod.value());
		}else if(datasourceFile!=null){
			DataSourceHolder.determineDS(datasourceFile.value());
		}else{
			DataSourceHolder.determineDefault();
		}
	}

}

5.spring配置數據源,使用自己實現的數據源路由類(DBRoutingDataSource 

<!-- 配置數據源 -->
	<bean name="dataSource_0" parent="abstractProxoolDataSource">
		<property name="url" value="${jdbc.0.url}" />
		<property name="username" value="${jdbc.0.username}" />
		<property name="password" value="${jdbc.0.password}" />
	</bean>
	
	<!-- 配置數據源tlshow-->
	<bean name="dataSource_1" parent="abstractProxoolDataSource">
		<property name="url" value="${jdbc.1.url}" />
		<property name="username" value="${jdbc.1.username}" />
		<property name="password" value="${jdbc.1.password}" />
	</bean>
	
	<!-- 配置數據源publicaccount-->
	<bean name="dataSource_2" parent="abstractProxoolDataSource">
		<property name="url" value="${jdbc.2.url}" />
		<property name="username" value="${jdbc.2.username}" />
		<property name="password" value="${jdbc.2.password}" />
	</bean>
	
	
	<bean id="dataSource" class="com.changyou.common.util.dbaccess.DBRoutingDataSource">
		<property name="defaultTargetDataSource" ref="dataSource_0"/>
		<property name="targetDataSources">
			<map key-type="com.changyou.common.enums.DataSourceEnum"><!-- 數據源枚舉 -->
				<entry key="anquan" value-ref="dataSource_0" />
				<entry key="tlshow" value-ref="dataSource_1" />
				<entry key="publ" value-ref="dataSource_2" />
			</map>
		</property>
	</bean>

6.基礎工作完成,下面開始使用,需要在server類或方法上添加注解。(上面的切面會查看是否有指定注解的存在)。

  定義自己的注解:

@Target(value={ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSourceRouter {
	public DataSourceEnum value() default DataSourceEnum.anquan;
}

7.開始愉快的使用吧,方法上的注解權限高於整個類上的注解,這取決於切面的處理方式。

@Service
@DataSourceRouter(DataSourceEnum.publ)
public class CyjUserServiceImpl{

	@Autowired
	private UserMapper userMapper;
	
	public void saveOrUpdateBlock(CyjUserBlock cyjUserBlock) {
		userMapper.saveOrUpdateBlock(cyjUserBlock);
	}

        @DataSourceRouter(DataSourceEnum.anquan)
	public void deleteBlockById(int blockId) {
		userMapper.deleteBlockById(blockId);
	}
}

  

ok,后期補上demo。。。。。。。

 


免責聲明!

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



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