Springboot实现根据用户ID切换动态数据源

首先在application.yml 文件添加一下配置 

#每个库可连接最大用户数
dynamic-server:
  #每个服务最大建库数
  database-max-number: 30
  #每个库最大用户连接数
  user-max-number: 200
  template: gis_template

然后项目中添加 dynamicds 模块的代码,仅展示模块文件目录,代码太多不展示了

然后添加拦截器


    @Override
    public void addInterceptors(InterceptorRegistry registry){
        //排除登录注册拦截
        List<String> patterns = new ArrayList<>();

        patterns.add("/doc.html");
        patterns.add("/js/**");
        patterns.add("/webjars/**");
        patterns.add("/swagger-resources/**");
        patterns.add("/unify-resource/**");
        patterns.add("/unify-auth/oauth/token");
        patterns.add("/unify-auth/register");
        patterns.add("/unify-resource/**");
        patterns.add("/rabbit/**");
        //默认数据源 不需要切换的 排除
        registry.addInterceptor(dynamicDataSourceInterceptor()).addPathPatterns("/**")
                .excludePathPatterns(patterns).order(1);
      //  registry.addInterceptor(dynamicDefaultDataSourceInterceptor()).addPathPatterns("/**").order(-1);
    }

    @Bean
    public DynamicDataSourceInterceptor dynamicDataSourceInterceptor(){
        return new DynamicDataSourceInterceptor();
    }

动态数据源拦截器

跟据token 获取用户id 再根据用户id切换对应数据源 


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.gis.dynamicds.cache.DynamicDataSourceCache;
import org.springblade.gis.dynamicds.datasource.MyDynamicDataSource;
import org.springblade.gis.dynamicds.service.DynamicDataSourceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * file:DynamicDataSourceInterceptor
 * <p>
 * 文件简要说明
 *
 * @author 2021-10-28 tarzan 创建初始版本
 * @version V1.0  简要版本说明
 */
public class DynamicDataSourceInterceptor implements HandlerInterceptor {
    private static final Logger log = LoggerFactory.getLogger(DynamicDataSourceInterceptor.class);
    @Autowired
    private MyDynamicDataSource dynamicDataSource;
    @Autowired
    private DynamicDataSourceCache dynamicDataSourceCache;
    @Autowired
    private DynamicDataSourceService dynamicDataSourceService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)  {
        //获取当前登录用户信息
        BladeUser user = AuthUtil.getUser();
     /*   if(user == null || user.getUserId() == null){
            throw new UnauthorizedException(ErrorEnum.E_401);
        }*/
        log.info("据源切换--------------用户名-----"+user.getUserName()+"------------>【{}】", user.getUserId());
        //如果未获取到 dsName 重新加载数据库
        if(!dynamicDataSourceCache.hasDataSourceName(user.getUserId())){
            dynamicDataSourceService.addUserDataSource(user.getUserId());
        }
        String dsName = dynamicDataSourceCache.getUserIdDataSourceName(user.getUserId());
        if(!dynamicDataSource.switchDataSource(dsName)){
            //如果切换数据源失败 返回错误
            throw new RuntimeException("未找到用户数据库");
        }
        return true;
    }

}

数据库设计

dynamicDataSource:
  default:
    url: jdbc:postgresql://${POSTGRES_HOST:172.16.10.201}:${POSTGRES_PORT:5432}/${POSTGRES_DATABASE:gis_db}
    username: ${POSTGRES_USERNAME:postgres}
    password: ${POSTGRES_PASSWORD:postgres}
    driverClassName: org.postgresql.Driver
    pool:
      #最小空闲连接
      minimum-idle: 2
      #最大连接
      maximum-pool-size: 3
      # 空闲连接存活最大时间,默认600000(10分钟)
      idle-timeout: 1200000
      # 据库连接超时时间,默认30秒
      connection-timeout: 300000

初始链接一个基础数据库,放置用户表,数据源表,数据库表

数据库表建表语句

