当前位置: 首页 > news >正文

长沙房地产网站建设led网站建设

长沙房地产网站建设,led网站建设,外贸网站排行,上手机淘宝网站建设多级缓存 多级缓存a.JVM进程缓存1) Caffeine2) 案例 b.Lua语法1) 变量和循环2) 条件控制、函数 c.多级缓存1) 安装OpenResty2) 请求参数处理3) 查询Tomcat4) Redis缓存预热5) 查询Redis缓存6) Nginx本地缓存 d.缓存同步1) 数据同步策略2) 安装Canal2.a) 开启MySQL主从2.b) 安装… 多级缓存 多级缓存a.JVM进程缓存1) Caffeine2) 案例 b.Lua语法1) 变量和循环2) 条件控制、函数 c.多级缓存1) 安装OpenResty2) 请求参数处理3) 查询Tomcat4) Redis缓存预热5) 查询Redis缓存6) Nginx本地缓存 d.缓存同步1) 数据同步策略2) 安装Canal2.a) 开启MySQL主从2.b) 安装Canal 3) 监听Canal 多级缓存 传统缓存的问题 传统的缓存策略一般是请求到达Tomcat后先查询Redis如果未命中则查询数据库存在下面的问题 请求要经过Tomcat处理Tomcat的性能成为整个系统的瓶颈Redis缓存失效时会对数据库产生冲击 多级缓存方案 多级缓存就是充分利用请求处理的每个环节分别添加缓存减轻Tomcat压力提升服务性能 a.JVM进程缓存 本地进程缓存 缓存在日常开发中启动至关重要的作用由于是存储在内存中数据的读取速度是非常快的能大量减少对数据库的访问减少数据库的压力。我们把缓存分为两类 分布式缓存例如Redis 优点存储容量更大、可靠性更好、可以在集群间共享缺点访问缓存有网络开销场景缓存数据量较大、可靠性要求较高、需要在集群间共享 进程本地缓存例如HashMap、GuavaCache 优点读取本地内存没有网络开销速度更快缺点存储容量有限、可靠性较低、无法共享场景性能要求较高缓存数据量较小 1) Caffeine 导入相关依赖 dependencygroupIdcom.github.ben-manes.caffeine/groupIdartifactIdcaffeine/artifactId /dependency简单学习Caffeine的使用 /*基本用法测试*/ Test void testBasicOps() {// 构建cache对象CacheString, String cache Caffeine.newBuilder().build();// 存数据cache.put(gf, 迪丽热巴);// 取数据 getIfPresentString gf cache.getIfPresent(gf);System.out.println(gf gf);// 取数据如果未命中则查询数据库 getString defaultGF cache.get(defaultGF, key - {// 根据key去数据库查询数据return 柳岩;});System.out.println(defaultGF defaultGF); }Caffeine提供了三种缓存驱逐策略 基于容量设置缓存的数量上限 基于时间设置缓存的有效时间 基于引用设置缓存为软引用或弱引用利用GC来回收缓存数据。性能较差不建议使用。 在默认情况下当一个缓存元素过期的时候Caffeine不会自动立即将其清理和驱逐。而是在一次读或写操作后或者在空闲时间完成对失效数据的驱逐。 2) 案例 案例实现商品的查询的本地进程缓存 利用Caffeine实现下列需求 给根据id查询商品的业务添加缓存缓存未命中时查询数据库给根据id查询商品库存的业务添加缓存缓存未命中时查询数据库缓存初始大小为100缓存上限为10000 在config包下创建Caffeine配置类 Configuration public class CaffeineConfig {Beanpublic CacheLong, Item itemCache() {return Caffeine.newBuilder().initialCapacity(100).maximumSize(10000).build();}Beanpublic CacheLong, ItemStock stockCache() {return Caffeine.newBuilder().initialCapacity(100).maximumSize(10000).build();} }在controller下添加缓存的业务代码使用get (优先查询缓存 若无则查询数据库) Autowired private CacheLong, Item itemCache;Autowired private CacheLong, ItemStock stockCache;GetMapping(/{id}) public Item findById(PathVariable(id) Long id){return itemCache.get(id, key - itemService.query().ne(status, 3).eq(id, key).one()); }GetMapping(/stock/{id}) public ItemStock findStockById(PathVariable(id) Long id){return stockCache.get(id, key - stockService.getById(key)); }b.Lua语法 Lua 是一种轻量小巧的脚本语言用标准C语言编写并以源代码形式开放 其设计目的是为了嵌入应用程序中从而为应用程序提供灵活的扩展和定制功能。官网https://www.lua.org/ 1) 变量和循环 数据类型 数据类型描述nil这个最简单只有值nil属于该类表示一个无效值在条件表达式中相当于false。boolean包含两个值false和truenumber表示双精度类型的实浮点数string字符串由一对双引号或单引号来表示function由 C 或 Lua 编写的函数tableLua 中的表table其实是一个关联数组associative arrays数组的索引可以是数字、字符串或表类型。在 Lua 里table 的创建是通过构造表达式来完成最简单构造表达式是{}用来创建一个空表。 变量 Lua声明变量的时候并不需要指定数据类型 -- 声明字符串 local str hello -- 声明数字 local num 21 -- 声明布尔类型 local flag true -- 声明数组 key为索引的 table local arr {java, python, lua} -- 声明table类似java的map local map {nameJack, age21}访问table -- 访问数组lua数组的角标从1开始 print(arr[1]) -- 访问table print(map[name]) print(map.name)循环 数组、table都可以利用for循环来遍历 遍历数组 -- 声明数组 key为索引的 table local arr {java, python, lua} -- 遍历数组 for index,value in ipairs(arr) doprint(index, value) end遍历table -- 声明map也就是table local map {nameJack, age21} -- 遍历table for key,value in pairs(map) doprint(key, value) end2) 条件控制、函数 函数 定义函数的语法 function 函数名( argument1, argument2..., argumentn)-- 函数体return 返回值 end例如定义一个函数用来打印数组 function printArr(arr)for index, value in ipairs(arr) doprint(value)end end条件控制 类似Java的条件控制例如if、else语法 if(布尔表达式) then--[ 布尔表达式为 true 时执行该语句块 --] else--[ 布尔表达式为 false 时执行该语句块 --] end与java不同布尔表达式中的逻辑运算是基于英文单词 操作符描述实例and逻辑与操作符。 若 A 为 false则返回 A否则返回 B。(A and B) 为 false。or逻辑或操作符。 若 A 为 true则返回 A否则返回 B。(A or B) 为 true。not逻辑非操作符。与逻辑运算结果相反如果条件为 true逻辑非为 false。not(A and B) 为 true。 案例自定义函数打印table 需求自定义一个函数可以打印table当参数为nil时打印错误信息 local function printArr(arr)if (not arr) thenprint(数组不能为空)return nilendfor index, value in ipairs(arr) doprint(value)end endc.多级缓存 OpenResty® 是一个基于 Nginx的高性能 Web 平台用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。具备下列特点 具备Nginx的完整功能基于Lua语言进行扩展集成了大量精良的 Lua 库、第三方模块允许使用Lua自定义业务逻辑、自定义库 1) 安装OpenResty 首先你的Linux虚拟机必须联网 安装开发库 首先要安装OpenResty的依赖开发库执行命令 yum install -y pcre-devel openssl-devel gcc --skip-broken安装OpenResty仓库 你可以在你的 CentOS 系统中添加 openresty 仓库这样就可以便于未来安装或更新我们的软件包通过 yum check-update 命令。运行下面的命令就可以添加我们的仓库 yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo如果提示说命令不存在则运行 yum install -y yum-utils 然后再重复上面的命令 安装OpenResty 然后就可以像下面这样安装软件包比如 openresty yum install -y openresty安装opm工具 opm是OpenResty的一个管理工具可以帮助我们安装一个第三方的Lua模块。 如果你想安装命令行工具 opm那么可以像下面这样安装 openresty-opm 包 yum install -y openresty-opm目录结构 默认情况下OpenResty安装的目录是/usr/local/openresty 看到里面的nginx目录了吗OpenResty就是在Nginx基础上集成了一些Lua模块。 配置nginx的环境变量 打开配置文件 vi /etc/profile在最下面加入两行 export NGINX_HOME/usr/local/openresty/nginx export PATH${NGINX_HOME}/sbin:$PATHNGINX_HOME后面是OpenResty安装目录下的nginx的目录 然后让配置生效 source /etc/profile启动和运行 OpenResty底层是基于Nginx的查看OpenResty目录的nginx目录结构与windows中安装的nginx基本一致 所以运行方式与nginx基本一致 # 启动nginx nginx # 重新加载配置 nginx -s reload # 停止 nginx -s stopnginx的默认配置文件注释太多影响后续我们的编辑这里将nginx.conf中的注释部分删除保留有效部分。 修改/usr/local/openresty/nginx/conf/nginx.conf文件内容如下 #user nobody; worker_processes 1; error_log logs/error.log;events {worker_connections 1024; }http {include mime.types;default_type application/octet-stream;sendfile on;keepalive_timeout 65;server {listen 8081;server_name localhost;location / {root html;index index.html index.htm;}error_page 500 502 503 504 /50x.html;location /50x.html {root html;}} }在Linux的控制台输入命令以启动nginx nginx然后访问页面http://192.168.150.101:8081注意ip地址替换为你自己的虚拟机IP 备注 加载OpenResty的lua模块 #lua 模块 lua_package_path /usr/local/openresty/lualib/?.lua;;; #c模块 lua_package_cpath /usr/local/openresty/lualib/?.so;;; common.lua放在lualib中 -- 封装函数发送http请求并解析响应 local function read_http(path, params)local resp ngx.location.capture(path,{method ngx.HTTP_GET,args params,})if not resp then-- 记录错误信息返回404ngx.log(ngx.ERR, http not found, path: , path , , args: , args)ngx.exit(404)endreturn resp.body end -- 将方法导出 local _M { read_http read_http } return _M释放Redis连接API -- 关闭redis连接的工具方法其实是放入连接池 local function close_redis(red)local pool_max_idle_time 10000 -- 连接的空闲时间单位是毫秒local pool_size 100 --连接池大小local ok, err red:set_keepalive(pool_max_idle_time, pool_size)if not ok thenngx.log(ngx.ERR, 放入redis连接池失败: , err)end end读取Redis数据的API -- 查询redis的方法 ip和port是redis地址key是查询的key local function read_redis(ip, port, key)-- 获取一个连接local ok, err red:connect(ip, port)if not ok thenngx.log(ngx.ERR, 连接redis失败 : , err)return nilend-- 查询redislocal resp, err red:get(key)-- 查询失败处理if not resp thenngx.log(ngx.ERR, 查询Redis失败: , err, , key , key)end--得到的数据为空处理if resp ngx.null thenresp nilngx.log(ngx.ERR, 查询Redis数据为空, key , key)endclose_redis(red)return resp end开启共享词典 # 共享字典也就是本地缓存名称叫做item_cache大小150m lua_shared_dict item_cache 150m; 2) 请求参数处理 OpenResty获取请求参数 OpenResty提供了各种API用来获取不同类型的请求参数 参数格式参数示例参数解析代码示例路径占位符/item/1001# 1.正则表达式匹配 location ~ /item/(\d) { content_by_lua_file lua/item.lua;} #2. 匹配到的参数会存入ngx.var数组中可以用角标获取local id ngx.var[1]请求头id1001– 获取请求头返回值是table类型 local headers ngx.req.get_headers()Get请求参数?id1001– 获取GET请求参数返回值是table类型 local getParams ngx.req.get_uri_args()Post表单参数id1001– 读取请求体ngx.req.read_body() – 获取POST表单参数返回值是table类型local postParams ngx.req.get_post_args()JSON参数{“id”: 1001}– 读取请求体ngx.req.read_body()-- 获取body中的json参数返回值是string类型local jsonBody ngx.req.get_body_data() 案例获取请求路径中的商品id信息拼接到json结果中返回 需求在OpenResty中接收这个请求并获取路径中的id信息拼接到结果的json字符串中返回 修改/usr/local/openresty/nginx/conf中的nginx.conf添加 location ~ /api/item/(\d) #user nobody; worker_processes 1; error_log logs/error.log;events {worker_connections 1024; }http {include mime.types;default_type application/octet-stream;sendfile on;keepalive_timeout 65;#lua 模块lua_package_path /usr/local/openresty/lualib/?.lua;;;#c模块 lua_package_cpath /usr/local/openresty/lualib/?.so;;; server {listen 8081;server_name localhost;location ~ /api/item/(\d) {# 默认的响应类型default_type application/json;# 响应结果由lua/item.luacontent_by_lua_file lua/item.lua;}location / {root html;index index.html index.htm;}error_page 500 502 503 504 /50x.html;location /50x.html {root html;}} }在/usr/local/openresty/nginx中创建lua文件夹创建item.lua文件 -- 获取路径参数 local id ngx.var[1] -- 返回结果 ngx.say({id:..id..,name:SALSA AIR, title:30存行李箱})3) 查询Tomcat nginx内部发送Http请求 nginx提供了内部API用以发送http请求 local resp ngx.location.capture(/path,{method ngx.HTTP_GET, -- 请求方式args {a1,b2}, -- get方式传参数body c3d4 -- post方式传参数 })返回的响应内容包括 resp.status响应状态码resp.header响应头是一个tableresp.body响应体就是响应数据 注意这里的path是路径并不包含IP和端口。这个请求会被nginx内部的server监听并处理。但是我们希望这个请求发送到Tomcat服务器所以还需要编写一个server来对这个路径做反向代理 location /path {# 这里是windows电脑的ip和Java服务端口需要确保windows防火墙处于关闭状态proxy_pass http://192.168.150.1:8081; }封装http查询的函数 可以把http查询的请求封装为一个函数放到OpenResty函数库中方便后期使用 1.在/usr/local/openresty/lualib目录下创建common.lua文件 vi /usr/local/openresty/lualib/common.lua2.在common.lua中封装http查询的函数 -- 封装函数发送http请求并解析响应 local function read_http(path, params)local resp ngx.location.capture(path,{method ngx.HTTP_GET,args params,})if not resp then-- 记录错误信息返回404ngx.log(ngx.ERR, http not found, path: , path , , args: , args)ngx.exit(404)endreturn resp.body end -- 将方法导出 local _M { read_http read_http } return _MJSON结果处理 OpenResty提供了一个cjson的模块用来处理JSON的序列化和反序列化。 1.引入cjson模块 local cjson require cjson2.序列化 local obj {name jack,age 21 } local json cjson.encode(obj)3.反序列化 local json {name: jack, age: 21} -- 反序列化 local obj cjson.decode(json); print(obj.name)案例获取请求路径中的商品id信息根据id向Tomcat查询商品信息 这里要修改item.lua满足下面的需求 1.获取请求参数中的id (已完成)2.根据id向Tomcat服务发送请求查询商品信息3.根据id向Tomcat服务发送请求查询库存信息4.组装商品信息、库存信息序列化为JSON格式并返回 设置反向代理 location /item {proxy_pass http://192.168.200.1:8081; }修改item.lua文件 -- 导入common函数库 local common require(common) local read_http common.read_http-- 导入cjson函数库 local cjson require(cjson)-- 获取路径参数 local id ngx.var[1]-- 查询商品信息 local itemJSON read_http(/item/ .. id, nil)-- 查询库存信息 local stockJSON read_http(/item/stock/ .. id, nil)-- JSON转化为lua的table local item cjson.decode(itemJSON) local stock cjson.decode(stockJSON) -- 组合数据 item.stock stock.stock item.sold stock.sold-- 把item序列化为json 返回结果 ngx.say(cjson.encode(item))Tomcat集群的负载均衡 # tomcat集群配置 upstream tomcat-cluster{hash $request_uri;server http://192.168.200.1:8081;server http://192.168.200.1:8082; }# 反向代理配置将/item路径的请求代理到tomcat集群 location /item {proxy_pass http://tomcat-cluster; }4) Redis缓存预热 添加redis缓存的需求 冷启动与缓存预热 冷启动服务刚刚启动时Redis中并没有缓存如果所有商品数据都在第一次查询时添加缓存可能会给数据库带来较大压力。 缓存预热在实际开发中我们可以利用大数据统计用户访问的热点数据在项目启动时将这些热点数据提前查询并保存到Redis中。 缓存预热 1利用Docker安装Redis docker run --name redis -p 6379:6379 -d redis redis-server --appendonly yes2在item-service服务中引入Redis依赖 dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId /dependency3配置Redis地址 spring:redis:host: 192.168.150.1014编写初始化类 缓存预热需要在项目启动时完成并且必须是拿到RedisTemplate之后。 这里我们利用InitializingBean接口来实现因为InitializingBean可以在对象被Spring创建并且成员变量全部注入后执行。 Component public class RedisHandler implements InitializingBean {Autowiredprivate StringRedisTemplate redisTemplate;Autowiredprivate IItemService itemService;Autowiredprivate IItemStockService stockService;private static final ObjectMapper MAPPER new ObjectMapper();Overridepublic void afterPropertiesSet() throws Exception {// 初始化缓存// 1.查询商品信息ListItem itemList itemService.list();// 2.放入缓存for (Item item : itemList) {// 2.1.item序列化成JSONString json MAPPER.writeValueAsString(item);// 2.2.存入redisredisTemplate.opsForValue().set(item:id: item.getId(), json);}// 3.查询商品库存信息ListItemStock stockList stockService.list();// 4.放入缓存for (ItemStock stock : stockList) {// 4.1.stock序列化成JSONString json MAPPER.writeValueAsString(stock);// 4.2.存入redisredisTemplate.opsForValue().set(item:stock:id: stock.getId(), json);}} }5) 查询Redis缓存 OpenResty的Redis模块 OpenResty提供了操作Redis的模块我们只要引入该模块就能直接使用 引入Redis模块并初始化Redis对象修改/usr/local/openresty/lualib/common.lua文件 -- 导入redis local redis require(resty.redis) -- 初始化redis local red redis:new() red:set_timeouts(1000, 1000, 1000)封装函数用来释放Redis连接其实是放入连接池 -- 关闭redis连接的工具方法其实是放入连接池 local function close_redis(red)local pool_max_idle_time 10000 -- 连接的空闲时间单位是毫秒local pool_size 100 --连接池大小local ok, err red:set_keepalive(pool_max_idle_time, pool_size)if not ok thenngx.log(ngx.ERR, 放入redis连接池失败: , err)end end封装函数从Redis读数据并返回 -- 查询redis的方法 ip和port是redis地址key是查询的key local function read_redis(ip, port, key)-- 获取一个连接local ok, err red:connect(ip, port)if not ok thenngx.log(ngx.ERR, 连接redis失败 : , err)return nilend-- 查询redislocal resp, err red:get(key)-- 查询失败处理if not resp thenngx.log(ngx.ERR, 查询Redis失败: , err, , key , key)end--得到的数据为空处理if resp ngx.null thenresp nilngx.log(ngx.ERR, 查询Redis数据为空, key , key)endclose_redis(red)return resp end案例查询商品时优先Redis缓存查询 需求 1.修改item.lua封装一个函数read_data实现先查询Redis如果未命中再查询tomcat2.修改item.lua查询商品和库存时都调用read_data这个函数 1修改/usr/local/openresty/lua/item.lua文件添加一个查询函数 -- 导入common函数库 local common require(common) local read_http common.read_http local read_redis common.read_redis -- 封装查询函数 function read_data(key, path, params)-- 查询本地缓存redislocal val read_redis(127.0.0.1, 6379, key)-- 判断查询结果if not val thenngx.log(ngx.ERR, redis查询失败尝试查询http key: , key)-- redis查询失败去查询httpval read_http(path, params)end-- 返回数据return val end-- 查询商品信息 local itemJSON read_data(item:id: .. id, /item/ .. id, nil) -- 查询库存信息 local stockJSON read_data(item:stock:id: .. id, /item/stock/ .. id, nil)6) Nginx本地缓存 OpenResty为Nginx提供了shard dict的功能可以在nginx的多个worker之间共享数据实现缓存功能。 开启共享字典在nginx.conf的http下添加配置 # 共享字典也就是本地缓存名称叫做item_cache大小150m lua_shared_dict item_cache 150m; 操作共享字典 -- 获取本地缓存对象 local item_cache ngx.shared.item_cache -- 存储, 指定key、value、过期时间单位s默认为0代表永不过期 item_cache:set(key, value, 1000) -- 读取 local val item_cache:get(key)案例在查询商品时优先查询OpenResty的本地缓存 需求 1.修改item.lua中的read_data函数优先查询本地缓存未命中时再查询Redis、Tomcat2.查询Redis或Tomcat成功后将数据写入本地缓存并设置有效期3.商品基本信息有效期30分钟4.库存信息有效期1分钟 1修改/usr/local/openresty/lua/item.lua文件修改read_data查询函数添加本地缓存逻辑 -- 导入共享词典本地缓存 local item_cache ngx.shared.item_cache-- 封装查询函数 function read_data(key, expire, path, params)-- 查询本地缓存local val item_cache:get(key)if not val thenngx.log(ngx.ERR, 本地缓存查询失败尝试查询Redis key: , key)-- 查询redisval read_redis(127.0.0.1, 6379, key)-- 判断查询结果if not val thenngx.log(ngx.ERR, redis查询失败尝试查询http key: , key)-- redis查询失败去查询httpval read_http(path, params)endend-- 查询成功把数据写入本地缓存item_cache:set(key, val, expire)-- 返回数据return val end2修改item.lua中查询商品和库存的业务实现最新的read_data函数 -- 查询商品信息 local itemJSON read_data(item:id: .. id, 1800, /item/ .. id, nil)-- 查询库存信息 local stockJSON read_data(item:stock:id: .. id, 60, /item/stock/ .. id, nil)其实就是多了缓存时间参数过期后nginx缓存会自动删除下次访问即可更新缓存。 这里给商品基本信息设置超时时间为30分钟库存为1分钟。 因为库存更新频率较高如果缓存时间过长可能与数据库差异较大。 d.缓存同步 1) 数据同步策略 缓存数据同步的常见方式有三种 设置有效期给缓存设置有效期到期后自动删除。再次查询时更新 优势简单、方便缺点时效性差缓存过期之前可能不一致场景更新频率较低时效性要求低的业务 同步双写在修改数据库的同时直接修改缓存 优势时效性强缓存与数据库强一致缺点有代码侵入耦合度高场景对一致性、时效性要求较高的缓存数据 异步通知修改数据库时发送事件通知相关服务监听到通知后修改缓存数据 优势低耦合可以同时通知多个缓存服务缺点时效性一般可能存在中间不一致状态场景时效性要求一般有多个服务需要同步 基于MQ的异步通知 解读 商品服务完成对数据的修改后只需要发送一条消息到MQ中。缓存服务监听MQ消息然后完成对缓存的更新 依然有少量的代码侵入。 基于Canal的异步通知 解读 商品服务完成商品修改后业务直接结束没有任何代码侵入Canal监听MySQL变化当发现变化后立即通知缓存服务缓存服务接收到canal通知更新缓存 代码零侵入 2) 安装Canal Canal译意为水道/管道/沟渠canal是阿里巴巴旗下的一款开源项目基于Java开发。基于数据库增量日志解析提供增量数据订阅消费。 Canal是基于mysql的主从同步来实现的MySQL主从同步的原理如下 1MySQL master 将数据变更写入二进制日志( binary log其中记录的数据叫做binary log events2MySQL slave 将 master 的 binary log events拷贝到它的中继日志(relay log)3MySQL slave 重放 relay log 中事件将数据变更反映它自己的数据 Canal就是把自己伪装成MySQL的一个slave节点从而监听master的binary log变化。再把得到的变化信息通知给Canal的客户端进而完成对其它数据库的同步。 2.a) 开启MySQL主从 Canal是基于MySQL的主从同步功能因此必须先开启MySQL的主从功能才可以。 这里以之前用Docker运行的mysql为例 开启binlog 打开mysql容器挂载的日志文件我的在/tmp/mysql/conf目录: 修改文件 vi /tmp/mysql/conf/my.cnf添加内容 log-bin/var/lib/mysql/mysql-bin binlog-do-dbheima配置解读 log-bin/var/lib/mysql/mysql-bin设置binary log文件的存放地址和文件名叫做mysql-binbinlog-do-dbheima指定对哪个database记录binary log events这里记录heima这个库 最终效果 [mysqld] skip-name-resolve character_set_serverutf8 datadir/var/lib/mysql server-id1000 log-bin/var/lib/mysql/mysql-bin binlog-do-dbheima设置用户权限 在数据库中添加一个仅用于数据同步的账户出于安全考虑这里仅提供对heima这个库的操作权限。 create user canal% IDENTIFIED by canal; GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT,SUPER ON *.* TO canal% identified by canal; FLUSH PRIVILEGES;重启mysql容器即可 docker restart mysql测试设置是否成功在mysql控制台或者Navicat中输入命令 show master status;2.b) 安装Canal 创建网络 我们需要创建一个网络将MySQL、Canal、MQ放到同一个Docker网络中 docker network create heima让mysql加入这个网络 docker network connect heima mysql安装Canal 课前资料中提供了canal的镜像压缩包: 大家可以上传到虚拟机然后通过命令导入 docker load -i canal.tar或者在镜像网站中拉取 docker pull canal/canal-server:v1.1.5然后运行命令创建Canal容器 docker run -p 11111:11111 --name canal \ -e canal.destinationsheima \ -e canal.instance.master.addressmysql:3306 \ -e canal.instance.dbUsernamecanal \ -e canal.instance.dbPasswordcanal \ -e canal.instance.connectionCharsetUTF-8 \ -e canal.instance.tsdb.enabletrue \ -e canal.instance.gtidonfalse \ -e canal.instance.filter.regexheima\\..* \ --network heima \ -d canal/canal-server:v1.1.5说明: -p 11111:11111这是canal的默认监听端口-e canal.instance.master.addressmysql:3306数据库地址和端口如果不知道mysql容器地址可以通过docker inspect 容器id来查看-e canal.instance.dbUsernamecanal数据库用户名-e canal.instance.dbPasswordcanal 数据库密码-e canal.instance.filter.regex要监听的表名称 表名称监听支持的语法 mysql 数据解析关注的表Perl正则表达式. 多个正则之间以逗号(,)分隔转义符需要双斜杠(\\) 常见例子 1. 所有表.* or .*\\..* 2. canal schema下所有表 canal\\..* 3. canal下的以canal打头的表canal\\.canal.* 4. canal schema下的一张表canal.test1 5. 多个规则组合使用然后以逗号隔开canal\\..*,mysql.test1,mysql.test2 3) 监听Canal Canal提供了各种语言的客户端当Canal监听到binlog变化时会通知Canal的客户端。 Canal客户端 Canal提供了各种语言的客户端当Canal监听到binlog变化时会通知Canal的客户端。不过这里我们会使用GitHub上的第三方开源的canal-starter 引入依赖 dependencygroupIdtop.javatool/groupIdartifactIdcanal-spring-boot-starter/artifactIdversion1.2.1-RELEASE/version /dependency编写配置 canal:destination: heima # canal的集群名字要与安装canal时设置的名称一致server: 192.168.150.101:11111 # canal服务地址修改Item实体类 通过Id、Column、等注解完成Item与数据库表字段的映射 Data TableName(tb_item) public class Item {TableId(type IdType.AUTO)Idprivate Long id;//商品idprivate String name;//商品名称private String title;//商品标题private Long price;//价格分private String image;//商品图片private String category;//分类名称private String brand;//品牌名称private String spec;//规格private Integer status;//商品状态 1-正常2-下架private Date createTime;//创建时间private Date updateTime;//更新时间TableField(exist false)Transientprivate Integer stock;TableField(exist false)Transientprivate Integer sold; }编写监听器 通过实现EntryHandlerT接口编写监听器监听Canal消息。注意两点 实现类通过CanalTable(tb_item)指定监听的表信息EntryHandler的泛型是与表对应的实体类 package com.heima.item.canal;Component CanalTable(tb_item) public class ItemHandler implements EntryHandlerItem {Autowiredprivate RedisHandler redisHandler;Autowiredprivate CacheLong, Item itemCache;Overridepublic void insert(Item item) {// 写数据到jvm进程缓存itemCache.put(item.getId(), item);// 写数据到redisredisHandler.saveItem(item);}Overridepublic void update(Item before, Item after) {// 写数据到jvm进程缓存itemCache.put(after.getId(), after);// 写数据到redisredisHandler.saveItem(after);}Overridepublic void delete(Item item) {// 删除数据到jvm进程缓存itemCache.invalidate(item.getId());// 删除数据到redisredisHandler.deleteItemById(item.getId());} }
http://www.dnsts.com.cn/news/123658.html

相关文章:

  • 网站建设最基础的是什么wordpress 手机播放不了视频
  • 做网站服务器在哪买电影网站制作
  • 怎样做专业网站电子商务基础平台有哪些
  • 岳阳网站建设企业中山网站定制公司
  • 怎么黑网站的步骤江苏省城乡和住房建设厅网站首页
  • 国外的ui设计思想网站苏州公司建设网站制作
  • 西地那非是什么药上海网站建设优化
  • 网站建设公司如何推广哈尔滨建设网站公司
  • 网站建设服务费如何做会计分录网站建设与管理是学什么
  • 建设网站公司那里好相关的热搜问题解决方案wordpress 开发 知乎
  • 顺德新网站制作建设网站选多大的空间合适
  • 知名网站开发哪里有php做网站导购模板
  • 旅游网站制作我的网站怎么做
  • 中小微企业建设网站wordpress图片主题 简约
  • 微网站建设计划书2022建站市场
  • 做二手车广告推广哪家网站好下载京东正版官网
  • 沈阳建站模板源码做问卷的网站
  • 中宁网站建设北京模型设计制作
  • 2016个人网站备案怎么做网页宣传
  • 网站导航容易做网站建设评比标准
  • 一 网站开发背景wordpress发布文章页面错误
  • 网站建设方案书阿里云skype在网站上怎么做链接
  • 微网站的图标怎么做做网站排名工具
  • 陕西专业做网站广告制作合同
  • 优化 导航网站用wordpress建站一个人可以吗
  • 百度有没有做游戏下载网站吗想学平面设计哪个网上可以学
  • 做网站通过什么挣钱阳泉推广型网站开发
  • 小企业网站建设怎样可以快速东方网景做网站怎么样
  • 唐山网站建设唐山谷歌推广费用
  • 网站如何实现微crm客户管理系统