Redis緩存數(shù)據(jù)庫SaaS多租戶實現(xiàn)方案_第1頁
Redis緩存數(shù)據(jù)庫SaaS多租戶實現(xiàn)方案_第2頁
Redis緩存數(shù)據(jù)庫SaaS多租戶實現(xiàn)方案_第3頁
Redis緩存數(shù)據(jù)庫SaaS多租戶實現(xiàn)方案_第4頁
Redis緩存數(shù)據(jù)庫SaaS多租戶實現(xiàn)方案_第5頁
已閱讀5頁,還剩9頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領

文檔簡介

1、Redis緩存數(shù)據(jù)庫SaaS多租戶實現(xiàn)方案刖誇上2個童節(jié)已經(jīng)實現(xiàn)了mysql和MongoDB的多租戶切實現(xiàn)方宰.本童將繼續(xù)學習Redis的多數(shù)據(jù)源切換.Redis服務器默認有16個 database,我們可以將每個租戶的數(shù)據(jù)放到M中一個database中,也可以部詈多臺Redis服務器,每個租戶使用YRedis服務器,也可 城兩者結(jié)合起來,Redis服務騎部菩多臺,先在一臺的16個Database上放,放滿了 16個Database然后再往下一臺Redis服務器上放這 種方式需要有一個MySQ虜據(jù)陣表存儲每臺Redis服務器的Database使用情況,這個實現(xiàn)方式也很筒單,就不在本文中進行實現(xiàn)

2、了,還是 主要介紹本次的重點Redis多城源的切換.二.實現(xiàn)方案既然前面已經(jīng)有了MySQLftlMongoDB的實現(xiàn)方垂,Redis的實現(xiàn)方室也很清時了,Redis的實現(xiàn)方宰與MongoDB的方室很類似,只是 MongoDB使用的數(shù)據(jù)源,而Redis使用的是連接工廠RedisConnectionFactory.1、首先我們需要一個Map來保存各租戶與Redis連接工廠的映射關系時候設遷到當前餞程中.3. 因為我們使用Redi曲時候,F(xiàn)是使用RedisTemplate來對RedisSt據(jù)庫逬行提作,所以我%血iARedisTemplate這個bean的時候,不能使 用默認的RedisTempla

3、te,要使用我們目走義的MultiRedisTemplate,這個MultiRedisTemplateii麗目RedisTemplate4、我們再MultiRedisTemplate中要重寫RedisTemplate的getConnectionFactoryO方法,從當前皴程中獲取到RedisConnectionFactory,這樣當前餞程切換瓷源后,我們使用的RedisTemplate也就目動切換了數(shù)據(jù)源.三.準備為了演示簡單,我們就使用一臺Redis服務器的2個database, 一個是db1-個db2當切換數(shù)據(jù)源的時候,同一條數(shù)據(jù)會被插入到不同的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另外,我們需要更新上一個童節(jié)的存儲租戶數(shù)據(jù)源的庫,將Redi啲數(shù)據(jù)源配置加入到表里面.所以我們需要給tenant_datasource表增加 redis_hostx redisport. redis password. redis_databasei4個字段保存Redis的IP、端口、密碼和數(shù)據(jù)庫這些連接信息 執(zhí)

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的連接字符配呂到表中,執(zhí)行的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>由于數(shù)據(jù)源是配冒在mysql數(shù)據(jù)庫中,所以本次application.yml文件不需要動2. (§K$f$l!tTenantDatasource.ja

22、va增加屬性redisHost% redisPort、redisPassword和redisDatabase.見下面紅色字體內(nèi)容 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數(shù)據(jù)源上下文切換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數(shù)據(jù)斥上下文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確保在一個綬秤內(nèi)使用同一個Redis連接匸廠private stalk final ThreadLocal<RedisConnectionFactory> REDIS DB FACTORY THR£AD_ LOCAL = new ThreadLocal<>0;從Mysq數(shù)據(jù)冷中査詢出所有的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;制除片前找程的數(shù)據(jù)源public static gid removeRedisDbFactoryO REDIS_DB FACTORY_ THR£AD_LOCAL remove 根撫redis數(shù)號庫連接信息創(chuàng)建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敎罄庫連接信息創(chuàng)建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);設豐默認便用的數(shù)抿陳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多數(shù)據(jù)源配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數(shù)據(jù)源的切換具體見代碼紅色郡分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) 如果是當前不存在的敎據(jù)源.則淹加這個數(shù)據(jù)源if(!dynamicDataSourcc.existTenantKey(tenantKey)TenantDatasource db = datasourccScrvkc.getOne(ncw LambdaQueryWrapper<TenantDatasourceO eq(TenantDatasource:g

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論