SASS平台根据用户机构动态切换数据库连接的datasource

背景:作为sass平台,有若干机构作为系统的租户存在,用户的创建需要绑定到唯一的机构下面,机构有机构简称,设计为,根据不同的机构下的用户设立独立的数据库,平台系统根据用户所在的机构去连接不同数据库进行业务操作

1.创建注解类

1@Target(ElementType.METHOD,ElementType.Type) 2@Retention(RetentionPolicy.RUNTIME) 3@Inherited 4@Ducumented 5public @interface DBChangeAnno{ 6 String value() default "master"; 7}

2.在数据库连接配置文件中设置多个数据源,并且数据源的名称根据机构简称设置

1xx.jdbc.datasource.names=master,czbk 2xx.jdbc.datasource.master.jdbcurl=jdbc:mysql://192.1.1.1:3306/db1 3xx.jdbc.datasource.master.username=db1 4xx.jdbc.datasource.master.passowrd=123456 5xx.jdbc.datasource.master.driverClassName=com.mysql.jdbc.Driver 6.... 7xx.jdbc.datasource.czbk.jdbcurl=jdbc:mysql://192.1.1.2:3306/db2 8xx.jdbc.datasource.czbk.username=db2 9xx.jdbc.datasource.czbk.passowrd=123456 10xx.jdbc.datasource.czbk.driverClassName=com.mysql.jdbc.Driver

3.创建切面类等类,对所有标注了注解的方法执行前进行拦截并且切换数据源

1//编写切面类,对注解方法进行前置增强,改变当前线程的数据库连接 2@Slf4j 3@Aspect 4@Order(-1) 5@ConditionalOnProperty(value = {xx.jdbc.datasource.names}) 6@Component 7public class DBChangeInterceptor { 8 @Autowired 9 private XXXmapper mapper;//查询用户所在机构简称mapper 10 11 @Before("@annotation(dbChangeAnno)") 12 //这里也可加@within(dbChangeAnno)就会在类层面的所有方法进行切面,但是不能写在一起,比如@Before("@annotation(dbChangeAnno)||@within(dbChangeAnno)")这样只会生效后面的 13 public void switchDataSource(JoinPoint point,DBCHangeAnno anno){ 14 String sourceName = anno.value();//默认是连接master数据库的,因为用户及机构信息是在master数据库进行维护 15 if(SessionUtils.getSession() != null){ 16 sourceName = SessionUtils.getSession().getOrgId();//在session中存储当前登录用户的机构代码主键 17 OrgInfo orgi = mapper.sekectByPrimaryKey(sourceName); 18 sourceName = orgi.getShortName(); 19 } 20 if(XXDataSourceContextHolder.containDataSourceName(sourceName)){ 21 XXDataSourceContextHolder.setCurrentDataSourceName(sourceName); 22 } 23 } 24 25 //调用结束后还原线程的连接数据库到默认库中去 26 @After("@annotation(dbChangeAnno)") 27 public void restoreDataSource(JoinPoint point,DBCHangeAnno anno){ 28 XXDataSourceContextHolder.clearCurrentDataSourceName(); 29 } 30} 31 32//多数据源上下文类 33public final class XXDataSourceContextHolder{ 34 //数据源标识保存在线程变量中,避免多线程操作数据源时互相干扰。 35 private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<String>(); 36 private static final Set<String> NAME_SET = new CopyOnWriteArraySet<String>(); 37 private static String defaultDataSourceName = null;//程序启动时将xx.jdbc.datasource.names的第一个名称作为默认数据库 38 39 private XXDataSourceContextHolder(){ 40 } 41 42 public static void setCurrentDataSourceName(String name){ 43 CONTEXT_HOLDER.set(name); 44 } 45 46 public static String getCurrentDataSourceName(){ 47 String name = CONTEXT_HOLDER.get(); 48 if(name == null){ 49 name = defaultDataSourceName; 50 } 51 return name; 52 } 53 54 public static void clearCurrentDataSourceName(){ 55 CONTEXT_HOLDER.remove(); 56 } 57 58 public static boolean containDataSourceName(String name){ 59 return NAME_SET.contains(name); 60 } 61 62 public static void addDataSourceName(String name){ 63 NAME_SET.add(name); 64 } 65 66 public static void setDefaultDataSourceName(String name){ 67 XXDataSourceContextHolder.defaultDataSourceName = name; 68 } 69} 70 71//在数据源的配置时使用该数据源配置 72@Slf4j 73public class XXRoutingDataSource extends AbstractRoutingDataSource{ 74 @Override 75 protected Object determinCurrentLookupKey(){ 76 String cuurentDSName = XXDataSourceContextHolder.getCurrentDataSourceName(); 77 if(currentDSName == null || "".equals(cuurentDSName)){ 78 cuurentDSName = XXDataSourceContextHolder.getDefaultDataSourceName(); 79 } 80 return cuurentDSName; 81 } 82} 83 84//在Controller类中需要切换数据库的方法增加注解 85@RequestMapping("/a/b/") 86public class XXController{ 87 @RequestMapping(value = "list") 88 @DBChangeAnno //增加此注解表示该业务需根据用户所在机构切换不同数据库连接 89 public Obj list(){ 90 return new Object;//具体业务逻辑编写 91 } 92} 93 94//参考文章: 95https://www.jianshu.com/p/6b203f4926d5 96https://www.cnblogs.com/haha12/p/10613549.html
点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

Twitter的分布式自增ID算法snowflake (Java版)

概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移