PostgreSQL下用于操作Redis的存储过程

1. 依耐关系(首先需要安装Redis_fdw)

关于Redis_fdw 详见:https://pgxn.org/dist/redis_fdw/

CREATE EXTENSION IF NOT EXISTS redis_fdw;
CREATE SERVER redis_server FOREIGN DATA WRAPPER redis_fdw OPTIONS (address '127.0.0.1', port '6379');
CREATE USER MAPPING FOR PUBLIC SERVER redis_server OPTIONS (password '');

2. 操作方法、使用范列

  • structure_redis 存储过程可以用于某个表的触发器中,或其他数据逻辑操作的存储过程中
  • 当数据层某个表的数据发生变化时运行该存储过程快速创建、更新或删除Redis数据,应用层不需要去操作Redis,只需要读取Redis即可
  • 会在数据库中生成一个"public"."police_redis_foreign"的数据表,用于存放Redis服务器数据库MAP(0~15),请自行规划好Redis数据存放位置
  • Redis服务器数据库15位置处,KEY 值为indexedDBStorage_foreignList:redisForeign存放着"public"."police_redis_foreign"的数据表的数据,方便应用层查找调用数据
  • RedisKEY值生成规则:storage_store:pk

2.1 清空Redis缓存

SELECT structure_redis(json_build_object(
    'type', 'empty',
    'foreign', '外部表名称(不指定则清空所有)',
    'redis', 'police_redis(默认)'
);

2.2. 创建或刷新一条JSON对象形式的Redis缓存记录,用于单一数据的缓存

  • 2.2.1 将指定表tablewhere查询结果的第一行记录以JSON对象形式进行Redis数据缓存

SELECT structure_redis(
    json_build_object(
        'pk', 4,                                    -- 数据主键值
        'type', 'info',                             -- 数据类型, 必须指定为`info`
        'databases', 1,                             -- 指定Redis的databases,范围:0~15, 默认:0
        'storage', 'sessionStorage',                -- 前端存储位置, 用于构造Redis的Key,默认indexedDBStorage 
        'store', 'userInfo',                        -- 前端存储store, 用于构造Redis的Key
        'table', 'police_view_user',                -- 数据查询表名
        'where', 'uid=4'                            -- 数据查询条件
    )
);
  • 2.2.2 将指定表table的主键primary等于pk的查询结果的第一行记录以JSON对象形式进行Redis数据缓存

SELECT structure_redis(
    json_build_object(
        'pk', 4,                                    -- 数据主键值
        'type', 'info',                             -- 数据类型, 必须指定为`info`
        'databases', 1,                             -- 指定Redis的databases,范围:0~15, 默认:0
        'storage', 'sessionStorage',                -- 前端存储位置, 用于构造Redis的Key,默认indexedDBStorage
        'store', 'userInfo',                        -- 前端存储store, 用于构造Redis的Key
        'table', 'police_view_user',                -- 数据查询表名
        'primary', 'uid'                            -- 查询主键列名
    )
);

2.3 将指定表tablewhere查询结果以JSON数组对象形式创建或刷新一条Redis缓存记录,用于数据列表的缓存

SELECT structure_redis(
    json_build_object(
        'pk', 'policerList',                            -- 数据PK值(此处并非主键值,用以标注唯一性)
        'type', 'list',                                 -- 数据类型,可以不必指定,如果指定必须指定为`list`
        'databases', 1,                                 -- 指定Redis的databases,范围:0~15, 默认:0
        'storage', 'indexedDBStorage',                  -- 前端存储位置, 用于构造Redis的Key,默认indexedDBStorage
        'store', 'userList',                            -- 前端存储store, 用于构造Redis的Key
        'table', 'police_view_user_list',               -- 数据查询表名
        'where', 'user_group::JSONB @> json_build_array(''police'')::JSONB'    -- 数据查询条件
    )
);

2.4 将指定数据data进行Redis数据缓存

SELECT structure_redis(
    json_build_object(
        'pk', 4,
        'type', 'info',                             -- 数据类型, 必须指定为`info`
        'databases', 1,                             -- 指定Redis的databases,范围:0~15, 默认:0
        'storage', 'sessionStorage',
        'store', 'userInfo',
        'data', '需要进行Redis缓存的数据'
    )
);

2.5 删除一条指定pkRedis缓存记录

SELECT structure_redis(
    json_build_object(
        'pk', 4,
        'storage', 'sessionStorage',
        'store', 'userInfo'
    )
);

3 参数说明

参数 参数说明 可选值 类型 是否必填 默认值
type 数据或操作类型 list、info、remove、empty ENUM false list
schemas 缓存分区,可用于按用户组或项目功能进行数据可见性的分区 NULL string false app
storage 前端本地存储方式 NULL string 除完全清空Redis外均必填 NULL
store 前端本地存储store名 NULL string 除完全清空Redis外均必填 NULL
table 缓存所需的数据库表名 NULL string 缓存数据时未指定data情况下必填 NULL
where 缓存所需的数据库查询方法 NULL string false NULL
data 所需缓存的数据 NULL JSON 缓存数据时未指定table情况下必填 NULL
dbindex Redis数据库ID,该缓存数据在Redis中的位置 NULL number false 0
pk 当缓存列表数据时为list;当缓存info数据时为数据主键 NULL string or number 缓存数据类型为info时必填 list
method 数据请求方法 get、post、put、delete、options ENUM false get
restful RestFul请求路径 NULL string 新增缓存数据时必填 NULL
route 数据Route请求方式所需的参数 NULL JSON false NULL

4. 数据表和视图

DROP TYPE IF EXISTS methods;
CREATE TYPE methods AS ENUM('get', 'post', 'put', 'delete', 'options');
DROP TYPE IF EXISTS data_type;
CREATE TYPE data_type AS ENUM('list', 'info', 'empty', 'remove');

CREATE TABLE "public"."base_redis_foreigns" (
    "foreigns" VARCHAR(150) NOT NULL,
    "storage" VARCHAR(50) NOT NULL,
    "store" VARCHAR(50) NOT NULL,
    "table" VARCHAR(200) DEFAULT NULL,
    "where" VARCHAR(200) DEFAULT NULL,
    "type" data_type DEFAULT 'list',
    "dbindex" SMALLINT DEFAULT 0,
    "numbers" INTEGER DEFAULT 0,
    "datetime" TIMESTAMP(3) WITHOUT TIME ZONE NOT NULL DEFAULT now(),
    PRIMARY KEY ("foreigns")
);
COMMENT ON TABLE "public"."base_redis_foreigns" IS 'Redis外部表数据';
COMMENT ON COLUMN "public"."base_redis_foreigns"."foreigns" IS 'Redis外部表名';
COMMENT ON COLUMN "public"."base_redis_foreigns"."storage" IS '前端本地存储方式';
COMMENT ON COLUMN "public"."base_redis_foreigns"."store" IS '前端本地存储store名';
COMMENT ON COLUMN "public"."base_redis_foreigns"."table" IS '数据库查询表名';
COMMENT ON COLUMN "public"."base_redis_foreigns"."where" IS '数据库查询方法';
COMMENT ON COLUMN "public"."base_redis_foreigns"."type" IS '数据缓存类型';
COMMENT ON COLUMN "public"."base_redis_foreigns"."dbindex" IS 'Redis数据库id';
COMMENT ON COLUMN "public"."base_redis_foreigns"."numbers" IS '数据缓存数量';
COMMENT ON COLUMN "public"."base_redis_foreigns"."datetime" IS '最后更新时间';

CREATE TABLE "public"."base_redis_map" (
    "id" SERIAL8,
    "key" VARCHAR(150) NOT NULL,
    "foreigns" VARCHAR(150) NOT NULL,
    "method" methods DEFAULT 'get',
    "restful" VARCHAR(200) DEFAULT NULL,
    "route" JSON DEFAULT NULL,
    "datetime" TIMESTAMP(3) WITHOUT TIME ZONE NOT NULL DEFAULT now(),
    PRIMARY KEY ("id")
);
COMMENT ON TABLE "public"."base_redis_map" IS 'Redis数据请求方式MAP';
COMMENT ON COLUMN "public"."base_redis_map"."id" IS '自增主键';
COMMENT ON COLUMN "public"."base_redis_map"."key" IS 'Redis缓存KEY键名';
COMMENT ON COLUMN "public"."base_redis_map"."foreigns" IS 'Redis外部表名';
COMMENT ON COLUMN "public"."base_redis_map"."method" IS '数据请求方式';
COMMENT ON COLUMN "public"."base_redis_map"."restful" IS '数据请求RestFul路径';
COMMENT ON COLUMN "public"."base_redis_map"."route" IS '数据请求Route方式参数';
COMMENT ON COLUMN "public"."base_redis_map"."datetime" IS '最后更新时间';

DROP VIEW IF EXISTS "public"."base_redis_map_view";
CREATE VIEW "public"."base_redis_map_view" AS
    SELECT
        M."key",
        M."foreigns",
        F."storage",
        F."store",
        F."table",
        F."where",
        F."type",
        F."dbindex",
        F."numbers",
        M."method",
        M."restful",
        M."route"
    FROM "public"."base_redis_map" AS M, "public"."base_redis_foreigns" AS F
    WHERE M.foreigns = F.foreigns;

5. 存储过程

CREATE OR REPLACE FUNCTION structure_redis(
    IN redis JSON
)RETURNS JSON
AS $$
DECLARE
    redis_table_schemas VARCHAR(50) := 'public';              -- 请自行根据实际情况配置数据库的schemas
    redis_table_prefix VARCHAR(50) := 'police';                 -- 请自行根据实际情况配置数据库表名前缀
    redis_table_name VARCHAR(50) := 'redis_foreign';        -- 请自行根据实际情况配置数据库表名
    redis_table VARCHAR(150);
    pk_val VARCHAR(100);
    storage_val VARCHAR(50);
    store_val VARCHAR(50);
    redis_key VARCHAR(100);
    foreign_table VARCHAR(100) DEFAULT NULL;
    foreign_table_array VARCHAR(100)[];
    table_val VARCHAR(100) DEFAULT NULL;
    where_val   VARCHAR(250) DEFAULT NULL;
    type_val VARCHAR(50) DEFAULT 'list';
    redis_table_num INTEGER;
    foreign_table_num INTEGER;
    redis_key_num INTEGER;
    databases SMALLINT DEFAULT 0;
    executesql TEXT;
    data_val JSON DEFAULT NULL;
BEGIN
    IF (json_extract_path_text(redis, 'type') IS NOT NULL) THEN
        type_val := json_extract_path_text(redis, 'type');
    END IF;
    IF (json_extract_path_text(redis, 'redis') IS NOT NULL) THEN
        redis_table := json_extract_path_text(redis, 'redis');
    END IF;
    IF (json_extract_path_text(redis, 'foreign') IS NOT NULL) THEN
        foreign_table := lower(json_extract_path_text(redis, 'foreign'));
    END IF;
    redis_table := '"'||redis_table_schemas||'"."'||redis_table_prefix||'_'||redis_table_name||'"';
    SELECT COUNT(*) INTO redis_table_num FROM information_schema.tables WHERE table_type = 'BASE TABLE' AND table_name = redis_table_prefix||'_'||redis_table_name;
    IF(redis_table_num = 0) THEN
        executesql := 'CREATE TABLE '||redis_table||' (' ||
                                    '"foreigns" VARCHAR(150) NOT NULL,' ||
                                    '"storage" VARCHAR(50) NOT NULL,' ||
                                    '"store" VARCHAR(50) NOT NULL,' ||
                                    '"tables" VARCHAR(200) DEFAULT NULL,' ||
                                    '"databases" SMALLINT DEFAULT 0,' ||
                                    '"numbers" INTEGER DEFAULT 0,' ||
                                    '"datetime" TIMESTAMP(3) WITHOUT TIME ZONE NOT NULL DEFAULT now(),' ||
                                    'PRIMARY KEY ("foreigns")'
                                    ');' ||
                                    'COMMENT ON TABLE ' || redis_table || ' IS ''开发日志记录'';' ||
                                    'COMMENT ON COLUMN ' || redis_table || '."foreigns" IS ''Redis外部表名'';' ||
                                    'COMMENT ON COLUMN ' || redis_table || '."storage" IS ''前端本地存储方式'';' ||
                                    'COMMENT ON COLUMN ' || redis_table || '."store" IS ''前端本地存储store名'';' ||
                                    'COMMENT ON COLUMN ' || redis_table || '."tables" IS ''数据库查询表名'';' ||
                                    'COMMENT ON COLUMN ' || redis_table || '."databases" IS ''Redis数据库id'';' ||
                                    'COMMENT ON COLUMN ' || redis_table || '."numbers" IS ''数据缓存数量'';' ||
                                    'COMMENT ON COLUMN ' || redis_table || '."datetime" IS ''最后更新时间'';';
        EXECUTE executesql;
    END IF;
    IF(lower(type_val) = 'empty') THEN
        IF(foreign_table IS NULL) THEN
            SELECT array_agg(table_name::VARCHAR) INTO foreign_table_array FROM information_schema.tables WHERE table_type = 'FOREIGN TABLE' AND table_name LIKE 'redis_%';
            IF(foreign_table_array IS NOT NULL) THEN
                FOREACH foreign_table IN ARRAY foreign_table_array
                LOOP
                    executesql := 'DELETE FROM '||redis_table||' WHERE foreigns = $1;';
                    EXECUTE executesql USING foreign_table;
                    executesql := 'DELETE FROM "' || foreign_table || '";';
                    EXECUTE executesql;
                    executesql := 'DROP FOREIGN TABLE IF EXISTS "' || foreign_table || '";';
                    EXECUTE executesql;
                END LOOP;
            END IF;
            executesql := 'DROP TABLE '||redis_table||';';
            EXECUTE executesql USING foreign_table;
            RETURN json_build_object('type', 'Success', 'message', '服务器中所有的Redis缓存已经被清空!', 'code', 200);
        ELSE
            executesql := 'DELETE FROM '||redis_table||' WHERE foreigns = $1;';
            EXECUTE executesql USING foreign_table;
            executesql := 'DELETE FROM "' || foreign_table || '";';
            EXECUTE executesql;
            executesql := 'DROP FOREIGN TABLE IF EXISTS "' || foreign_table || '";';
            EXECUTE executesql;
            RETURN json_build_object('type', 'Success', 'message', '服务器中【' || foreign_table || '】的Redis缓存已经被清空!', 'code', 200);
        END IF;
    ELSE
        IF (json_extract_path_text(redis, 'pk') IS NOT NULL) THEN
            pk_val := json_extract_path_text(redis, 'pk');
        ELSE
            RETURN json_build_object('type', 'Error', 'message', 'Redis缓存pk参数不能为空!', 'code', 230);
        END IF;
        IF (json_extract_path_text(redis, 'storage') IS NOT NULL) THEN
            storage_val := json_extract_path_text(redis, 'storage');
        ELSE
            RETURN json_build_object('type', 'Error', 'message', 'Redis缓存storage参数不能为空!', 'code', 230);
        END IF;
        IF (json_extract_path_text(redis, 'store') IS NOT NULL) THEN
            store_val := json_extract_path_text(redis, 'store');
        ELSE
            RETURN json_build_object('type', 'Error', 'message', 'Redis缓存store参数不能为空!', 'code', 230);
        END IF;
        IF (json_extract_path_text(redis, 'table') IS NOT NULL) THEN
            table_val := json_extract_path_text(redis, 'table');
        END IF;
        IF (json_extract_path_text(redis, 'primary') IS NOT NULL) THEN
            where_val := json_extract_path_text(redis, 'primary') || ' = ' || pk_val;
        ELSE
            IF (json_extract_path_text(redis, 'where') IS NOT NULL) THEN
                where_val := json_extract_path_text(redis, 'where');
            END IF;
        END IF;
        IF (json_extract_path_text(redis, 'data') IS NOT NULL) THEN
            data_val := json_extract_path_text(redis, 'data');
        END IF;
        IF (json_extract_path_text(redis, 'databases') IS NOT NULL) THEN
            databases := json_extract_path_text(redis, 'databases');
        END IF;
        IF(foreign_table IS NULL) THEN
            foreign_table := 'redis_' || storage_val || '_' || store_val;
        END IF;
        SELECT COUNT(*) INTO foreign_table_num FROM information_schema.tables WHERE table_type = 'FOREIGN TABLE' AND table_name = foreign_table;
        if(foreign_table_num = 0) THEN
            executesql := 'CREATE FOREIGN TABLE "' || foreign_table || '" ("key" text, "val" json) SERVER redis_server OPTIONS ( database ''' || databases || ''');';
            EXECUTE executesql;
            executesql := 'INSERT INTO '||redis_table||' ("foreigns", "storage", "store", "tables", "databases") VALUES($1, $2, $3, $4, $5);';
            EXECUTE executesql USING foreign_table, storage_val, store_val, table_val, databases;
        ELSE
            executesql := 'SELECT databases FROM '||redis_table||' WHERE foreigns = $1;';
            EXECUTE executesql INTO databases USING foreign_table;
        END IF;
        redis_key := storage_val || '_' || store_val || ':' || pk_val;
        executesql := 'SELECT COUNT(*) FROM "' || foreign_table || '" WHERE "key" = $1;';
        EXECUTE executesql INTO redis_key_num USING redis_key;
        IF (table_val IS NULL AND where_val IS NULL AND data_val IS NULL) THEN
            IF (redis_key_num > 0) THEN
                executesql := 'UPDATE "'||redis_table||' SET numbers = numbers - 1, datetime = now() WHERE foreigns = $1;';
                EXECUTE executesql USING foreign_table;
                executesql := 'DELETE FROM "' || foreign_table || '" WHERE "key" = $1;';
                EXECUTE executesql USING redis_key;
                IF(pk_val != 'redisForeign') THEN
                    PERFORM structure_redis(json_build_object(
                                                                        'pk', 'redisForeign',
                                                                        'databases', 15,
                                                                        'storage', 'indexedDBStorage',
                                                                        'store', 'foreignList',
                                                                        'table', redis_table_prefix||'_'||redis_table_name
                                                                ));
                END IF;
                RETURN json_build_object('type', 'Success', 'message', '删除Redis缓存['||redis_key||']成功!', 'databases', databases, 'code', 230);
            ELSE
                RETURN json_build_object('type', 'Error', 'message', '未发现['||redis_key||']的Redis缓存!', 'code', 230);
            END IF;
        ELSE
            IF(table_val IS NULL AND data_val IS NULL)THEN
                RETURN json_build_object('type', 'Error', 'message', 'Redis缓存table参数和data参数不能同时为空!', 'code', 230);
            ELSE
                IF (table_val IS NOT NULL) THEN
                    IF(where_val IS NULL) THEN
                        IF(lower(type_val) = 'info') THEN
                            executesql := 'SELECT json_agg(' || table_val || ')->0 FROM "' || table_val || '" LIMIT 1;';
                        ELSE
                            executesql := 'SELECT json_agg(' || table_val || ') FROM "' || table_val || '";';
                        END IF;
                    ELSE
                        IF(lower(type_val) = 'info') THEN
                            executesql := 'SELECT json_agg(' || table_val || ')->0 FROM "' || table_val || '" WHERE ' || where_val || ' LIMIT 1;';
                        ELSE
                            executesql := 'SELECT json_agg(' || table_val || ') FROM "' || table_val || '" WHERE ' || where_val || ';';
                        END IF;
                    END IF;
                    EXECUTE executesql INTO data_val;
                END IF;
            END IF;
            IF(lower(type_val) = 'list') THEN
                IF(data_val IS NULL) THEN
                    data_val := json_build_array();
                END IF;
            ELSE
                IF(data_val IS NULL) THEN
                    data_val := json_build_object();
                END IF;
            END IF;
            IF (redis_key_num > 0) THEN
                executesql := 'UPDATE "' || foreign_table || '" SET "val" = $1 WHERE "key" = $2;';
                EXECUTE executesql USING data_val, redis_key;
                executesql := 'UPDATE '|| redis_table || ' SET datetime = now() WHERE foreigns = $1;';
                EXECUTE executesql USING foreign_table;
                IF(pk_val != 'redisForeign') THEN
                    PERFORM structure_redis(json_build_object(
                                                                        'pk', 'redisForeign',
                                                                        'databases', 15,
                                                                        'storage', 'indexedDBStorage',
                                                                        'store', 'foreignList',
                                                                        'table', redis_table_prefix||'_'||redis_table_name
                                                                ));
                END IF;
                RETURN json_build_object(
                        'type', 'Success',
                        'message', '更新Redis缓存['||redis_key||']成功!',
                        'code', 200,
                        'debug', json_build_object(
                                'pk', pk_val,
                                'table', table_val,
                                'where', where_val
                        ),
                        'redis', json_build_array(
                                json_build_object(
                                        'pk', pk_val,
                                        'databases', databases,
                                        'storage', storage_val,
                                        'store', store_val,
                                        'table', store_val,
                                        'type', type_val,
                                        'key', redis_key
                                )
                        )
                );
            ELSE
                executesql := 'INSERT INTO "' || foreign_table || '" ("key", "val") VALUES ($1, $2);';
                EXECUTE executesql USING redis_key, data_val;
                executesql := 'UPDATE '||redis_table||' SET numbers = numbers + 1, datetime = now() WHERE foreigns = $1;';
                EXECUTE executesql USING foreign_table;
                IF(pk_val != 'redisForeign') THEN
                    PERFORM structure_redis(json_build_object(
                                                                        'pk', 'redisForeign',
                                                                        'databases', 15,
                                                                        'storage', 'indexedDBStorage',
                                                                        'store', 'foreignList',
                                                                        'table', redis_table_prefix||'_'||redis_table_name
                                                                ));
                END IF;
                RETURN json_build_object(
                        'type', 'Success',
                        'message', '添加Redis缓存['||redis_key||']成功!',
                        'code', 230,
                        'debug', json_build_object(
                                'pk', pk_val,
                                'table', table_val,
                                'where', where_val
                        ),
                        'redis', json_build_array(
                                json_build_object(
                                        'pk', pk_val,
                                        'databases', databases,
                                        'storage', storage_val,
                                        'store', store_val,
                                        'table', store_val,
                                        'type', type_val,
                                        'key', redis_key
                                )
                        )
                );
            END IF;
        END IF;
    END IF;
    EXCEPTION WHEN OTHERS THEN
    RETURN json_build_object('type', 'Error', 'message', '系统Redis缓存操作失败!', 'error', replace(SQLERRM, '"', '`'), 'sqlstate', SQLSTATE);
END;
$$ LANGUAGE plpgsql;

4. 基于ThinkPHP 5.1Redis 操作模型

  • A. 调用方法

    • A.1 清空所有Redis数据

    $redisData = model\Base::structureRedis(['type'  => 'empty']);
    
    • A.2 删除指定RedisKEY数据

    删除KEYsessionStorage_userInfo:5Redis数据

    $redisData = model\Base::structureRedis([
                      'pk'        => 5,
                      'type'      => 'empty',
                      'storage'   => 'sessionStorage',
                      'store'     => 'userInfo'
    ]);
    
    • A.3 获取指定Redis数据,如果不存在则根据tablewhere创建Redis数据

    获取KEY值为sessionStorage_userInfo:5Redis数据,如果该数据不存在则根据tablewhere创建Redis数据

    $return = model\Base::structureRedis([
                      'pk'        => 5,
                      'type'      => 'info',
                      'databases' => 1,
                      'storage'   => 'sessionStorage',
                      'store'     => 'userInfo',
                      'table'     => 'public_user',
                      'where'     => 'uid = 5'
                  ]);
    
    • A.4 获取指定Redis数据,如果不存在则根据tableprimary创建Redis数据

    获取KEY值为sessionStorage_userInfo:5Redis数据,如果该数据不存在则根据tableprimary创建Redis数据

    $return = model\Base::structureRedis([
                      'pk'        => 5,
                      'type'      => 'info',
                      'databases' => 1,
                      'storage'   => 'sessionStorage',
                      'store'     => 'userInfo',
                      'table'     => 'public_user',
                      'primary'   => 'uid'
                  ]);
    
    • A.5 获取指定Redis数据,强制根据tableprimary创建Redis数据

    强制根据tableprimary创建Redis数据后, 返回KEY值为sessionStorage_userInfo:5Redis数据

    $return = model\Base::structureRedis([
                      'pk'        => 5,
                      'type'      => 'info',
                      'databases' => 1,
                      'storage'   => 'sessionStorage',
                      'store'     => 'userInfo',
                      'table'     => 'public_user',
                      'where'     => 'uid = 5'
                  ], true);
    
  • B. 程序代码

namespace app\redis\model;

use think\Model;
use think\Db;

class Base extends Model{
     /**
     * # 数组数据按条件筛选方法
     * @param $array    待筛选的数组
     * @param $filter   筛选条件: ['key' => '筛选键值名', 'val' => '筛选值', 'operator' => '筛选运算符']
     * @return mixed    返回匹配的数组值
     */
    protected static function arrayFilter($array, $filter){
        $filter = array_filter($array, function($val) use ($filter){
            switch($filter['operator']){
                case 'regexp':
                    return preg_match($filter['val'], $val[$filter['key']]);
                case 'between':
                    return $val[$filter['key']] >= $filter['val'][0] && $val[$filter['key']] <= $filter['val'][1];
                case '<':
                    return $val[$filter['key']] < $filter['val'];
                case '<=':
                    return $val[$filter['key']] <= $filter['val'];
                case '>':
                    return $val[$filter['key']] > $filter['val'];
                case '>=':
                    return $val[$filter['key']] >= $filter['val'];
                case '=':
                default:
                    return $val[$filter['key']] == $filter['val'];
            }
        });
        foreach(array_keys($filter) as $v){
            $return[] = $filter[$v];
        }
        return $return;
    }

    /**
     * # 运行数据库存储过程
     * @param       $name       存储过程名
     * @param array $param      存储过程参数数组或字符串
     * @param string $type      数据链接类型,默认:thinkphp,可选:adodb
     * @return mixed
     */
    protected static function callProcedure($name, $param = array(), $type = 'thinkphp'){
        if($type == 'adodb'){
            $db_conf = config('database.');
            $db = ADONewConnection($db_conf['type']);
            $db->Connect($db_conf['hostname'], $db_conf['username'], $db_conf['password'], $db_conf['database']);
            $db->setFetchMode(ADODB_FETCH_ASSOC);
            if(is_array($param))
                $logic = $db->getAll("SELECT ".$name."('".json_encode($param)."');");
            else
                $logic = $db->getAll("SELECT ".$name."('".$param."');");
        }else{
            if(is_array($param))
                $logic = Db::query("SELECT ".$name."('".json_encode($param)."');");
            else
                $logic = Db::query("SELECT ".$name."('".$param."');");
        }
        return json_decode($logic[0][$name], true);
    }

    /**
     * # 链接Redis服务器
     * @param int $dbindex  链接数据库index,默认:0,范围:0~15
     * @return \Redis
     */
    protected static function connectRedis($dbindex = 0){
        $redis = new \Redis();
        $conf = config('redis.');
        $redis->connect($conf['host'], $conf['port'], $conf['timeout']);
        $redis->auth($conf['password']);//登录验证密码,返回【true | false】
        $redis->select($dbindex);
        return $redis;
    }

    /**
     * # 操作redis方法
     * @param      $param       操作参数
     * @param bool $refresh     是否强制刷新
     * @return array|mixed
     */
    public static function structureRedis($param, $refresh = false){
        if(array_key_exists('storage', $param) && array_key_exists('store', $param)){
            $redis = self::connectRedis(15);
            $map = $redis->get('indexedDBStorage_foreignList:redisForeign');
            $filter = self::arrayFilter(json_decode($map, true), ['key' => 'foreigns', 'val' => 'redis_'.$param['storage'].'_'.$param['store']]);
            if(count($filter[0]) > 0){
                $foreign = array_merge($param, $filter[0]);
                if(array_key_exists('tables', $foreign)) $foreign['table'] = $foreign['tables'];
            }else{
                $foreign = $param;
                $foreign['databases'] = (array_key_exists('databases', $param))?$param['databases']:0;
            }
            $redis = self::connectRedis($foreign['databases']);
            if(array_key_exists('pk', $foreign)){
                $key = $foreign['storage'].'_'.$foreign['store'].':'.$foreign['pk'];
            }else{
                if(array_key_exists('key', $foreign)){
                    $key = $foreign['key'];
                }else{
                    return ['type' => 'Error', 'message' => '参数不正确,缺少pk或者key参数', 'param' => $foreign];
                }
            }
            if(!$redis->get($key) || $refresh){
                if(array_key_exists('table', $foreign) || array_key_exists('data', $foreign)){
                    $logic = self::callProcedure('structure_redis', $foreign);
                    if(strtolower($logic['type']) == 'error') return $logic;
                }else{
                    return ['type' => 'Error', 'message' => '参数不正确,缺少table或者data参数', 'param' => $foreign];
                }
            }
            return json_decode($redis->get($key), true);
        }else{
            if(array_key_exists('type', $param) && $param['type'] == 'empty'){
                $logic = self::callProcedure('structure_redis', $param);
                return json_decode($logic, true);
            }else{
                return ['type' => 'Error', 'message' => '参数不正确,缺少storage或者store参数', 'param' => $param];
            }
        }
    }
}

你可能感兴趣的:(PostgreSQL下用于操作Redis的存储过程)