从电波表到数据库小程序之 - 数据库异步广播(notify/listen)

标签

PostgreSQL , notify , listen , 异步消息


背景

小时候就梦想有个酷酷的电波表(虽然现在还没有拥有),不过电波表和PostgreSQL有什么关系呢?听我道来。

http://baike.baidu.com/view/1124741.htm

电波表内置高感度小型天线,接收标准电波进行自动对时,因而可以实现时间上的精准。在国际上,德国、英国、美国、日本都已经有标准电波的发送。2007年7月,在中国河南商丘建成的新电波塔已经开始发送电波。

标准电波接收(6局电波接收)原理

中国标准时间以10万年误差1秒的铯原子钟为基准。通过手表内置的高敏感度接收器接收以无线电波传送的标准时间信号,并自动校准手表走时。使手表显示的时间与标准时间同步,精确计时。在建筑物密集的室内也可以接收标准电波信号,显示正确的时间。

标准电波的接收范围是半径约1000~3000km, 深夜(最多6次)自动接收电波信号,不能收到标准电波信号时,自动接收GPS卫星电波获取时间信息并校正时间。中国的电波塔在河南省商丘市。

而用于接收电波信号的防震天线采用的是非晶材质,能够实现高敏感度接收。不但具备对应极端户外环境下使用的牢靠性,还可以确保稳定接收全球6局电波信号。

电波表是一个非常典型的广播应用,类似的还有组播(注意不是主播哦),类似的应用也很多,比如广播电视,电台等。

数据库广播

在数据库中,其实也有类似的应用,比如我前几天在文章中写的数据库到WEB客户端的广播,详见 :

《从微信小程序 到 数据库"小程序" , 鬼知道我经历了什么》

实际上是利用了PostgreSQL数据库的异步消息机制,数据库往消息通道发送数据,应用程序可以监听对应的消息通道,获取数据库发出的数据。

通过异步消息在数据库中实现了一对多的广播效果。

SQL语法参考文档:

1. 向通道发送消息

https://www.postgresql.org/docs/9.6/static/sql-notify.html

2. 监听某通道的消息

https://www.postgresql.org/docs/9.6/static/sql-listen.html

3. 取消监听某通道

https://www.postgresql.org/docs/9.6/static/sql-unlisten.html

4. 数据库函数

查看会话监听了哪些通道,以及当前数据库的异步消息队列使用了多少。

pg_listening_channels()         setof text  channel names that the session is currently listening on
pg_notification_queue_usage()   double          fraction of the asynchronous notification queue currently occupied (0-1)

pg_notification_queue_usage用来计算已使用的异步消息页面占比,如果有监听,但是一直不消费,可能导致溢出。

src/backend/commands/async.c  

/*
 * slru.c currently assumes that all filenames are four characters of hex
 * digits. That means that we can use segments 0000 through FFFF.
 * Each segment contains SLRU_PAGES_PER_SEGMENT pages which gives us
 * the pages from 0 to SLRU_PAGES_PER_SEGMENT * 0x10000 - 1.
 *
 * It's of course possible to enhance slru.c, but this gives us so much
 * space already that it doesn't seem worth the trouble.
 *
 * The most data we can have in the queue at a time is QUEUE_MAX_PAGE/2
 * pages, because more than that would confuse slru.c into thinking there
 * was a wraparound condition.  With the default BLCKSZ this means there
 * can be up to 8GB of queued-and-not-read data.
 *
 * Note: it's possible to redefine QUEUE_MAX_PAGE with a smaller multiple of
 * SLRU_PAGES_PER_SEGMENT, for easier testing of queue-full behaviour.
 */
#define QUEUE_MAX_PAGE                  (SLRU_PAGES_PER_SEGMENT * 0x10000 - 1)  

src/include/access/slru.h:#define SLRU_PAGES_PER_SEGMENT        32

异步消息编程

除了使用SQL来编写异步消息,还可以使用数据库的驱动来编写异步消息

c

参考libpq的异步消息部分

https://www.postgresql.org/docs/9.6/static/libpq-notify.html

PGnotify *PQnotifies(PGconn *conn);  

