随着业务的不断扩张,应用压力逐渐增大,特别是数据库。不论从读写分离还是分库的方法来提高应用的性能,都需要涉及到多数据源问题。本文主要介绍在Spring MVC+Mybatis下的多数据源配置。主要通过Spring提供的AbstractRoutingDataSource来实现多数据源。
1. 继承AbstractRoutingDataSource
AbstractRoutingDataSource 是spring提供的一个多数据源抽象类。spring会在使用事务的地方来调用此类的determineCurrentLookupKey()
方法来获取数据源的key值。我们继承此抽象类并实现此方法:
@Order(2) public class DynamicDataSource extends AbstractRoutingDataSource { private static final Logger logger = LogManager.getLogger(DynamicDataSource.class); @Override protected Object determineCurrentLookupKey() { logger.info("当前数据源为:"+DataSourceContextHolder.getDB()); return DataSourceContextHolder.getDB(); } }
2. 线程内部数据源处理类
public class DataSourceContextHolder { private static final Logger logger = LogManager.getLogger(DataSourceContextHolder.class); /** * 默认数据源 */ public static final String DEFAULT_DS = "dataSource"; private static final ThreadLocal<String> contextHolder = new ThreadLocal<>(); /** * 设置数据源名 * @param dbType */ public static void setDB(String dbType) { contextHolder.set(dbType); logger.info("切换到{"+dbType+"}数据源"); } /** * 获取数据源名 * @return */ public static String getDB() { if(contextHolder.get()==null){ return DEFAULT_DS; }else{ return (contextHolder.get()); } } /** * 清除数据源名 */ public static void clearDB() { contextHolder.remove(); }
3. 自定义数据源注解类
对于spring来说,注解即简单方便且可读性也高。所以,我们也通过注解在Mapper或service的方法前指定所用的数据源。我们先定义自己的注解类,其中value为数据源的key值,并初始化dataSource为默认数据源。
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD,ElementType.TYPE}) @Documented public @interface DS { String value() default "dataSource"; }
4. AOP 拦截mapper并切换数据源
指定注解以后,我们可以通过AOP拦截所有mapper方法,在方法执行之前获取方法上的注解:即数据源的key值。
@Order(1) @Aspect public class DynamicDataSourceAspect { @After("@annotation(DS)") public void afterSwitchDS(JoinPoint point){ DataSourceContextHolder.clearDB(); } /** * 拦截目标方法,获取由@DataSource指定的数据源标识,设置到线程存储中以便切换数据源 * * @param point * @throws Exception */ @Before("@annotation(DS)&#