CREATE TABLE "public"."data_server_database" (
  "id" int8 NOT NULL,
  "data_source_key" varchar(128) COLLATE "pg_catalog"."default" NOT NULL,
  "database_name" varchar(128) COLLATE "pg_catalog"."default" NOT NULL,
  "source_id" int8 NOT NULL,
  "create_time" timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
  "update_time" timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
  "priority" int4 NOT NULL,
  "amount" int4 NOT NULL DEFAULT 0,
  "status" int2 NOT NULL DEFAULT 2
)
;
COMMENT ON COLUMN "public"."data_server_database"."id" IS '主键';
COMMENT ON COLUMN "public"."data_server_database"."data_source_key" IS '数据源连接唯一key';
COMMENT ON COLUMN "public"."data_server_database"."database_name" IS '数据库名';
COMMENT ON COLUMN "public"."data_server_database"."source_id" IS '数据源id(data_server_source表主键id)';
COMMENT ON COLUMN "public"."data_server_database"."create_time" IS '创建时间';
COMMENT ON COLUMN "public"."data_server_database"."update_time" IS '更新时间';
COMMENT ON COLUMN "public"."data_server_database"."priority" IS '数据库使用顺序(升序)';
COMMENT ON COLUMN "public"."data_server_database"."amount" IS '数据使用用户数量';
COMMENT ON COLUMN "public"."data_server_database"."status" IS '使用状态(1:正在使用;2:本库使用用户数已满)';
COMMENT ON TABLE "public"."data_server_database" IS '用户连接的数据库配置';

-- ----------------------------
-- Uniques structure for table data_server_database
-- ----------------------------
ALTER TABLE "public"."data_server_database" ADD CONSTRAINT "source_key_unique" UNIQUE ("data_source_key");
COMMENT ON CONSTRAINT "source_key_unique" ON "public"."data_server_database" IS '数据源名 唯一';

-- ----------------------------
-- Primary Key structure for table data_server_database
-- ----------------------------
ALTER TABLE "public"."data_server_database" ADD CONSTRAINT "data_server_source_pkey" PRIMARY KEY ("id");

数据源表建表语句 

CREATE TABLE "public"."data_server_source" (
  "id" int8 NOT NULL,
  "driver_class_name" varchar(128) COLLATE "pg_catalog"."default" NOT NULL,
  "url" varchar(255) COLLATE "pg_catalog"."default" NOT NULL,
  "user_name" varchar(64) COLLATE "pg_catalog"."default" NOT NULL,
  "password" varchar(128) COLLATE "pg_catalog"."default" NOT NULL,
  "create_time" timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
  "update_time" timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
  "priority" int4,
  "amount" int4 DEFAULT 0,
  "status" int2 DEFAULT 2
)
;
COMMENT ON COLUMN "public"."data_server_source"."id" IS '主键';
COMMENT ON COLUMN "public"."data_server_source"."driver_class_name" IS '数据库驱动';
COMMENT ON COLUMN "public"."data_server_source"."url" IS '数据库连接url';
COMMENT ON COLUMN "public"."data_server_source"."user_name" IS '数据库用户名';
COMMENT ON COLUMN "public"."data_server_source"."password" IS '数据库用户密码';
COMMENT ON COLUMN "public"."data_server_source"."create_time" IS '创建时间';
COMMENT ON COLUMN "public"."data_server_source"."update_time" IS '更新时间';
COMMENT ON COLUMN "public"."data_server_source"."priority" IS '数据库服务使用顺序(升序)';
COMMENT ON COLUMN "public"."data_server_source"."amount" IS '数据服务建库数量';
COMMENT ON COLUMN "public"."data_server_source"."status" IS '使用状态(1:正在使用;2:本服务建库数已满)';
COMMENT ON TABLE "public"."data_server_source" IS '数据库服务的数据源连接表';

-- ----------------------------
-- Records of data_server_source
-- ----------------------------
INSERT INTO "public"."data_server_source" VALUES (2, 'org.postgresql.Driver', 'jdbc:postgresql://localhost:5432/', 'hgl', 'hgl', '2021-11-01 14:53:45', '2021-11-01 14:53:47', 2, 0, 2);
INSERT INTO "public"."data_server_source" VALUES (1, 'org.postgresql.Driver', 'jdbc:postgresql://172.16.10.201:5432/', 'postgres', 'postgres', '2021-11-01 14:53:45', '2021-11-01 14:53:47', 1, 3, 1);
INSERT INTO "public"."data_server_source" VALUES (5, 'org.postgresql.Driver', 'jdbc:postgresql://172.16.10.6:5432/', 'hgl', 'hgl', '2021-11-01 14:54:12', '2021-11-01 14:54:14', 10, 0, 2);
INSERT INTO "public"."data_server_source" VALUES (10, 'org.postgresql.Driver', 'jdbc:postgresql://172.16.10.72:5432,172.16.10.73:5432/', 'postgres', 'pgpg', '2021-11-01 14:54:12', '2021-11-01 14:54:14', 10, 0, 2);

-- ----------------------------
-- Primary Key structure for table data_server_source
-- ----------------------------
ALTER TABLE "public"."data_server_source" ADD CONSTRAINT "data_server_source_pkey1" PRIMARY KEY ("id");

用户表 省略,就是常规用户表,加上 数据库id外键即可

注册用户时,

调用DynamicDataSourceService类的getDatabaseId() 方法,将用户和数据库绑定。

      entity.setDatabaseId(dataSourceService.getDatabaseId());

getDatabaseId() 讲解 根据配置的数据库最大用户数配置,方法内部判断当前数据库用户数是否大于配置用户,没有则返回当前数据库id,有则返回下一个数据库id

使用方法,调用接口时候,传入token ,动态数据库拦截器,自动获取用户id,切换对应数据源。 

