- Markdown 编辑器:实时预览、PDF 导出、独立查看器 - 数据库优化:动态连接池、查询缓存、Redis Pipeline - 窗口置顶功能 - 文件系统增强:右键菜单、编辑器集成、收藏夹重构 - 安全修复:XSS 防护、路径穿越、HTML 注入 - 代码质量:正则预编译、缓存锁优化、死代码清理
152 lines
3.4 KiB
Go
152 lines
3.4 KiB
Go
package dbclient
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"log"
|
||
|
||
"github.com/redis/go-redis/v9"
|
||
)
|
||
|
||
// RedisPipeline Redis Pipeline 操作
|
||
type RedisPipeline struct {
|
||
client *RedisClient
|
||
commands []RedisCommand
|
||
ctx context.Context
|
||
}
|
||
|
||
// RedisCommand Redis 命令结构
|
||
type RedisCommand struct {
|
||
Command string
|
||
Args []interface{}
|
||
Result interface{}
|
||
Error error
|
||
}
|
||
|
||
// NewRedisPipeline 创建新的 Redis Pipeline
|
||
func (r *RedisClient) NewPipeline(ctx context.Context) *RedisPipeline {
|
||
return &RedisPipeline{
|
||
client: r,
|
||
commands: make([]RedisCommand, 0),
|
||
ctx: ctx,
|
||
}
|
||
}
|
||
|
||
// AddCommand 添加命令到 Pipeline
|
||
func (p *RedisPipeline) AddCommand(command string, args ...interface{}) {
|
||
p.commands = append(p.commands, RedisCommand{
|
||
Command: command,
|
||
Args: args,
|
||
})
|
||
}
|
||
|
||
// Execute 使用 go-redis 原生 Pipeline 执行所有命令
|
||
func (p *RedisPipeline) Execute() ([]interface{}, error) {
|
||
if len(p.commands) == 0 {
|
||
return nil, nil
|
||
}
|
||
|
||
pipe := p.client.client.Pipeline()
|
||
|
||
cmds := make([]*redis.Cmd, len(p.commands))
|
||
for i, c := range p.commands {
|
||
cmds[i] = pipe.Do(p.ctx, append([]interface{}{c.Command}, c.Args...)...)
|
||
}
|
||
|
||
// 一次性发送所有命令
|
||
results := make([]interface{}, len(p.commands))
|
||
cmdResults, err := pipe.Exec(p.ctx)
|
||
if err != nil && err != redis.Nil {
|
||
log.Printf("[RedisPipeline] Exec 错误: %v", err)
|
||
}
|
||
|
||
for i, cmd := range cmds {
|
||
result, cmdErr := cmd.Result()
|
||
results[i] = result
|
||
p.commands[i].Result = result
|
||
p.commands[i].Error = cmdErr
|
||
}
|
||
|
||
// 如果 Exec 返回了命令结果(部分 Redis 版本),使用它们
|
||
for i, cr := range cmdResults {
|
||
if cr.Err() != nil && cr.Err() != redis.Nil {
|
||
p.commands[i].Error = cr.Err()
|
||
if i < len(results) {
|
||
results[i] = nil
|
||
}
|
||
}
|
||
}
|
||
|
||
_ = results // 已经通过 cmds 获取
|
||
return results, nil
|
||
}
|
||
|
||
// GetCommands 获取 Pipeline 中的命令列表
|
||
func (p *RedisPipeline) GetCommands() []RedisCommand {
|
||
return p.commands
|
||
}
|
||
|
||
// Len 获取 Pipeline 中的命令数量
|
||
func (p *RedisPipeline) Len() int {
|
||
return len(p.commands)
|
||
}
|
||
|
||
// Clear 清空 Pipeline
|
||
func (p *RedisPipeline) Clear() {
|
||
p.commands = make([]RedisCommand, 0)
|
||
}
|
||
|
||
// RedisTransaction Redis 事务支持
|
||
type RedisTransaction struct {
|
||
client *RedisClient
|
||
watch []string
|
||
cmds []RedisCommand
|
||
ctx context.Context
|
||
}
|
||
|
||
// NewRedisTransaction 创建新的 Redis 事务
|
||
func (r *RedisClient) NewTransaction(ctx context.Context, watch ...string) *RedisTransaction {
|
||
return &RedisTransaction{
|
||
client: r,
|
||
watch: watch,
|
||
ctx: ctx,
|
||
}
|
||
}
|
||
|
||
// AddCommand 添加命令到事务
|
||
func (tx *RedisTransaction) AddCommand(command string, args ...interface{}) {
|
||
tx.cmds = append(tx.cmds, RedisCommand{
|
||
Command: command,
|
||
Args: args,
|
||
})
|
||
}
|
||
|
||
// Exec 使用 go-redis Watch + TxPipeline 执行事务(MULTI/EXEC)
|
||
func (tx *RedisTransaction) Exec() ([]interface{}, error) {
|
||
pipe := tx.client.client.TxPipeline()
|
||
|
||
// 添加所有命令
|
||
cmds := make([]*redis.Cmd, len(tx.cmds))
|
||
for i, c := range tx.cmds {
|
||
cmds[i] = pipe.Do(tx.ctx, append([]interface{}{c.Command}, c.Args...)...)
|
||
}
|
||
|
||
// TxPipeline 自动发送 MULTI/EXEC
|
||
results := make([]interface{}, len(tx.cmds))
|
||
_, err := pipe.Exec(tx.ctx)
|
||
|
||
for i, cmd := range cmds {
|
||
result, cmdErr := cmd.Result()
|
||
results[i] = result
|
||
tx.cmds[i].Result = result
|
||
tx.cmds[i].Error = cmdErr
|
||
}
|
||
|
||
if err != nil && err != redis.Nil {
|
||
return results, fmt.Errorf("事务执行失败: %v", err)
|
||
}
|
||
|
||
return results, nil
|
||
}
|
||
|