我尝试创建客户端 - >数据库通知/更新系统。客户端是用Java/Hibernate编写的。通知客户本人使用触发器:基于通知的实时PostgreSQL客户端更新
CREATE OR REPLACE FUNCTION notifyUsers() RETURNS TRIGGER AS $$
DECLARE
data integer;
notification json;
BEGIN
IF (TG_OP = 'DELETE') THEN
data = OLD.id;
ELSE
data = NEW.id;
END IF;
-- Contruct the notification
notification = json_build_object(
'table',TG_TABLE_NAME,
'action', TG_OP,
'id', data);
-- Execute pg_notify(channel, notification)
PERFORM pg_notify('events',notification::text);
-- Result is ignored since this is an AFTER trigger
RETURN NULL;
END;
$$ LANGUAGE 'plpgsql';
CREATE TRIGGER notifyUsersAccountData AFTER INSERT OR UPDATE OR DELETE ON document FOR EACH ROW EXECUTE PROCEDURE notifyUsers();
,但是当通过客户端收到的通知,我不能确定谁触发它。 我可以发送任何其他参数,以确定谁触发它(session_id?在我的应用程序中有自定义用户,但我想避免发送User.id作为登录同一用户由2 PC将打破我的通知/更新系统)
在通知接收方客户端更新值后,需要“会话ID”来确定“THIS客户端”是否进行了更改(当然在这种情况下客户端不应该更新)或其他人(在此情况下,更新应适用)
编辑 - - -
我想刷新这个话题,因为它没有得到解决。调用pg_backend_pid的解决方案有时会中断,导致“执行SQL查询的调用程序的PID”与PGNotification.getPid不同。代码:
public int getSessionPid() {
int lResult = -1;
try
{
connect();
Session session = _sessionFactory.getCurrentSession();
Transaction lTransaction = session.beginTransaction();
SQLQuery lQuery = session.createSQLQuery("SELECT pg_backend_pid()");
List lResultQuery = lQuery.list();
lResult = Integer.parseInt(lResultQuery.get(0).toString());
lTransaction.commit();
}catch(org.hibernate.SessionException e)
{
e.printStackTrace();
}
return lResult;
}
,并在那里出现比较代码:
int lPid = Facade.databaseConnector.warehouse.getSessionPid();
for(int i = 0; i < notifications.length; ++i)
{
if(lPid == notifications[i].getPID())
...
此外,我看到的是,在当前的后端连接可见表select * from pg_stat_activity
有按我的方案的一个实例3个连接。
SELECT 1
- 只是为了通知,因为没有“接触”数据库进行更新,通知不会被触发- 一个连接与休眠相关
- 一个连接与SQL查询数据库(如插入/相关更新/删除行等)
所有的后端连接在pg_stat_activity中有不同的端口和PID。
任何想法?
将链接添加到https://jdbc.postgresql.org/documentation/head/listennotify.html这个答案。 –
确定它工作正常,但是有没有办法避免调用: SELECT pg_backend_pid();我每次收到通知时都会收到 ? –
如果您的会话在收听活动时持续存在,那么您可以获得一次pid并将其存储在某个变量中。如果你不知道它是否持续,那么我会通过存储数组中的所有pid并检查其内容或者简单地存储'oldPid'和比较新鲜的pid来测试它。 –