Обновить значение кэша Redis из PostgreSQL
Я работаю над проектом Python, и у меня есть требование, чтобы при вставке, обновлении или удалении строки в таблице PostgreSQL соответствующее значение обновлялось в Redis. Я работаю в системе Windows, и Redis установлен в контейнере Docker в моей системе Windows. Версия PostgreSQL — 15.
Я пробовал разные сценарии, но ни один из них пока не сработал. Я попытался написать триггер, который вызывает функцию хранимой процедуры при возникновении каких-либо изменений в моей таблице, но я не могу подключиться к серверу Redis из моей хранимой процедуры.
Я также пробовал использовать plpython3u, но не смог создать хранимую процедуру из-за проблем с версией. Кроме того, я попробовал использовать pg_redis, но это тоже не сработало.
Ниже я включил сценарий, который использовал для создания хранимой процедуры.
1.
CREATE SCHEMA redis;
CREATE OR REPLACE FUNCTION update_redis() RETURNS TRIGGER AS $$
DECLARE
redis_host TEXT := 'localhost';
redis_port INTEGER := 32768;
redis_password TEXT := 'redispw';
redis_db INTEGER := 0;
redis_client redis.StrictRedis;
BEGIN
redis_client = redis.StrictRedis(host=redis_host, port=redis_port, password=redis_password, db=redis_db);
IF (TG_OP = 'DELETE') THEN
redis_client.hdel(TG_TABLE_NAME, OLD.id);
ELSE
redis_client.hset(TG_TABLE_NAME, NEW.id, row_to_json(NEW)::text);
END IF;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
2.
CREATE EXTENSION dblink;
CREATE OR REPLACE FUNCTION update_redis() RETURNS TRIGGER AS $$
DECLARE
redis_host text := 'localhost';
redis_port text := '32768';
redis_db text := '0';
redis_password text := 'redispw';
redis_conn text := 'redis://:' || redis_password || '@' || redis_host || ':' || redis_port || '/' || redis_db;
BEGIN
PERFORM pg_notify('redis_update', row_to_json(NEW)::text);
-- Connect to Redis
PERFORM pg_sleep(0.1); -- Wait a short time to allow the NOTIFY event to be processed
PERFORM dblink_connect('dbname=postgres', 'host.docker.internal', 'redis', '', 'redis_conn');
-- Set the value in Redis
PERFORM dblink_exec('redis_conn', 'SET key value');
-- Disconnect from Redis
PERFORM dblink_disconnect('redis_conn');
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
**3. **
CREATE OR REPLACE FUNCTION update_redisnew() RETURNS trigger AS $$
BEGIN
-- Retrieve the updated data from the table
DECLARE
data json;
BEGIN
data := row_to_json(NEW);
SELECT redis.add_server('redis://default:redispw@localhost:32768');
PERFORM redis.command('SET', 'key666', 'valll');
-- Configure the Redis server connection
SELECT redis.add_server('redis://localhost:6379/0');
-- Send the updated data to Redis
PERFORM redis.command('SET', NEW.id::text, data::text);
RETURN NEW;
END;
END;
$$ LANGUAGE plpgsql;
пожалуйста, кто-нибудь помогите мне разобраться в проблеме.
Я скопировал ошибки из ваших комментариев в сам вопрос.
Когда я выполнил первый запрос в postgressql, я получил ошибку ниже: ОШИБКА: функция dblink_connect(неизвестно, неизвестно, неизвестно, неизвестно, неизвестно) не существует LINE 1:SELECT dblink_connect('dbname=postgres', 'host.docker.intern. .. поэтому я не могу создать этот сп. –
Я могу создать два последних sp, выполнив соответствующие запросы, но когда я запускаю этот sp, я получаю следующие ошибки, соответствующие каждому sp, ПОДСКАЗКА: ни одна функция не соответствует данному имени и типам аргументов. Возможно, вам придется добавить явное приведение типов. ЗАПРОС:SELECT dblink_connect('dbname=postgres', 'host.docker.internal', 'redis', '', 'redis_conn') КОНТЕКСТ: функция PL/pgSQL update_redisnew(), строка 13 в состоянии PERFORM SQL: 42883 –
ОШИБКА: функция redis.add_server(unknown) не существует. СТРОКА 1: ВЫБЕРИТЕ redis.add_server('redis://default:redispw@localhost:3... ПОДСКАЗКА: ни одна функция не соответствует данному имени и типам аргументов. Возможно, вам понадобится для добавления явного приведения типов. ЗАПРОС:SELECT redis.add_server('redis://default:redispw@localhost:32768') КОНТЕКСТ: функция PL/pgSQL update_redisnew(), строка 10 в операторе SQL Состояние SQL: 42883 –
Я использую Windows 10, PostgreSQL-15 и Python 3.7 и 3.11. –
1 ответ
Итак, что вам нужно сделать, так это перестать бегать зигзагами, пробуя случайные вещи, не останавливаясь, чтобы понять детали любого из них.
Давайте возьмем ваше первое сообщение об ошибке (которое относится ко второму примеру блока кода). Он говорит вам, что не может найти функциюdblink_connect()
с предоставленными типами параметров («неизвестно» — это любое значение в кавычках, прежде чем PG сможет определить его реальный тип). В этом вопросе все довольно ясно, поэтому вам следует остановиться и выяснить, почему вы и ваша система баз данных расходитесь во мнениях.
Вариантов может быть только три:
- Вы подключены к другой базе данных, чем вы ожидаете, и dblink установлен где-то еще. Если ваш код показывает, что вы на самом деле выполняете, это кажется маловероятным, поскольку вы создаете расширение непосредственно перед созданием функции.
- Здесь нет
dblink_connect
функция вообще (что предполагает, что ваша функция не работает). - Есть один, но он требует других параметров.
Итак, что вам нужно сделать сейчас (и это всего лишь стандартная процедура отладки, применимая к любой системе — базе данных, сетевому маршрутизатору, веб-стеку), — это сузить два варианта.
Подключитесь к вашей базе данных с помощьюpsql
и бежать\dx
который распечатает все установленные вами расширения. Если вы не видите dblink, значит, он не установился. ПопробуйтеCREATE EXTENSION
теперь вручную, прочитайте и найдите сообщение об ошибке.
Если он есть, проверьте указанную для него схему — есть ли она в вашемsearch_path
? Если там написано «общедоступный», то это почти наверняка так, а если нет, вам нужно знать о путях поиска. Посмотрите это тоже.
Если расширение установлено и находится в вашем пути поиска, вы можете проверить, существует ли функция с помощью\df dblink_connect
. Что там написано, какие параметры вам нужны?
Я могу догадаться, что он скажет, хотя в моей базе данных не установлен dblink, поскольку у меня есть доступ к официальным руководствам.
https://www.postgresql.org/docs/15/contrib-dblink-connect.html
И он говорит, что ожидает две строки с именем соединения в качестве первого параметра. Не несколько с именем соединения в качестве последнего параметра. Понятия не имею, откуда вы это взяли, но это не из документации.
Теперь, прежде чем вы начнете исправлять это, ожидая, что все заработает, вы уверены, что dblink вообще может подключиться к Redis? Я слышал только о том, что его используют для подключения к другим серверам PostgreSQL. Ответ будет в документации, поэтому сначала сядьте и прочитайте ее.
Я предполагаю, что вам либо понадобится одна из оболочек resdis/fdw (которая может потребовать от вас их компиляции), либо использовать pl/python3u и импортировать клиент Redis в Python (что потребует от вас понимания, какая версия Python совместима с ваш установленный postgresql).