博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【JAVA秒会技术之随意切换数据库】Spring如何高效的配置多套数据源
阅读量:6113 次
发布时间:2019-06-21

本文共 7950 字,大约阅读时间需要 26 分钟。

 Spring如何高效的配置多套数据源

    真正的开发中,难免要使用多个数据库,进行不同的切换。无论是为了实现读写分离”也好,还是为了使用不同的数据库“MySQL”或“Oracle”或“SQLServer”)。传统的方法,是配置多套Spring配置文件与Mysql配置文件,不仅配置起来较为混乱,而且切换及对事物的管理,也很麻烦。下面,博主就介绍一种方法,帮助大家解决“Spring如何高效的配置多套数据源”!

(一)Spring核心配置文件

1.Spring-conf配置文件

classpath:*.properties
classpath:/mybatis/mapper/*.xml
2.配置jdbc.properties

#------------------------JDBC-------------------------------jdbc.url:jdbc:sqlserver://ip地址1:端口;database=数据库;integratedSecurity=falsejdbc.driverClassName:com.microsoft.sqlserver.jdbc.SQLServerDriverjdbc.username:用户名jdbc.password:密码jdbc.filters:statjdbc.maxActive:10jdbc.initialSize:2jdbc.maxWait:60000jdbc.minIdle:2jdbc.timeBetweenEvictionRunsMillis:60000jdbc.minEvictableIdleTimeMillis:300000jdbc.validationQuery:SELECT 'x' FROM DUALjdbc.testWhileIdle:truejdbc.testOnBorrow:falsejdbc.testOnReturn:falsejdbc.maxOpenPreparedStatements:20jdbc.removeAbandoned:truejdbc.removeAbandonedTimeout:180jdbc.logAbandoned:true #---------------------------JDBC-2----------------------------jdbc2.url:jdbc:mysql://ip地址1:端口/数据库?autoReconnect=truejdbc2.driverClassName:com.mysql.jdbc.Driverjdbc2.username:用户名jdbc2.password:密码jdbc2.filters:statjdbc2.maxActive:10jdbc2.initialSize:2jdbc2.maxWait:60000jdbc2.minIdle:2jdbc2.timeBetweenEvictionRunsMillis:60000jdbc2.minEvictableIdleTimeMillis:300000jdbc2.validationQuery:SELECT 'x' FROM DUALjdbc2.testWhileIdle:truejdbc2.testOnBorrow:falsejdbc2.testOnReturn:falsejdbc2.maxOpenPreparedStatements:20jdbc2.removeAbandoned:truejdbc2.removeAbandonedTimeout:180jdbc2.logAbandoned:true

(二)配置通知与切面

1.配置通知

package com.netease.numen.core.annotation;import java.lang.annotation.*;/** * @author liyan */@Target({ ElementType.PARAMETER, ElementType.METHOD })@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface DatabaseConfiguration {	/**	 * annotation description	 * @return {@link java.lang.String}	 */	String description() default "";	/**	 * annotation value ,default value "dataSource"	 * @return {@link java.lang.String}	 */	String value() default "";}

2.配置切面

