Mybatis(拦截器实现)通用mapper及全ORM实现(五)-- springboot+mybatis多数据源设置
发布日期:2022-02-22 18:04:24
浏览次数:13
分类:技术文章
本文共 7572 字,大约阅读时间需要 25 分钟。
本篇实际上和mybatisext项目并没有太大关系了,但在实际项目中脱离不开多个数据源,尤其是主从分离,同样网上一些资料大同小异而且大部分并不能真正解决问题,所以单独提出来说一下
假设我们就是要解决一个主从分离,数据源定义在了application.properties中如下:
datasources.master.driverClassName=com.mysql.cj.jdbc.Driverdatasources.master.url=xxxdatasources.master.username=xxxdatasources.master.password=xxxdatasources.master.type=com.alibaba.druid.pool.DruidDataSourcedatasources.master.filters=statdatasources.master.maxActive= 20datasources.master.initialSize= 1datasources.master.maxWait= 60000datasources.master.minIdle =1datasources.master.timeBetweenEvictionRunsMillis= 60000datasources.master.minEvictableIdleTimeMillis=300000datasources.master.validationQuery= select 'x'datasources.master.testWhileIdle= truedatasources.master.testOnBorrow=falsedatasources.master.testOnReturn= falsedatasources.master.poolPreparedStatements=truedatasources.master.maxOpenPreparedStatements= 20datasources.slave.driverClassName=com.mysql.cj.jdbc.Driverdatasources.slave.url=xxxdatasources.slave.username=xxxdatasources.slave.password=xxxdatasources.slave.type=com.alibaba.druid.pool.DruidDataSourcedatasources.slave.filters=statdatasources.slave.maxActive= 20datasources.slave.initialSize= 1datasources.slave.maxWait= 60000datasources.slave.minIdle =1datasources.slave.timeBetweenEvictionRunsMillis= 60000datasources.slave.minEvictableIdleTimeMillis=300000datasources.slave.validationQuery= select 'x'datasources.slave.testWhileIdle= truedatasources.slave.testOnBorrow=falsedatasources.slave.testOnReturn= falsedatasources.slave.poolPreparedStatements=truedatasources.slave.maxOpenPreparedStatements= 20
定义一个枚举类,针对这两个数据源
public enum DataSourceType { Master, Slave,}
动态数据源定义,保证线程安全引用了ThreadLocal类记录当前使用的数据源
public class DynamicDataSource extends AbstractRoutingDataSource { private static final ThreadLocalcontextHolder = new ThreadLocal<>(); public static void setDataSourceType(DataSourceType dataSourceType){ contextHolder.set(dataSourceType); } public static DataSourceType getDataSourceType() { return contextHolder.get(); } public static void clear(){ contextHolder.remove(); } @Override protected Object determineCurrentLookupKey(){ return DynamicDataSource.getDataSourceType(); }}
然后进行mybatis配置的注入
@Configuration@MapperScan({"cw.frame.mybatisext.test.mapper"})public class MyBatisConfig { @Autowired private Environment environment; @Autowired private MySqlInterceptor mySqlInterceptor; @Bean public MySqlInterceptor mySqlInterceptor(){ return new MySqlInterceptor(); } @Bean public DataSource masterDataSource() throws Exception{ return DruidDataSourceFactory.createDataSource(this.getDataSourceProperty("datasources.master.")); } @Bean public DataSource slaveDataSource() throws Exception{ return DruidDataSourceFactory.createDataSource(this.getDataSourceProperty("datasources.slave.")); } /** * @Primary 该注解表示在同一个接口有多个实现类可以注入的时候,默认选择哪一个,而不是让@autowire注解报错 * @Qualifier 根据名称进行注入,通常是在具有相同的多个类型的实例的一个注入(例如有多个DataSource类型的实例) * @DependsOn 解决循环依赖问题,在系统自动创建datasource前创建指定数据源 * @param masterDataSource * @param slaveDataSource * @return */ @Bean @Primary @DependsOn({ "masterDataSource", "slaveDataSource"}) public DynamicDataSource dataSource(@Qualifier("masterDataSource") DataSource masterDataSource, @Qualifier("slaveDataSource") DataSource slaveDataSource){ Map
这里特别说明一下:
@DependsOn({ "masterDataSource", "slaveDataSource"}),告知springboot这个bean依赖另外两个bean,保证了注入顺序,要不会报错或不起作用 另外由于手动创建了SqlSessionFactory,所以拦截器的定义也要手动设置一下(代码中已有注释说明),要不按照普通的配置拦截器将无法生效最后在做一个切片定义
@Aspect@Componentpublic class DynamicDataSourceAspect { @Before("@annotation(DataSource)") public void beforeExecute(JoinPoint point){ } @Around("@annotation(DataSource)") public Object aroundExecute(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{ Class classType = proceedingJoinPoint.getTarget().getClass(); String methodName = proceedingJoinPoint.getSignature().getName(); Class[] argClass = ((MethodSignature)proceedingJoinPoint.getSignature()).getParameterTypes(); DataSourceType lastDataSourceType = null; boolean resetDataSourceType = false; Method method = classType.getMethod(methodName, argClass); if (method.isAnnotationPresent(DataSource.class)){ DataSourceType dataSourceType = method.getAnnotation(DataSource.class).value(); lastDataSourceType = DynamicDataSource.getDataSourceType(); if (lastDataSourceType == null){ DynamicDataSource.setDataSourceType(dataSourceType); resetDataSourceType = true; } else { switch (lastDataSourceType){ case Master: break; case Slave: if (dataSourceType == DataSourceType.Master){ DynamicDataSource.setDataSourceType(dataSourceType); resetDataSourceType = true; } break; } } } Object result = proceedingJoinPoint.proceed(); if (resetDataSourceType){ if (lastDataSourceType == null){ DynamicDataSource.clear(); } else { DynamicDataSource.setDataSourceType(lastDataSourceType); } } return result; } @After("@annotation(DataSource)") public void afterExecute(JoinPoint point){ }}
所有带@DataSource注解的都会进入切片,动态设置数据源
当然代码中你想手动设置也可以通过:DynamicDataSource.setDataSourceType 方法进行设置到此为止,介绍完了关于mybatis的拦截器全ORM实现的方案和mybatisext的项目,源代码
转载地址:https://blog.csdn.net/erct/article/details/82703889 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
路过,博主的博客真漂亮。。
[***.116.15.85]2024年03月27日 09时11分05秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
终于找到可以一文多发的平台了!
2019-04-26
IntelliJ IDEA 2019 快捷键终极大全,速度收藏!
2019-04-26
第3章-5 字符转换 (15分)【python】
2019-04-26
L1-068 调和平均 (10 分)
2019-04-26
L1-069 胎压监测 (15 分)
2019-04-26
L1-071 前世档案 (20 分)
2019-04-26
L1-072 刮刮彩票 (20 分)
2019-04-26
L2-012 关于堆的判断 (25 分)
2019-04-26
L1-064 估值一亿的AI核心代码 (20 分)
2019-04-26
L2-033 简单计算器 (25 分)
2019-04-26
L2-034 口罩发放 (25 分)
2019-04-26
L2-019 悄悄关注 (25 分)
2019-04-26
L1-020 帅到没朋友 (20 分)
2019-04-26
L1-046 整除光棍 (20 分)
2019-04-26
L2-021 点赞狂魔 (25 分)【优化后的】
2019-04-26
L2-032 彩虹瓶 (25 分)
2019-04-26
L2-004 这是二叉搜索树吗? (25 分)
2019-04-26
L2-011 玩转二叉树 (25 分)
2019-04-26
L2-006 树的遍历 (25 分)
2019-04-26