Postgresql 主动触发更新Redis数据方案测试总结

还没有专栏

文章目录


前言

减轻数据库查询压力建立redis缓存已经是IT业务场景里老生常谈的话题了,我周围的大多方案都是初始化表数据到缓存,建立过期时间,定时跑批,再去库里查询后进行更新,我把它认为被动更新缓存数据,先查库发现不同了或者定时跑批再去跟新热数据有点太被动了,我喜欢主动,我就有了这么个不成熟的想法哈,能不能数据库更新了一条 redis里就随着更新一条,让数据实时保持随着表的变动而更新,经过今天不成熟的实践和测试,感觉可行! 因为我们Web 应用的关系型数据库都已经从MYSQL 迁移到了 Postgresql 或者 Gaussdb ,废话不多说为各位好汉叨咕叨咕我的实现过程和测试后的结果。

一、Postgresql 运用pg_notify

PostgreSQL中的 Listen/Notify 是用来提供客户端之间通过服务段进行消息通信的机制。

  • listen:监听消息通道

  • unlisten:取消先前的监听

  • notify:发送消息到消息通道中

  • pg_notify():与 notify 命令的功能相同,也可以发送消息到消息同道中。

  • pg_listening_channels():调用此函数可以查询当前 session 已注册了哪些消息监听。

利用PG的这个功能,再加上触发器,去主动告诉外界数据的变化,从而可以触发其它动作,感叹PG的强大,很多国产数据库厂商的内核都是基于PG,那我个人感觉可以用上这个,我之前看到有个国产库厂商推出了Pg_Cron的特性,也很实用,因为在数据对接时我们考虑成本存储问题,是会定时删除掉一个周期之前的数据。

二、实现步骤

1.创建测试表

CREATE TABLE "public"."test" (
  "id" int4 NOT NULL,
  "name" varchar(50) COLLATE "pg_catalog"."default" NOT NULL,
  "py_code" varchar(50) COLLATE "pg_catalog"."default",
  "seq_no" int4 NOT NULL,
  "description" varchar(200) COLLATE "pg_catalog"."default",
  CONSTRAINT "pk_zd_business_type" PRIMARY KEY ("id")
)
;

ALTER TABLE "public"."test" 
  OWNER TO "postgres";

2.创建SQL函数

CREATE OR REPLACE FUNCTION "public"."notifyshipment"()
  RETURNS "pg_catalog"."trigger" AS $BODY$
DECLARE
BEGIN     
         PERFORM pg_notify(
   CAST('test' AS text),
   row_to_json(NEW)::text); #test 是要监听的订阅名称,自行更改就是了

   RETURN NEW;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100

这个函数什么意思呢,有懂的,但也有没用过PG或不懂的,我得吧一下,阿门!这个NEW就是表的一行记录的数据,可以理解是个对象,NEW.字段名就出这个属性的值,做类似于实体类哈!新插入一条记录,就以json 的形式推送出去。客户端,也就是我们的代码端去实时监就能拿到

3.绑定触发器

CREATE TRIGGER t_cdc_notify AFTER INSERT OR UPDATE ON test
FOR EACH ROW EXECUTE PROCEDURE notifyshipment();

#大概意思  : 触发器绑定刚才的函数作用到test表上

4. 客户端代码

    public void run() {
        while (true) {
            try {
                PGConnection pgConn = (PGConnection) conn.unwrap(PGConnection.class);
                PGNotification[] notify = pgConn.getNotifications();
                if (null != notify) {
                    for (int k = 0; k < notify.length; k++) {
                        
                        String jsonStr = notify[k].getParameter();
                        JSONObject jsonObj = JSON.parseObject(jsonStr);
                        System.out.println("------------NEW 记录------------------");
                        System.out.println(jsonObj.toJSONString());
                        System.out.println("------------NEW 记录------------------");
//                      redisRWService.set("a",jsonObj.toJSONString());
                        //连接本地的 Redis 服务
                        Jedis jedis = new Jedis("192.168.56.103",6379);
                        System.out.println("redis连接成功");
                        //查看服务是否运行
                        System.out.println("redis服务正在运行: "+jedis.ping());
                        System.out.println("======================key==========================");
                        //清除当前数据库所有数据
                        jedis.flushDB();
                        //设置键值对
                        jedis.set("test",jsonObj.toJSONString());
                        //查看存储的键的总数
                        System.out.println(jedis.dbSize());
                        //取出设置的键值对并打印
                        System.out.println(jedis.get("test"));

                    }
                }
                Thread.sleep(300);
            } catch (Exception e) {
                e.printStackTrace();

            }
        }
    }

客户端代码可以使用多线程的方式实时读取队列里推送过来的数据,进行redis的更新存储,我这里是单类启动,pom.xml 使用的是jedis,value没做序列化操作, 没走springBoot自带的redisTemplate模板。只是为了展示下value内容的更新变化。

5.测试

第一步  启动客户端的监听程序

第二步  往这张表里插入一条测试记录

 第三步 查看实时数据   

客户端

 redis端

 第四步 更新表记录

 最后一步  查看redis数据是否随着记录的变化马上变化

 

 

查看后,redis 端数据已经改变,随着数据库记录的变化,redis数据紧接着就跟着变化。满足了我想要的实时性。

总结

 作为一个数据治理从业人员,数据的实时性是很重要的一点需求。也经过了今天休息日的测试呢证明,目前这种初级的设想还行,能满足。也必然存在一些没谈及到的问题,比如说,删除记录数据,是没办法去redis 里马上清除对应key。这样就涉及到了redis端的过期超市设置和跑批任务。

产生这种场景的想法,自己也是设想能解决redis 缓存能随着数据库表记录的主动跟新,从而能去主动触更新缓存数据,达到数据实时性。在俩套系统对接过程中,如果要实时查询对方库里的一张表中记录的最新状态,这种高频次的查询,如果换做我是对方,在考虑负载性能时也不会同意,如果使用今天测试的这种方案,较低了查询负载也实现了双方应用系统原本的健壮性。但,目前这种方案还只是适用于pg内核的数据库。如果是mysql的话或者oracle 还想实现的话,就得用FLINK CDC 实时读取源数据到pg库再去实现。当然,既然用FLINK了,那方法自然就多了!今天的节目就到这了,见笑 见笑~~~

后期会一直更新CSDN,总结工作整理和个人想法测试等,还恳切各位大哥和小仙女们 ,多多提出指导意见,严厉不怕,促使大弟我进步就行!

东北礼仪  ~~~之~~~~~

 抱拳了老铁!!!

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值