有什么方法可以在不查询/减少查询的情况下了解数据库更新?
我遇到了一个奇怪的问题,寻找我可以到达的最佳解决方案。我正在开发一个rails应用程序,它显示来自另一个应用程序(nodejs)正在使用的公用数据库的数据。所有CRUD操作都发生在另一个平台上。在rails应用程序中,我们只是查询并显示数据。有什么方法可以在不查询/减少查询的情况下了解数据库更新?
在rails应用程序中,我需要自动更新视图而无需刷新。例如
def index
@states = State.page(params[:state_page])
@level_one_companies = Company.includes(:state)
.where(level: 1)
.order('created_at DESC').limit(20)
@level_two_companies = Company.includes(:state)
.where(level: 2)
.order('created_at DESC').limit(20)
end
在索引页我将为每个这些表,我需要刷新表时,新数据添加到状态,(或)1级(或)二级公司。
我知道我可以用两种方式自动更新的观点去即
- 作用电缆。
- 使用Jquery以一定的时间间隔数据池。
通常在使用Action Cable时,我们将在db中创建记录(在创建操作(或模型中的after_save回调之后的.save之后)之后从服务器广播数据。但是,我不通过Rails应用程序创建任何记录。
我的第一个问题是,在这种情况下是否有任何方式使用动作电缆?
所以我去了第二个选项,它工作正常。但是在每X秒后它会调用太多的db调用。 有什么办法可以减少查询来更新视图? 什么是我可以在这里与最好的方式?任何帮助高度赞赏。谢谢。
如果您的标签设置正确,您将使用postgres作为数据库。
postgres提供了一个发布 - 订阅机制,您可以结合使用action-cable来监听数据库中的更改。
在this gist,你可以找到postgres-pubsub与服务器发送事件的例子。将其转换为兼容行动电缆的代码应该很简单。
您可以在表格上创建触发器(创建/更新/删除),在“通道”上触发通知,并且您可以侦听所述通道的事件。我使用socketcluster,从工作人员处听取并向消费者(浏览器和移动应用程序)广播。
首先创建触发器:
CREATE FUNCTION deletes_notify_trigger() RETURNS trigger
LANGUAGE plpgsql
AS $$
DECLARE
BEGIN
PERFORM pg_notify('deletes_channel', ('DELETED' || ';;' || OLD.id)::text);
RETURN new;
END;
$$;
和
CREATE TRIGGER deletes_trigger AFTER DELETE ON events FOR EACH ROW EXECUTE PROCEDURE deletes_notify_trigger();
您可以添加在数据包被广播想要的任何东西,在我来说,我只需要记录的ID 。对于创建和更新,您可以发送整行或只选择一些选定的列。你也可以在PG 9.2(我认为)和更高版本中将它作为JSON发送。我使用9.1,所以我连接;;分隔符。
确保您的代码在查询之间至多需要10%的时间,否则如果您执行复杂的联接或更新或其他操作,您会注意到性能显着下降。你希望这个过程尽可能的简单和快速,把它放在基本的操作上,并且在应用层上做任何繁重的工作。
然后,观察者和广播给消费者(在我的情况节点,socketcluster和PG宝石,你的情况,你可以使用JS,Python和Ruby,不管你喜欢)
var global_deletes = socket.subscribe('deletes_channel');
pg.connect(connectionString, function(err, client) {
client.on('notification', function(dbmsg) {
console.log(dbmsg.payload);
var payload = dbmsg.payload.split(";;"); // you can use JSON instead
if (payload[0] == "DELETED") { // when a DELETE is received...
global_deletes.publish(dbmsg.payload);
var tchannel = socket.subscribe('events-'+ payload[1]); // join the channel we want to broadcast
setTimeout(() => tchannel.publish(dbmsg.payload), 50); // send the update to all consumers
setTimeout(() => tchannel.unsubscribe(), 100);
}
);
var query = client.query("LISTEN deletes_channel"); // turn on notifications from the server
});
谢谢@phoet ,会试一试,让你知道。 –