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];
            }
        }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容