DeepSeek辅助编写的带缓存检查的数据库查询缓存系统

发布于:2025-08-09 ⋅ 阅读:(15) ⋅ 点赞:(0)

以下是加入缓存检查逻辑的完整程序,如果查询已存在缓存中,则直接使用缓存结果:

import db.sqlite
import x.json2
import os
import strings

struct QueryCache {
    id int
    sql_query string
    description string
    json_data string
    created_at string
}

fn main() {
    // 连接缓存数据库
    mut cache_db := sqlite.connect('query_cache.db') or {
        eprintln('连接缓存数据库失败: ${err}')
        return
    }
    defer {
        cache_db.close() or {}
    }

    // 主循环
    for {
        // 用户输入
        query := os.input('\n请输入SQL查询语句(输入q退出): ')
        if query == 'q' {
            println('退出程序')
            break
        }

        description := os.input('请输入查询描述(中文): ')

        // 1. 首先检查缓存
        cached_rows := cache_db.exec_param('
            SELECT json_data 
            FROM result_cache 
            WHERE sql_query = ? 
            LIMIT 1
        ', query) or {
            eprintln('检查缓存失败: ${err}')
            continue
        }

        if cached_rows.len > 0 {
            println('(从缓存读取结果)')
            display_results(cached_rows[0].vals[0].str())
            continue
        }

        println('(执行新查询并缓存结果)')

        // 2. 连接源数据库并执行查询(缓存不存在时才执行)
        mut source_db := sqlite.connect('food.db') or {
            eprintln('连接源数据库失败: ${err}')
            continue
        }

        // 使用exec_map获取结果
        rows := source_db.exec_map(query) or {
            source_db.close() or {}
            eprintln('查询执行失败: ${err}')
            continue
        }

        // 3. 转换引号并存入缓存
        json_data := convert_quotes_only(rows)
        println('\n即将存入的JSON数据:')
        println(json_data)
        
        cache_db.exec_param_many('
            INSERT OR REPLACE INTO result_cache 
            (sql_query, description, json_data)
            VALUES (?, ?, ?)
        ', [query, description, json_data]) or {
            source_db.close() or {}
            eprintln('缓存结果失败: ${err}')
            continue
        }

        source_db.close() or {}

        // 4. 从缓存中读取最新结果并显示
        new_cached_rows := cache_db.exec_param('
            SELECT json_data 
            FROM result_cache 
            WHERE sql_query = ? 
            LIMIT 1
        ', query) or {
            eprintln('读取缓存失败: ${err}')
            continue
        }

        if new_cached_rows.len == 0 {
            eprintln('意外错误: 缓存写入成功但读取失败')
            continue
        }

        display_results(new_cached_rows[0].vals[0].str())
    }
}

fn convert_quotes_only(rows []map[string]string) string {
    mut json_str := strings.new_builder(1024)
    json_str.write_string('[')
    
    for i, row in rows {
        if i > 0 {
            json_str.write_string(', ')
        }
        
        json_str.write_string('{')
        mut first := true
        
        for key, val in row {
            if !first {
                json_str.write_string(', ')
            }
            
            escaped_key := json2.encode(key).trim('"')
            escaped_val := json2.encode(val).trim('"')
            
            json_str.write_string('"${escaped_key}":"${escaped_val}"')
            first = false
        }
        
        json_str.write_string('}')
    }
    
    json_str.write_string(']')
    result := json_str.str()
    json_str.free()
    return result
}

fn display_results(json_data string) {
    raw_data := json2.raw_decode(json_data) or {
        println('JSON解析失败: $err')
        return
    }

    json_array := raw_data.arr()
    if json_array.len == 0 {
        println('空结果集')
        return
    }

    first_obj := json_array[0].as_map()
    mut headers := []string{}
    mut alignments := []string{}
    
    for key, val in first_obj {
        headers << key
        if val is int || val is f64 {
            alignments << '--:'
        } else {
            alignments << '--'
        }
    }

    println('\n查询结果:')
    println(headers.join('|'))
    println(alignments.join('|'))

    for item in json_array {
        obj := item.as_map()
        mut row := []string{}
        for header in headers {
            val := obj[header] or { json2.Null{} }
            if val is json2.Null {
                row << 'NULL'
            } else {
                row << val.str()
            }
        }
        println(row.join('|'))
    }
}

主要改进点

  1. 缓存检查逻辑

    • 在用户输入查询后,首先检查缓存是否存在该查询结果
    • 如果存在,直接显示缓存结果并跳过后续步骤
    • 如果不存在,才执行源数据库查询和缓存写入
  2. 用户提示

    • 添加"(从缓存读取结果)“和”(执行新查询并缓存结果)"提示
    • 让用户清楚知道数据来源
  3. 性能优化

    • 避免不必要的源数据库查询
    • 减少重复数据的处理和存储
  4. 流程清晰

    • 将程序流程分为明确的4个步骤:
      1. 检查缓存
      2. 查询源数据库(仅在缓存不存在时)
      3. 写入缓存(新查询时)
      4. 显示结果

使用示例

执行本程序前首先准备好2个sqlite数据库

#!/bin/bash

# 初始化源数据库
sqlite3 food.db <<EOF
CREATE TABLE IF NOT EXISTS foods (
    id INTEGER PRIMARY KEY,
    name TEXT,
    category TEXT,
    calories INTEGER,
    fats_g REAL,
    sugars_g REAL
);
EOF

sqlite3 food.db "INSERT INTO foods VALUES(1,'Apple','fruit',52,0.2,10.4);"
sqlite3 food.db "INSERT INTO foods VALUES(2,'Chicken','meat',239,14,0);"
# 初始化缓存数据库
sqlite3 query_cache.db <<EOF
CREATE TABLE IF NOT EXISTS result_cache (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    sql_query TEXT UNIQUE,
    description TEXT,
    json_data TEXT,
    created_at TEXT DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_sql_query ON result_cache(sql_query);
EOF

echo "数据库初始化完成"

然后如此执行

请输入SQL查询语句(输入q退出): SELECT * FROM foods
请输入查询描述(中文): 获取所有食物
(执行新查询并缓存结果)

即将存入的JSON数据:
[{"id":"1","name":"Apple","category":"fruit","calories":"52","fats_g":"0.2","sugars_g":"10.4"},{"id":"2","name":"Chicken","category":"meat","calories":"239","fats_g":"14.0","sugars_g":"0.0"}]

查询结果:
id|name|category|calories|fats_g|sugars_g
--|--|--|--|--|--
1|Apple|fruit|52|0.2|10.4
2|Chicken|meat|239|14.0|0.0

请输入SQL查询语句(输入q退出): SELECT * FROM foods
请输入查询描述(中文): 再次获取食物
(从缓存读取结果)

查询结果:
id|name|category|calories|fats_g|sugars_g
--|--|--|--|--|--
1|Apple|fruit|52|0.2|10.4
2|Chicken|meat|239|14.0|0.0

请输入SQL查询语句(输入q退出): select max(name) max_name,min(fats_g)*10 min_fats from foods
请输入查询描述(中文): 取出最大的食物和最小的脂肪
(执行新查询并缓存结果)

即将存入的JSON数据:
[{"max_name":"Chicken", "min_fats":"2.0"}]

查询结果:
max_name|min_fats
--|--
Chicken|2.0

请输入SQL查询语句(输入q退出): q
退出程序

从最初的设计,到最后正确,用了5个小时。中间很多曲折,难以尽述。


网站公告

今日签到

点亮在社区的每一天
去签到