typedef struct pgNotify
{
    char *relname;              /* notification channel name */
    int  be_pid;                /* process ID of notifying server process */
    char *extra;                /* notification payload string */
} PGnotify;

文档中有一个例子如下

https://www.postgresql.org/docs/9.6/static/libpq-example.html#LIBPQ-EXAMPLE-2

java

参考文档

https://jdbc.postgresql.org/documentation/head/listennotify.html

应用举例

Broadcasting PostgreSQL NOTIFY messages to WebSocket Clients

The system works like this:

Client subscribes to a WebSocket topic...  

NOTIFY event on database server ->
  PGNotificationListener on web server ->
      Send Websocket notification on server ->
         Receive Websocket event on browser.

With the code below, if you call NOTIFY dml_events, 'some message'; in Postgres, it will be broadcast to all WebSocket clients.

Follow this answer regarding proper listener setup

URL:

http://blog.databasepatterns.com/2014/04/postgresql-nofify-websocket-spring-mvc.html

http://stackoverflow.com/questions/37916489/listen-notify-pgconnection-goes-down-java

The notification listeners are internally maintained by that library as weak references meaning that you have to hold a hard reference externally so they won't be garbage collected.
Check out the BasicContext class lines 642 - 655:  

---
public void addNotificationListener(String name, String channelNameFilter, NotificationListener listener) {  

    name = nullToEmpty(name);
    channelNameFilter = channelNameFilter != null ? channelNameFilter : ".*";  

    Pattern channelNameFilterPattern = Pattern.compile(channelNameFilter);  

    NotificationKey key = new NotificationKey(name, channelNameFilterPattern);  

    synchronized (notificationListeners) {
      notificationListeners.put(key, new WeakReference<NotificationListener>(listener));
    }  

}
---  

If the GC picks up your listener, calls to "get" on the weak reference will return null and will not fire as seen from lines 690 - 710  

---
  @Override
  public synchronized void reportNotification(int processId, String channelName, String payload) {  

    Iterator<Map.Entry<NotificationKey, WeakReference<NotificationListener>>> iter = notificationListeners.entrySet().iterator();
    while (iter.hasNext()) {  

      Map.Entry<NotificationKey, WeakReference<NotificationListener>> entry = iter.next();  

      NotificationListener listener = entry.getValue().get();
      if (listener == null) {  

        iter.remove();
      }
      else if (entry.getKey().channelNameFilter.matcher(channelName).matches()) {  

        listener.notification(processId, channelName, payload);
      }  

    }  

}
---  

To fix this, add your notification listeners as such:  

