SpringBoot整合mybatis-plus实现动态数据源。

mac2022-11-22  5

前言:学习SpringAop和mybatis-plus的使用

一、SpringAop简介

1、理念:面向切面编程。
2、思想:基于代理思想,对原来目标对象,创建代理对象,在不修改原对象代码情况下,通过代理对象,调用增强功能的代码,从而对原有业务方法进行增强 !
3、技术:动态代理(JAVA反射)。
4、使用场景:日志记录、拦截请求、事务管理 …

二、Springboot中使用@Aspect

1、pom文件:

<!--aop--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>

2、使用方法: 在类上加上@Aspect即可。

三、整合mybatis-plus实现动态数据源(方式一基于aop)。

1、既然是动态数据源我们就配置两个。

spring: datasource: druid: driverClassName: com.mysql.cj.jdbc.Driver initialSize: 5 maxActive: 8 testOnBorrow: true validationQuery: SELECT 1 aliYun: url: jdbc:mysql://**********/aliyun?serverTimezone=Asia/Shanghai username: root password: root paper: url: jdbc:mysql://**********/paper?serverTimezone=Asia/Shanghai username: root password: root mybatis-plus: config-location: 'classpath:/mapper/**/*Mapper.xml'

2、配置类:

@Configuration //mapper接口扫描 @MapperScan("com.study.dynamicdatasource.mapper*") public class MybatisPlusConfig implements ApplicationContextAware { @Value("${spring.datasource.druid.driverClassName}") private String driverClassName; @Value("${spring.datasource.druid.initialSize}") private Integer initialSize; @Value("${spring.datasource.druid.maxActive}") private Integer maxActive; @Value("${spring.datasource.druid.testOnBorrow}") private Boolean testOnBorrow; @Value("${spring.datasource.druid.validationQuery}") private String validationQuery; @Value("${spring.datasource.aliYun.username}") private String aliYunUserName; @Value("${spring.datasource.aliYun.url}") private String aliYunUrl; @Value("${spring.datasource.aliYun.password}") private String aliYunPassword; @Value("${spring.datasource.paper.username}") private String paperUserName; @Value("${spring.datasource.paper.url}") private String paperUrl; @Value("${spring.datasource.paper.password}") private String paperPassword; private static ApplicationContext applicationContext; @Value("${mybatis-plus.config-location}") private String mapperLocations; /** * mybatis-plus分页插件。 * 原理:拦截器 * 文档:http://mp.baomidou.com */ @Bean public PaginationInterceptor paginationInterceptor() { PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); paginationInterceptor.setLimit(5000); paginationInterceptor.setDialectType("mysql"); return paginationInterceptor; } //数据源1 @Bean("aliYun") public DataSource aliYun() { //初始化数据源 DruidDataSource druidDataSource = this.initDruidDataSource(); druidDataSource.setUrl(aliYunUrl); druidDataSource.setUsername(aliYunUserName); druidDataSource.setPassword(aliYunPassword); return druidDataSource; } //数据源2 @Bean("paper") public DataSource paper() { DruidDataSource druidDataSource = initDruidDataSource(); druidDataSource.setUrl(paperUrl); druidDataSource.setUsername(paperUserName); druidDataSource.setPassword(paperPassword); return druidDataSource; } //AbstractRoutingDataSource类可以动态设置数据源 //实现determineCurrentLookupKey方法,动态指定DbType @Bean @Primary public DataSource multipleDataSource(@Qualifier("aliYun")DataSource aliYun, @Qualifier("paper")DataSource paper){ //实现determineCurrentLookupKey AbstractRoutingDataSource abstractRoutingDataSource = new AbstractRoutingDataSource() @Override protected Object determineCurrentLookupKey() { //DbContextHolder.getDbType()获取当前线程的数据源。 return DbContextHolder.getDbType(); } }; Map<Object, Object> targetDataSources = Maps.newHashMap(); targetDataSources.put(DBTypeEnum.ALI_YUN.getValue(),aliYun); targetDataSources.put(DBTypeEnum.PAPER.getValue(),paper); abstractRoutingDataSource.setTargetDataSources(targetDataSources); //默认数据库 abstractRoutingDataSource.setDefaultTargetDataSource(aliYun); return abstractRoutingDataSource; } /** * 配置mybatis-plus的sqlSessionFactory * @return {@link SqlSessionFactory} * @throws {@link Exception} */ @Bean("sqlSessionFactory") public SqlSessionFactory sqlSessionFactory() throws Exception { MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean(); sqlSessionFactory.setDataSource(multipleDataSource(aliYun(),paper())); MybatisConfiguration configuration = new MybatisConfiguration(); configuration.setJdbcTypeForNull(JdbcType.NULL); configuration.setMapUnderscoreToCamelCase(true); configuration.setCacheEnabled(false); sqlSessionFactory.setConfiguration(configuration); sqlSessionFactory.setMapperLocations(applicationContext.getResources(mapperLocations)); sqlSessionFactory.setPlugins(new Interceptor[]{ paginationInterceptor() }); return sqlSessionFactory.getObject(); } /** * 初始化数据源 * @return */ private DruidDataSource initDruidDataSource() { DruidDataSource druidDataSource = new DruidDataSource(); druidDataSource.setDriverClassName(driverClassName); druidDataSource.setInitialSize(initialSize); druidDataSource.setMaxActive(maxActive); druidDataSource.setTestOnBorrow(testOnBorrow); druidDataSource.setValidationQuery(validationQuery); return druidDataSource; } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; }

至此已经配置好数据源。 3、DbContextHolder:使用ThreadLocal保存每个线程数据源名称。

public class DbContextHolder { /** * 存储不同数据源的名称 */ private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>(); /** * 设置数据源 * * @param dbTypeEnum */ public static void setDbType(DBTypeEnum dbTypeEnum) { CONTEXT_HOLDER.set(dbTypeEnum.getValue()); } /** * 取得当前数据源 * * @return */ public static String getDbType() { return CONTEXT_HOLDER.get(); } /** * 清除上下文数据 */ public static void clearDbType() { CONTEXT_HOLDER.remove(); }

4、使用aop在执行mapper之前时切入。

@Component @Order(value = -1) @Aspect public class DataSourceSwitchAspect { /** * 切点 * 在paper包下切入 */ @Pointcut("execution(* com.study.dynamicdatasource.mapper.paper..*.*(..))") private void paperAspect() { } /** * 切点 * 在aliyun包下切入 */ @Pointcut("execution(* com.study.dynamicdatasource.mapper.aliyun..*.*(..))") private void aliYunAspect() { } /** * 方法执行之前 * 设置paper数据源 */ @Before(value = "paperAspect()") public void paperBefore() { System.out.println("设置数据源paper"); DbContextHolder.setDbType(DBTypeEnum.PAPER); } /** * 方法执行之前 * 设置aliyun数据源 */ @Before("aliYunAspect()") public void aliYunBefore() { DbContextHolder.setDbType(DBTypeEnum.ALI_YUN); System.out.println("设置数据源aliYun"); } /** * 方法执行之后 * 清除paper数据源 */ @After(value = "paperAspect()") public void paperAfter() { System.out.println("清除数据源paper"); DbContextHolder.clearDbType(); } /** * 方法执行之后 * 清除aliyun数据源 */ @After(value = "aliYunAspect()") public void aliYunAfter() { DbContextHolder.clearDbType(); System.out.println("清除数据源aliYun"); }

四、整合mybatis-plus实现动态数据源(方式二,基于sqlSessionFactory)。

待续。。.

最新回复(0)