首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

MySQL UDF + Trigger 實現資料自動同步至 Redis:C++ 開發完整實戰

     編輯:MySQL 綜合教學

MySQL UDF + Trigger 實現資料自動同步至 Redis:C++ 開發完整實戰

架構模式:MySQL 作為主存儲,Redis 作為緩存層。透過 UDF (User Defined Function) 封裝 Redis 客戶端操作,Trigger 捕獲資料異動自動呼叫 UDF,業務代碼無感知完成雙寫同步。

核心組件

  1. UDF (C++ 動態庫):實作 redis_hset(key, field, value) 寫入 Redis Hash
  2. Trigger:AFTER INSERT/UPDATE/DELETE ON table 呼叫 UDF
  3. 業務層:僅操作 MySQL,無需感知 Redis

UDF 開發流程

1. 環境準備

yum install mysql-devel boost boost-devel -y
git clone https://github.com/mrpi/redis-cplusplus-client

2. 核心 API 實作 (redis_hset 範例)

// test.cpp
#include 
#include "redisclient.h"
using namespace std;

static redis::client *g_client = NULL;

extern "C" char *redis_hset(UDF_INIT *initid, UDF_ARGS *args,
                            char *result, unsigned long *length,
                            char *is_null, char *error) {
    try {
        // 懶加載連線 (支援環境變數 REDIS_HOST)
        if (!g_client) {
            const char* c_host = getenv("REDIS_HOST");
            string host = c_host ? c_host : "127.0.0.1";
            g_client = new redis::client(host);
        }
        // 參數檢查
        if (!(args->args && args->args[0] && args->args[1] && args->args[2])) {
            *is_null = 1; return result;
        }
        // 呼叫 Redis HSET
        if (g_client->hset(args->args[0], args->args[1], args->args[2])) {
            return result;  // 成功回傳空字串
        } else {
            *error = 1; return result;
        }
    } catch (const redis::redis_error& e) {
        return result;
    }
}

extern "C" my_bool redis_hset_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
    if (3 != args->arg_count) {
        strncpy(message, "Usage: redis_hset('key', 'field', 'value')", MYSQL_ERRMSG_SIZE);
        return -1;
    }
    // 強制字串型別
    args->arg_type[0] = args->arg_type[1] = args->arg_type[2] = STRING_RESULT;
    initid->ptr = NULL;
    return 0;
}

3. 編譯部署

g++ -shared -fPIC -I /usr/include/mysql \
    -lboost_serialization -lboost_system -lboost_thread \
    -o libmyredis.so anet.c test.cpp

cp libmyredis.so /usr/lib64/mysql/plugin/
chmod 777 /usr/lib64/mysql/plugin/libmyredis.so

4. MySQL 註冊函數

CREATE FUNCTION redis_hset RETURNS STRING SONAME 'libmyredis.so';

Trigger 定義

DELIMITER $
CREATE TRIGGER tg_student_sync
AFTER INSERT ON Student
FOR EACH ROW
BEGIN
    SET @id = (SELECT redis_hset(CONCAT('stu_', NEW.Sid), 'id', CAST(NEW.Sid AS CHAR(8))));
    SET @name = (SELECT redis_hset(CONCAT('stu_', NEW.Sid), 'name', CAST(NEW.Sname AS CHAR(20))));
    SET @age = (SELECT redis_hset(CONCAT('stu_', NEW.Sid), 'age', CAST(NEW.Sage AS CHAR)));
    SET @gender = (SELECT redis_hset(CONCAT('stu_', NEW.Sid), 'gender', CAST(NEW.Sgen AS CHAR)));
    SET @dept = (SELECT redis_hset(CONCAT('stu_', NEW.Sid), 'department', CAST(NEW.Sdept AS CHAR(10))));
END$
DELIMITER ;

驗證測試

mysql> INSERT INTO Student VALUES('09388165', 'Rose', 19, 'F', 'SS3-205');
Query OK, 1 row affected (0.27 sec)

redis-cli> HGETALL stu_09388165
1) "id"        2) "09388165"
3) "name"      4) "Rose"
5) "age"       6) "19"
7) "gender"    8) "F"
9) "department" 10) "SS3-205"

擴展方向

  • 支援 UPDATE/DELETE 觸發器同步修改/刪除
  • UDF 實作連線池、重試、熔斷機制提升穩定性
  • 雙寫一致性:Binlog 監聽 (Canal/Maxwell) 作為兜底補償
  • 效能優化:批次寫入、Pipeline、非同步佇列

風險提醒

  • UDF 運行在 MySQL 進程內,崩潰會導致 MySQL 宕機 → 代碼需極度謹慎、充分測試
  • Redis 故障會阻塞 MySQL 寫入 → 建議 UDF 內設定超時、失敗不拋錯僅記錄日誌
  • 大量寫入場景考慮異步同步架構 (Binlog -> Kafka -> Consumer -> Redis)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved