Redis缓存数据库SaaS多租户实现方案_第1页
Redis缓存数据库SaaS多租户实现方案_第2页
Redis缓存数据库SaaS多租户实现方案_第3页
Redis缓存数据库SaaS多租户实现方案_第4页
Redis缓存数据库SaaS多租户实现方案_第5页
已阅读5页,还剩9页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Redis缓存数据库SaaS多租户实现方案刖誇上2个童节已经实现了mysql和MongoDB的多租户切实现方宰.本童将继续学习Redis的多数据源切换.Redis服务器默认有16个 database,我们可以将每个租户的数据放到M中一个database中,也可以部詈多台Redis服务器,每个租户使用YRedis服务器,也可 城两者结合起来,Redis服务騎部菩多台,先在一台的16个Database上放,放满了 16个Database然后再往下一台Redis服务器上放这 种方式需要有一个MySQ虜据阵表存储每台Redis服务器的Database使用情况,这个实现方式也很筒单,就不在本文中进行实现

2、了,还是 主要介绍本次的重点Redis多城源的切换.二.实现方案既然前面已经有了MySQLftlMongoDB的实现方垂,Redis的实现方室也很清时了,Redis的实现方宰与MongoDB的方室很类似,只是 MongoDB使用的数据源,而Redis使用的是连接工厂RedisConnectionFactory.1、首先我们需要一个Map来保存各租户与Redis连接工厂的映射关系时候设迁到当前饯程中.3. 因为我们使用Redi曲时候,F是使用RedisTemplate来对RedisSt据库逬行提作,所以我%血iARedisTemplate这个bean的时候,不能使 用默认的RedisTempla

3、te,要使用我们目走义的MultiRedisTemplate,这个MultiRedisTemplateii丽目RedisTemplate4、我们再MultiRedisTemplate中要重写RedisTemplate的getConnectionFactoryO方法,从当前皴程中获取到RedisConnectionFactory,这样当前饯程切换瓷源后,我们使用的RedisTemplate也就目动切换了数据源.三.准备为了演示简单,我们就使用一台Redis服务器的2个database, 一个是db1-个db2当切换数据源的时候,同一条数据会被插入到不同的databasee0 RDM GUI fo