package com.netease.numen.core.aop;import java.lang.reflect.Method;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.AfterThrowing;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.annotation.Pointcut;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import com.netease.numen.core.annotation.DatabaseConfiguration;import com.netease.numen.core.util.MultipleDataSource;/** * 数据库配置切面 * @author liyan */@Aspectpublic class DatabaseConfigurationAspect {	/**	 * default dataSource	 */	public static final String DEFAULT_DATASOURCE = "dataSource";	/**	 * 日志	 */	private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseConfigurationAspect.class);	@Pointcut("@annotation(com.netease.numen.core.annotation.DatabaseConfiguration)")	public void DBAspect() {	}	/**	 * 前置通知	 * @param joinPoint 切点	 */	@Before("DBAspect()")	public void doBefore(JoinPoint joinPoint) {		try {			MultipleDataSource.setDataSourceKey(getTargetDataSource(joinPoint));			LOGGER.info("Methods Described:{}", getDescription(joinPoint));			LOGGER.info("Replace DataSource:{}", getTargetDataSource(joinPoint));		} catch (Exception e) {			LOGGER.warn("DataSource Switch Exception:{}", e);			MultipleDataSource.setDataSourceKey(DEFAULT_DATASOURCE);		}	}	/**	 * 异常通知	 * @param joinPoint  切点	 * @param e  异常	 */	@AfterThrowing(pointcut = "DBAspect()", throwing = "e")	public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {		try {			MultipleDataSource.setDataSourceKey(DEFAULT_DATASOURCE);		} catch (Exception ex) {			LOGGER.warn("DataSource Switch Exception:{}", e);		}	}	/**	 * 方法后通知	 * @param joinPoint  切点	 */	@After("DBAspect()")	public void doAfter(JoinPoint joinPoint) {		try {			MultipleDataSource.setDataSourceKey(DEFAULT_DATASOURCE);			LOGGER.info("Restore Default DataSource:{}", DEFAULT_DATASOURCE);		} catch (Exception e) {			LOGGER.warn("Restore Default DataSource Exception:{}", e);		}	}	/**	 * 获取数据源描述	 * @param joinPoint 切点	 * @return DB-Key(数据库)	 * @throws Exception	 */	@SuppressWarnings("rawtypes")	public static String getDescription(JoinPoint joinPoint) throws Exception {		String targetName = joinPoint.getTarget().getClass().getName();		String methodName = joinPoint.getSignature().getName();		Object[] arguments = joinPoint.getArgs();		Class targetClass = Class.forName(targetName);		Method[] methods = targetClass.getMethods();		String description = "";		for (Method method : methods) {			if (method.getName().equals(methodName)) {				Class[] clazzs = method.getParameterTypes();				if (clazzs.length == arguments.length) {					description = method.getAnnotation(DatabaseConfiguration.class).description();					if (description == null || "".equals(description))						description = "Database switch";					break;				}			}		}		return description;	}	/**	 * 获取数据源	 * @param joinPoint 切点	 * @return DB-Key(数据库)	 * @throws Exception	 */	@SuppressWarnings("rawtypes")	public static String getTargetDataSource(JoinPoint joinPoint) throws Exception {		String targetName = joinPoint.getTarget().getClass().getName();		String methodName = joinPoint.getSignature().getName();		Object[] arguments = joinPoint.getArgs();		Class targetClass = Class.forName(targetName);		Method[] methods = targetClass.getMethods();		String value = "";		for (Method method : methods) {			if (method.getName().equals(methodName)) {				Class[] clazzs = method.getParameterTypes();				if (clazzs.length == arguments.length) {					value = method.getAnnotation(DatabaseConfiguration.class).value();					if (value == null || "".equals(value))						value = DEFAULT_DATASOURCE;					break;				}			}		}		return value;	}}

(三)编写切换数据源工具类

package com.netease.numen.core.util;import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;/** * 多数据源配置 *  * 说明:定义动态数据源,实现通过集成Spring提供的AbstractRoutingDataSource,只需要 * 实现determineCurrentLookupKey方法即可  * 由于DynamicDataSource是单例的,线程不安全的,所以采用ThreadLocal保证线程安全,由 * DynamicDataSourceHolder完成。 *  * @author Liyan */public class MultipleDataSource extends AbstractRoutingDataSource {	private static final ThreadLocal
dataSourceKey = new InheritableThreadLocal
(); public static void setDataSourceKey(String dataSource) { dataSourceKey.set(dataSource); } @Override protected Object determineCurrentLookupKey() { // TODO Auto-generated method stub return dataSourceKey.get(); }}

(四)如何使用

这就很简单了,只要在serviceImpl中,要切换数据源前,调用工具类:

public String isExist(String jobNumber) throws DataAccessException {		try {			//切换数据源,对中间库操作			MultipleDataSource.setDataSourceKey("dataSource4");			Map
param = new HashMap
(0); param.put("jobNumber", jobNumber); return mapper.isExist(param); } catch (DataAccessException e) { throw e; } finally{ //切回数据源 MultipleDataSource.setDataSourceKey("dataSource"); } }

 

转载地址:http://mejka.baihongyu.com/

你可能感兴趣的文章
IIS7如何显示详细错误信息
查看>>
ViewPager切换动画PageTransformer使用
查看>>
coco2d-x 基于视口的地图设计
查看>>
C++文件读写详解(ofstream,ifstream,fstream)
查看>>
Android打包常见错误之Export aborted because fatal lint errors were found
查看>>
Tar打包、压缩与解压缩到指定目录的方法
查看>>
新手如何学习 jQuery?
查看>>
配置spring上下文
查看>>
Python异步IO --- 轻松管理10k+并发连接
查看>>
mysql-python模块编译问题解决
查看>>
Oracle中drop user和drop user cascade的区别
查看>>
【Linux】linux经常使用基本命令
查看>>
Java 内存区域和GC机制
查看>>
更新代码和工具,组织起来,提供所有博文(C++,2014.09)
查看>>
HTML模块化:使用HTML5 Boilerplate模板
查看>>
登记申请汇总
查看>>
Google最新截屏案例详解
查看>>
2015第31周一
查看>>
2015第31周日
查看>>
在使用EF开发时候,遇到 using 语句中使用的类型必须可隐式转换为“System.IDisposable“ 这个问题。...
查看>>