---
/// Do not let this reference go out of scope!
PGNotificationListener listener = new PGNotificationListener() {  

@Override
public void notification(int processId, String channelName, String payload) {
    // interesting code
};
pgConnection.addNotificationListener(listener);
---  

Quite an odd use-case for weak references in my opinion...

代码:

https://bitbucket.org/neilmcg/postgresql-websocket-example

其他编程语言的驱动,大多数是基于libpq的,不再举例。

参考

《从微信小程序 到 数据库"小程序" , 鬼知道我经历了什么》

时间: 2024-07-29 02:03:04

从电波表到数据库小程序之 - 数据库异步广播(notify/listen)的相关文章

从微信小程序 到 数据库&quot;小程序&quot; - 鬼知道我经历了什么

标签 PostgreSQL , 服务端编程接口 , pl language , 小程序 , 地球语言 , java , perl , python , php , tcl , R , go , JULIA 背景 微信小程序最近比较火,大概以后大家都不需要安装程序了,直接在微信中调用运行.跑在微信里的小程序类似一个虚拟机或者一个Docker容器,这是腾讯要分APP store蛋糕的节奏吗? 从技术角度来看,微信小程序带来了几个好处,不需要安装软件,用户不需要进行软件的版本管理,节省了一点点手机的空

Oracle数据库小程序

oracle|程序|数据|数据库 http://61.144.28.245/hjc/web/doc/wangyou/tanggang/OraTools.html 本站首页设为首页收藏本站联系本站 一个Oracle数据库小程序作者:唐纲 程序说明 这是一个从oracle数据库中取函数.存储过程.包的源代码的小程序.程序采用多线程处理,并且考虑到程序的通用性,连接数据库采用JDBC-ODBC网桥.因此,在运行程序之前,必须先建立一个ODBC数据源(DSN),该DSN指向一个oracle数据库实例.程

VC中使用ADO开发数据库应用程序简明教程_C 语言

本文实例讲述了VC中使用ADO开发数据库应用程序的方法.分享给大家供大家参考,具体如下: 一.ADO概述 ADO是Microsoft为最新和最强大的数据访问范例 OLE DB 而设计的,是一个便于使用的应用程序层接口.ADO 使您能够编写应用程序以通过 OLE.DB 提供者访问和操作数据库服务器中的数据.ADO 最主要的优点是易于使用.速度快.内存支出少和磁盘遗迹小.ADO 在关键的应用方案中使用最少的网络流量,并且在前端和数据源之间使用最少的层数,所有这些都是为了提供轻量.高性能的接口.之所以

第十三章-Delphi开发数据库应用程序概述(一)(2)

13.2.1 Delphi的数据库特性 跟其他的应用程序一样,Delphi提供了许多部件以方便地创建数据库应用程序.数据库对象的数据成员既可在设计阶段设置,也可在运行阶段通过程序代码进行设置.Delphi的部件板上提供了两页数据库应用程序开发中所要使用的部件: 数据访问页(Data Access Page)上的部件用于直接访问数据库中的数据库表. 数据控制页(Data Control Page)上的部件用来与用户交互,显示.修改数据库中的数据. 数据库应用程序首先是利用Delphi提供的数据库部

微信小程序之ES6与事项助手的功能实现_javascript技巧

由于官方IDE更新到了0.11.112301版本,移除了对Promise的支持,造成事项助手不能正常运行,解决此问题,在项目中引入第三方兼容库Bluebird支持Promise,代码已经整合到项目代码中. 好久没有写关于微信小程序的随笔了,其实是不知道写点什么好,之前的豆瓣图书和知乎日报已经把小程序的基础部分写的很详细了,高级部分的API有些还得不到IDE的调试支持.之前发表了知乎日报小例,有网友问我小程序有没有关于日历显示的组件,可以显示所有天数的,自己看了一遍,好像没有这个组件,所以打算那这

ACCESS数据库向MySQL快速迁移小程序(二)

access|mysql|程序|数据|数据库 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 以下为 import.php 源程序 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ <html> <head> <style type=text/css> body,td,li,div,p,pre,a,b,h1,h2,h3,h4 {font-family:verdana;font-size:9pt;lin

ACCESS数据库向MySQL快速迁移小程序(一)

access|mysql|程序|数据|数据库 近日,本人为了将为公司开发的一个信息管理系统从以前试运行的开发机器上(Windows NT + IIS4.0 + Access)迁移至一台真正的Linux服务器上(Apache1.3.12 + PHP 4.03 + MySQL 3.23.26),其中数据库中的几十个表的内容迁移,开始让我小费了一些周折,从网上也下载了一些MySqL的客户软件或是数据库管理软件,写得较好的软件均有数据迁移功能,但其迁移方式不外乎两种,一种是采用文件引入方式,此种方式在处

数据库查询-关于这个SSH小程序思路问题

问题描述 关于这个SSH小程序思路问题 编写一个成绩管理系统. (1)用数据库建立两个表,分别存储成绩信息(学号,姓名,课程名,成绩)和用户登录信息:(数据库类型不限) (2)用户登录后可以录入.删除.修改成绩: (3)能够分别按姓名和课程名查询相应记录: (4)能够统计每门课程的平均分.最高分和最低分并显示在相应的页面上. 前三步用SSH+mysql直接实现,第四步没有思路,怎么把数据查出来显示. 解决方案 SELECT 课程 AVG (成绩)MAX(成绩)MIN(成绩) FROM 成绩表 G

java-关于Java含有数据库的小程序打包问题

问题描述 关于Java含有数据库的小程序打包问题 我想把我用MyEclipse写的一个含有sqlsever数据库的Java小程序打包成jar包,然后放在桌面上可以双击打开,就像其他应用一样,但是我下载了sqlsever的驱动包,不知道如何把驱动包和程序一起打包成jar包,求好心大神帮助! 解决方案 http://blog.csdn.net/ljz2009y/article/details/7707237