4、r Redis® 2021.2O连接到Redis服 T* dbO (0)XJr 17 )Av ooouo( lf /V /l /k /k z/v /0 12 3 4 5 23456/89111111 bbbbbbbbbbbbbb dddddddddddddd另外,我们需要更新上一个童节的存储租户数据源的库,将Redi啲数据源配置加入到表里面.所以我们需要给tenant_datasource表增加 redis_hostx redisport. redis password. redis_databasei4个字段保存Redis的IP、端口、密码和数据库这些连接信息 执

5、行的sql如下:alter table ten antdatasource add column redis_host VARCHAR(512);alter table tenant datasource add column redis port int;alter table tenant datasource add column redis_password VARCHAR(50);alter table tenant datasource add column redis_database int;然后将2个MongoDB的连接字符配呂到表中,执行的sql如下:update tena

6、nt datasource set redis host = ** jedisport =6379,redis_password ='123456* jedis database =1 where tenant_key=*te nant_one:update tenant datasource set redis host = ** jedis_port =6379edis_password ='123456* jedis database =2 where tenant_key=*te nant_two:A_uu.ledv人 U£

7、S.K、VUJSV3 一 0& ZAUOJSJOA V APz>Jtere、vw<>ed,Qt£slooq6uudsAP-pe±t:ev AP-dnoJ6、v4-*ooq4OAA2lue+6uuds6OAP_dnal6vAGOJedvAuoqduxopvseesOJtQEQ.OUJQaAU.2.5.l>5upvAuEI>u、volu2pllueu27-p-nuJA:MUPU VAcosvo-; U.25.WA V人 p-pe七匸 e、vqpo6UOE-bsAElueu2TP-nul APz:>eJtet:e:> 人 p-dn

8、a!6、VUJeu2k2-duJex2E0VAP-dnQI6vA U.2SJOAPPOEV0 0 令 A uofEAPPOUl VA- P5X.O.OV u aAeul、psx、poxpedquaAmul、uda00p、2od、6.loulpedquaApul、Q.=F HU.2_exrleuJux:>5.L:5x.u2unsu.euloq 勺迄 x/LOOZ'BOcnMMMM/'sdHF 巴5?<511-0|< oop、wod、0oOMv&QUOAeul、Q.=F Hsu-ulx 一 xfaldvA 8-din. M6U-POXJO 0 厂 -Exv

9、7暑仪WOd界 CSHl -專&Eodss 一 paNY-nn-HawlEodEwTO 弭»:g図怵g雇哀怜眩掘匚ffiEQlr噪nl?假®±=梓直墨z扯 星巨 an g 9H, ffc f > tt e - 5VRS m I 09 «E0 ts V09SS *e?ts A CK S0.O % mjnX SSA X is A X &XA i s 52wl.si M L !3 Ms 5 U5 A u.2sg、V E0 L;U.25JQA VAp-pe±te、v2tet;,looq 6 uyds,p-nJPAP=3e±

10、;t:ev 人 p_dnoJ6veqeq=p UJO:>A32dnal6vAAXJopuodQpv AuopuodopvA pzveste、V d oe <Dte4s4Looq 6wd s 人 p二吊七te V AP_dnoJ6、xooq-xOM2Ee 上 6u-ds 6OA32dnol6v 人 AXJopuodopv A:#圧 dow_s;vA &UOPU odopv A pzve七 t e、V q<Dvl2tret;4Looq 6u-ds A p 二吊七匸 e V A pQ.n oi 6、V - o oq-ifOMQlu e 上 6 u p d s 6 j o A

11、32d n oi 6 VAAXIQpuodopv人uopuodop'v Apzv昱t:e、vqpo6UOEe4ep,.l2tet;2-ooq6wdsAP=J±t:ev 人2dn QJ6、v4ooq-ifOM2lue 上 6uyds 6oc32dnol6v人 AxlopuodopvAsgxlopuodupvAoftodoldv AUoTg 一ooq 6.Eds、v3s<naa:oE ZAU.2TOA 一 ooq6uudsv 人 6.Epovu3yuhno6.Etodar>0f2d、v8u.ln 人 6.EPOMlUJ5d3o6.£t:odQ.r 一 Eol

12、dv AbEpsusollnos pl3qpofald、v®dlDA6.Epo2uIJUo>lno5 pl-nq 一 x>OJdvCUO&JQAgpf、v8;UOIS.WA CAefvctuodaldv</dcpcndcncy><dcpcndcrKy><grouptd>com.baomidou</groupld><artifMtld>mybatis-plus-boot-starter</artrfactld><vcrs»n>3.3.1</VDrsion><

13、;/dependency ><dcpcndcrKy><groupld>coni.baomidou</groupld><artifactld>mybatis-plus-generator</artifactld>< versio n>3.3.1 </ucrsio n ></dcpcndcncy><!-mysq!-><dcpcndcrKy><groupld>mysql</groupld><artifactld>mysql-c onn ec

14、tor-java </a rt ifac t Id ></dependency ><dcpcndcrKy><groupld >jectlombok</groupld ><artifactld>lombok</artifactld></dependency ><dcpcndcfKy><groupld>junit</groupld><artifactld>j un it</artifactld>< versb n>4.

15、12</version ></dependency ></- Redi,相关依検-><dcpcndcrKy><groupld >org.springframework.boot</groupld ><artifactld >spring bo ot-starterdataredisv/artifaitld></dependency ><A-如果使用Lettue作为连接池需耍引入commons-poo!2包.否則会报fUbean注入失败-> <dcpcndctKy><

16、;groupld >mons</groupld ><artifactld>commons-pool2</artifactld></dependency ><dcpcndcfKy><groupld>redis.clients</groupld><artifactld>jedis</artifactld>< vcrsk)n>3.1.0</vcrsk)n></dependency ><dcpcndcrKy><groupld>co

17、m.alibaba</groupld><artifactld>fastjson</artifactld>< vcrs»n>1.2.76</vcrs»n></dependency ><dcpcndcrKy><groupld>org.spnngframework.boot</groupld ><artifactld>spring-boot-starter-test</artifactld>< sco pc > test </sco

18、 pc ><cxclu£ion£><cxclu£ion><groupld >org.junit.vi ntage«/groupld ><artifactld>junit-vintage-e nginev/artifa<tld> </cxdusion></cxclusions></dcpcndcncy></dcpcndcncics>< dcpcndcncyM a nagcmcnt ><dcpcndcrKics>&l

19、t; dependency ><groupld>org.springframework.boot</groupld><artifactld>spring-boot-depe ndenciesv/artifactld <vcrsion>$spring boot>/ersion</vcMionA< typo pom </typc><scopc>import</scopc></dcpcndcncy>v/dcpcndcfK ics ></dependency Ma nag

20、cmcnt ><plugins><plugin><groupld>org.apache.maven.plugins</groupld> <artifactld> maven-compiler-plugin </artifact Id > <configuration>< sourcc>1 8</sourcc>< target > 1.8</targct ><cncoding>UTF-8</cncoding></configura

21、tk>n></plugin><plugin><groupld>org.springframework.boot</groupld> <artifactld>spring-boot-maven-plugin</artifactld> </plugin></plugins></build> </projcct>由于数据源是配冒在mysql数据库中,所以本次application.yml文件不需要动2. (§K$f$l!tTenantDatasource.ja

22、va增加属性redisHost% redisPort、redisPassword和redisDatabase.见下面红色字体内容 package com.example.te nant. entity;import com.baomidou.mybatisplus.annotationdType;import com.baomidou.mybatisplus.annotation.Tableld;import com baomidou.mybatisplus.annotation.TableName;import lombok.Data;import java.io.Serializable;

23、import java.util.Date;DataTableName( Icnant datasource )public class TenantDatasource implements Serializable private static final long serilVenionUID 1L;Tableld(value = Id : type = dlype.AUTO)private Integer id;private String tenant Key;private Integer tcnantiypc;private String url;private String m

24、ongoUri;private String username;private String password;private Boolean active;private Date crcatcdTimc;private Date updatedTime;private String redisHost;private int redisPort;private String redisPassword;private int redisDatabase;3、増加Redis数据源上下文切换RedisConfigpackage com.example.tenant.config.redis;i

25、mport com.alibaba.fastjson.supportspring.FastlsonRedisSerializer;import com.example.tenant.dto.TenantDatasourceDTO;import com.example.tenantentity.TenantDatasource;import com.example.tenant.service.TenantDatasourceService;import lombok.extern.slf4j.Slf4j;import org mons.pool2.impl.GenericObjectPoolC

26、onfig;import org pringframworkBanlltik;import org.springframework.beans.factory.annotation.Autowired;import perties.Configurati on Properties;import org.springframework.contextannotation.Bean;import org springframework.context.annotation.Configuration;import org.sp

27、ringframework data.redis.connection.RedisConnectionFactory;import org.springframework-data.redis.connection.RedisPassword;import org springframework.data.redis.connection.RedisStandaloneConfiguration;import org.springframework.data.redis.connection.lettuce.LettuceCliereconfiguration;import org sprin

28、gframework.data.redis.connection.lettuce.LettuceConnectionFactory;import org.springframework.data.redis.connection.lettuce.LettucePoolingCliertConfiguration;import org.springframeworlGdata.redis.serializer.StringRedisSerializer;import javax.a nnotation.PostConstruct;import java.util.HashMap;import j

29、ava.util.lterator;import java.util.List;import java.util.Map;严 Redis数据斥上下文7©ConfigurationSlf4jpublic class RedisConfig Auto wiredprivate Ten antDatasourceService tenant Data so urccScr vice;使用Map保布租户ID号Redi就接工厂的映肘关系public static Map<Stri ng, RedisC onn ection FactoryredisConnectionFactoryMap

30、 = new HashMap<String, RedisConnectionFactoryAO;通过Threadbcal确保在一个綬秤内使用同一个Redis连接匸厂private stalk final ThreadLocal<RedisConnectionFactory> REDIS DB FACTORY THR£AD_ LOCAL = new ThreadLocal<>0;从Mysq数据冷中査询出所有的Redis连接信息并耐釣Map中 PostConstructpublic void initRedisTempO throws Exception /

31、.info(START 初始化 Rcdis 连接池 STARTED* );List<TenantDatasource> tenantlnfoUst = tcnantDatasourccScrvicc.listO;for (TenantDatasource info : tenantlnfoUst) TenantDatasourceDTO tenantDatasourceDTO = new TenantDatasourceDTOO;BeanJ.copyProperties(nQt tenantDatasourceDTO); redisConnectionFactoryMapjpnio

32、.geenantKeyO, getRedisConnectonFactory(info);END 初始化 Rcdis 连接池 END 六W获取当前找程的edi泄接i:rpublic static RedisConnectionFactory getRedisDbFactoryO return REDIS_DB_FACTORY_ THR£AD_LOCALgetQ;设置当前找程的redi泄接l:rpublic static oid setRedisDbFactory(String name) REDIS DB FACTORY THREAD LOCAL.seUredisConMCtionF

33、actoryMap.gEUzmE;制除片前找程的数据源public static gid removeRedisDbFactoryO REDIS_DB FACTORY_ THR£AD_LOCAL remove 根撫redis数號库连接信息创建redis连接1:厂public RedisConnectionFactory getRedisConnectionFactoryfTenantDatasource info) throws Exception GenericObjectPoolConfig genericObjectPoolConfig = redisPoolO;Lettuce

34、ConnectionFactory lettuceConnectionFactory = redisConnectionFactory(genericObjectPoolConfig, info); lettuceC onn ectio nF actory.afterPropertiesSetO;return lettuceConnectionFactory;根撫redis敎罄库连接信息创建LettuceConnectionFactory连接匸厂public LettuceCon nectionFactory redisC on nectionFactory(GenericObjectPool

35、Config con fig, Tena ntDatasouixe info) /甲机箴jedisRedistandaloneConfiguration redisStandaloneConfiguration 二 new RedisStandaloneConfigurationO;设置redis服务器的hos诫者ip地址redisStandalo neCon figuratio netHostName(info.getRedisHostO);设豐默认便用的数抿陈redisStandalo neCon figuratio netDatabase(info.getRedisDatabaseO);