到此这篇关于Springboot实现根据用户ID切换动态数据源的文章就介绍到这了,更多相关Springboot切换动态数据源内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Springboot动态切换数据源的具体实现与原理分析

    目录 前言 具体实现: 原理分析: 总结 前言 在springboot项目中只需一句代码即可实现多个数据源之间的切换: // 切换sqlserver数据源: DataSourceContextHolder.setDataBaseType(DataSourceEnum.SQLSERVER_DATASOURCE); ...... // 切换mysql数据源 DataSourceContextHolder.setDataBaseType(DataSourceEnum.MYSQL_DATASOURCE)

  • SpringBoot Mybatis动态数据源切换方案实现过程

    背景 最近让我做一个大数据的系统,分析了一下,麻烦的地方就是多数据源切换抽取数据.考虑到可以跨服务器跨数据库抽数,再整理数据,就配置了这个动态数据源的解决方案.在此分享给大家. 实现方案 数据库配置文件 我们项目使用的是yml形式的配置文件,采用的是hikari的数据库连接池.第一步我们自然是配置多个数据库源头. 我们找到spring的datasource,在下方配置三个数据源. spring: application: name: dynamicDatasource datasource: t

  • 详解SpringBoot+Mybatis实现动态数据源切换

    业务背景 电商订单项目分正向和逆向两个部分:其中正向数据库记录了订单的基本信息,包括订单基本信息.订单商品信息.优惠卷信息.发票信息.账期信息.结算信息.订单备注信息.收货人信息等:逆向数据库主要包含了商品的退货信息和维修信息.数据量超过500万行就要考虑分库分表和读写分离,那么我们在正向操作和逆向操作的时候,就需要动态的切换到相应的数据库,进行相关的操作. 解决思路 现在项目的结构设计基本上是基于MVC的,那么数据库的操作集中在dao层完成,主要业务逻辑在service层处理,controll

  • SpringBoot 自定义+动态切换数据源教程

    目录 1.添加maven依赖 2.配置application.yml 3.配置动态数据源 4.配置数据源操作Holder 5.读取自定义数据源,并配置 6.动态切换关键--AOP进行切换 7.使用 1).配置mapper 2).配置service 3).单元测试调用 4).测试结果 1.添加maven依赖 <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</ar

  • Springboot实现根据用户ID切换动态数据源

    首先在application.yml 文件添加一下配置  #每个库可连接最大用户数 dynamic-server: #每个服务最大建库数 database-max-number: 30 #每个库最大用户连接数 user-max-number: 200 template: gis_template 然后项目中添加 dynamicds 模块的代码,仅展示模块文件目录,代码太多不展示了 然后添加拦截器 @Override public void addInterceptors(InterceptorR

  • SpringBoot整合MyBatisPlus配置动态数据源的方法

    MybatisPlus特性 •无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑 •损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作 •强大的 CRUD 操作:内置通用 Mapper.通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求 •支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错 •支持多种数据库:支持 MySQL.MariaDB.Ora

  • Spring Boot 动态数据源示例(多数据源自动切换)

    本文实现案例场景: 某系统除了需要从自己的主要数据库上读取和管理数据外,还有一部分业务涉及到其他多个数据库,要求可以在任何方法上可以灵活指定具体要操作的数据库. 为了在开发中以最简单的方法使用,本文基于注解和AOP的方法实现,在spring boot框架的项目中,添加本文实现的代码类后,只需要配置好数据源就可以直接通过注解使用,简单方便. 一配置二使用 1. 启动类注册动态数据源 2. 配置文件中配置多个数据源 3. 在需要的方法上使用注解指定数据源 1.在启动类添加 @Import({Dyna

  • Java注解实现动态数据源切换的实例代码

    当一个项目中有多个数据源(也可以是主从库)的时候,我们可以利用注解在mapper接口上标注数据源,从而来实现多个数据源在运行时的动态切换. 实现原理 在Spring 2.0.1中引入了AbstractRoutingDataSource, 该类充当了DataSource的路由中介, 能有在运行时, 根据某种key值来动态切换到真正的DataSource上. 看下AbstractRoutingDataSource: 复制代码 代码如下: public abstract class AbstractR

  • Spring实现动态切换多数据源的解决方案

    前言 Spring动态配置多数据源,即在大型应用中对数据进行切分,并且采用多个数据库实例进行管理,这样可以有效提高系统的水平伸缩性.而这样的方案就会不同于常见的单一数据实例的方案,这就要程序在运行时根据当时的请求及系统状态来动态的决定将数据存储在哪个数据库实例中,以及从哪个数据库提取数据. Spring2.x以后的版本中采用Proxy模式,就是我们在方案中实现一个虚拟的数据源,并且用它来封装数据源选择逻辑,这样就可以有效地将数据源选择逻辑从Client中分离出来.Client提供选择所需的上下文

  • 通过springboot+mybatis+druid配置动态数据源

    一.建数据库和表 1.数据库demo1放一张user表 SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for user -- ---------------------------- DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` int(11) NOT NULL, `name` varchar(255) DEFAULT NU

  • mybatis plus动态数据源切换及查询过程浅析

    mybatis plus多数据源切换 mybatis plus多数据源切换使用注解 @DS DS注解作为多数据源切点,具体实现作用主要由两个类完成 DynamicDataSourceAnnotationAdvisor DynamicDataSourceAnnotationInterceptor DS多数据源切换实现 1.DynamicDataSourceAnnotationAdvisor类实现切面配置,其中AnnotationMatchingPointcut用于寻找切点,进入可看到支持类和方法的

  • springboot 动态数据源的实现方法(Mybatis+Druid)

    Spring多数据源实现的方式大概有2中,一种是新建多个MapperScan扫描不同包,另外一种则是通过继承AbstractRoutingDataSource实现动态路由.今天作者主要基于后者做的实现,且方式1的实现比较简单这里不做过多探讨. 实现方式 方式1的实现(核心代码): @Configuration @MapperScan(basePackages = "com.goofly.test1", sqlSessionTemplateRef = "test1SqlSess

随机推荐