36、设賈擀码redisStandalo neCon figuratio nsetPassword(RedisPassword.o/(infogetRedisPassword();设Bredis的服务的端口号redisStandalo neCon figuratio nsetPort(i nf o.getRedisPortO);LettuceClientConfiguration clientConfiguration =LettucePoolingClientConfiguration.b(/Xt/erOpoolConfig(config).buildO;return new LettuceCon

37、nectionFactory(redisStandaloneConfiguration, clientConfiguration);俨配展lettuce连接池©BeanConfigurationProperties(prefix = Spring.redis.lcttucc.pooI *)public GenericObjectPoolConfig redisPoolO return new GenericObjectPoolConfig< >0;注入redisTemplate bean名称为edisTemplati bean从Map中获取默认使用第一个将redisTem

38、plate封装为口定义的MuitiRedisTemplate对魚.并配侵序列化Bean(name = VcdisTcmplatc *)public MultiRedisTemplate dynamicRedisTemplateO lterator<RedisConnectionFactory> iterator = redisConnect/onFacto/yMap.valuesO.iteratorQ; MultiRedisTemplate template = new MultiRedisTemplate(iterator.next。); template.setKeySeria

39、lizer(ncw StringRedisSerializerO); template.setValueSerializerfncw FastJsonRedisSerializer< >(Object.class); template.setHashKeySerializer(ncw StringRedisSerializerO); template.setHashValueSerializerfncw Fastis on RedisSerializer< > (Object.class);return template;4. 増加Redis多数据源配MultiRedi

40、sTemplatepackagc com.example.tenant.config.redis;import org.springframework.data.redis.connection.RedisConnectionFactory;import org springframework.data.redis.core.RedisTemplate;严* 口 定义的 RedisTemplatG.Redis TemplateVpublic class MultiRedisTemplate extends RedisTemplate public MultiRedisTemplate(Redi

41、sConnectionFactory redisConnectionFactory) supcr.setC on nectio nFactory(redisCon nectionFactory);重rj获取redis连接工厂的方法©Overridepublic RedisConnectionFactory getConnectionFactoryO 从当前找程中获取佗dis连接nrRedisConnectionFactory redisDbFactory = RedisCong.get/iedisDbFactoryO;如果从为酋级程获取的连接l:厂为空则使用默认默认连接1:厂如果不为

42、空.则使用找程中的连接匸厂return redisDbFactory = null ? supcr.getConnectionFactory(): redisDbFactory;)5、修改AOP切面,増加Redis数据源的切换具体见代码红色郡分package com.example.tenant.aop;import com.baomidou.mybatisplus.core.conditions.query丄ambdaQueryWrapper;import com.baomidou.mybatisplus.core.toolkit.StringUtils;import com.example

43、.tenantconfig.mongodb.MongoDbContext;import com.example.tenantconfig.mysql.DataSourceContextHolder;import com.example.tenantconfig.mysql.DynamicDataSourxe;import com.example.tena nt config.redis.RedisConfig;import com.example.tenant.dto.TenantDatasourceDTO;import com.example.tenant.entity.TenantData

44、source;import com.example.tenant.servite.TenantDatasouweService;import lombok.extern.slf4j.Slf4j;import org.aspectjangJoinPoint;import org.aspectj.lang.annotation.Aspect;import org.aspectjang.annotation.Before;import org.aspectjang.annotation.Pointcut;import org.springframework.beans.BeanUtils;impor

45、t org.springframework.beans.factory.annotation.Autowired;import org.springframework.core.annotation.Order;import org.springframework.stereotype.Component;import org.springframework.util.ObjectUtils;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.con

46、textrequestServletRequestAttributes;import javax.servlet.http.HttpServletRequest;©Component AspectOrder(2)Slf4jpublic class DataSourceAspect ©Autowiredprivate Dyn amicDataSource dynamic Data Source; Auto wiredprivate Ten antDatasourceService data so urccScr vice;Pointcut( v®annotation

47、(org.£pringframcwork.wcb.bindnnotation.Rcquc£tMapping)|(annotation(org.springframcwork.wcb.bi private void cutControllerO Before( tulControllcrO ?public void before(Joi nPoint join Point) ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.pe/?eQy«t4f

48、fn£x/r«0;HttpServletRequest request = attributes.getRequest();从谕求头获取租户IDString tenantKey = request.getHeader( "TenantKcy ");if (Stringlltils.zkM胎加(tenantKey) 如果是当前不存在的敎据源.则淹加这个数据源if(!dynamicDataSourcc.existTenantKey(tenantKey)TenantDatasource db = datasourccScrvkc.getOne(ncw LambdaQueryWrapper<TenantDatasourceO eq(TenantDatasource:g

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论