Linux嵌入式系统SQlite3数据库学习笔记

前言

SQlite3是一个轻量级、嵌入式的关系型数据库管理系统,其中具有的核心特点:

1:嵌入式数据库:无需独立服务器进程,数据库直接嵌入到应用程序中。

2:单文件存储:整个数据库存储为单个文件(.db或.sqlite后缀),便于移植和备份。

3:跨平台:支持 Windows、Linux、macOS、iOS、Android 等系统。

相比于MySQl/PostgreSQL等数据库具有轻量级操作简单的优点。

一、数据库安装

可以直接使用命令安装

复制代码
# 更新软件源
sudo apt update

# 安装 SQLite3 命令行工具和库
sudo apt install sqlite3

# 可选:安装开发头文件(用于编程开发)
sudo apt install libsqlite3-dev

也可以直接去下载对应的安装包本地编译

复制代码
wget https://www.sqlite.org/2024/sqlite-autoconf-3440200.tar.gz
tar xvfz sqlite-autoconf-*.tar.gz
cd sqlite-autoconf-*/

# 编译安装
./configure
make
sudo make install

安装的话是比较简单的,毕竟是轻量级的数据库。

二、数据库使用方法

1:创建数据库

复制代码
sqlite3 xxxx.db //创建数据库

创建完数据库后进入数据库后开头就是sqlite>这样的

然后对数据库的操作的相关指令

复制代码
.open filename -- 打开文件
.show -- 显示SQKite命令提示符的默认设置
.q -- 退出
.databases -- 显示数据库
.help -- 帮助
.dump --导入导出数据库
.tables -- 查看表

2.数据类型

Sqlite3的主要数据类型

除了这些主要的数据类型之外还有别的数据类型

3.创建表

前面已经创建了数据库和知道了有那些数据类型,那么接下来就该进行数据库的核心操作"增删改查"。

创建表的话有两种方式一种是使用标准的SQL语句另外一种是使用对应的API接口函数,我看了很多文章很多博主是分开进行介绍的其本质还是一样的。

标准SQL语句

复制代码
CREATE TABLE Filename (列名 数据类型 ...)

API接口函数

对于SQlite3数据库的基本使用的话就三个核心API接口函数

1:打开数据库

函数原型:

cpp 复制代码
SQLITE_API int sqlite3_open(
  const char *filename,   /* Database filename (UTF-8) */
  sqlite3 **ppDb          /* OUT: SQLite db handle */
);

参数说明:

const char *filename:指向要打开的数据库文件名的字符串,可以带路径。

sqlite3 **ppDb:是一个指向SQlite的结构体的二级指针

函数返回值:

  1. 成功开发返回SQLITE_OK(0)。
  2. 失败返回错误码

补充说明:

cpp 复制代码
SQLITE_API int sqlite3_open16(
  const void *filename,   /* Database filename (UTF-16) */
  sqlite3 **ppDb          /* OUT: SQLite db handle */
);
SQLITE_API int sqlite3_open_v2(
  const char *filename,   /* Database filename (UTF-8) */
  sqlite3 **ppDb,         /* OUT: SQLite db handle */
  int flags,              /* Flags */
  const char *zVfs        /* Name of VFS module to use */
);

2:SQL语句执行函数

函数原型:

cpp 复制代码
SQLITE_API int sqlite3_exec(
  sqlite3*,                                  /* An open database */
  const char *sql,                           /* SQL to be evaluated */
  int (*callback)(void*,int,char**,char**),  /* Callback function */
  void *,                                    /* 1st argument to callback */
  char **errmsg                              /* Error msg written here */
);

函数参数:

sqlite3*:一个打开的数据库连接指针。

const char *sql:要执行的 SQL 语句字符串。可以是单个 SQL 语句或多个 SQL 语句的序列,以分号分隔。

int (*callback)(void*,int,char**,char**):回调函数,每当执行一个查询语句并返回结果时,这个回调函数会被调用。如果不需要处理查询结果,可以设置为 NULL。

void *:用户提供的指针,可以在回调函数中使用,通常用于传递上下文信息。

char **errmsg:如果发生错误,这个指针将被设置为指向一个包含错误信息的字符串。

函数返回值:

  1. 成功返回SQLITE_OK(0)。
  2. 失败返回错误码

3:关闭数据库

cpp 复制代码
SQLITE_API int sqlite3_close(sqlite3*);

函数参数:

数据库链接指针。

这三个函数就是SQLite3的基本API接口函数。可以直接使用SQL语句来进行相关的表操作,其本质与直接使用SQl语句操作数据库是一样的。除此之外还有一些高级用法。

创建表格的基础用法程序示例:

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <sqlite3.h>

//打开数据库函数示例
int main(int argc,char * argv[])
{
    sqlite3 *db;
    char *mang = 0;
    int rc;
    char *err_msg = 0;
    //1:连接数据库
    rc = sqlite3_open("./test.db",&db);//打开当前目录下的数据库
    if(rc)
    {
        //非0表示打开失败
        fprintf(stderr,"Can't open database: %s\n",sqlite3_errmsg(db));
    }else
    {
        //打开成功
        fprintf(stderr,"Opened database successfully\n");
    }
    //2:创建表
    /*
        构建SQLstatement
        创建一个名为files的表
        一共三列分别为:FILENAME DATE SIZE
        数据类型分别为:文本字符串 文本字符串 无符号整形
    */
    // 创建表的 SQL 语句
    const char *sql = 
        "CREATE TABLE IF NOT EXISTS files ("
        "FILENAME TEXT PRIMARY KEY,"
        "DATE TEXT NOT NULL,"
        "SIZE INTEGER NOT NULL);";

    //执行SQL命令创建表
    rc = sqlite3_exec(db,sql,0,0,&err_msg);
    if( rc != SQLITE_OK ){
    fprintf(stderr, "SQL error: %s\n", err_msg);
        sqlite3_free(err_msg);
    }else{
        fprintf(stdout, "Table created successfully\n");
    }

    sqlite3_close(db);//关闭数据库
    return 0;
}

查看上面的SQL语句做一下解释说明:

观察上面的写法可以看到其中处理规范中的内容多了一些:PRIMARY KEY、NOT NULL。

这些在sqlite3数据库中叫做约束,表中的每一列都有一些限制属性,这些限制属性就叫做约束。

这些约束在表中根据具体情况来使用。

4:插入数据

上面介绍的示例使用的SQL语句使用法,在表中插入数据当然也可以使用这个方法,

语法一:insert into 表名 (字段名称) values (值名称)。

例如:insert into user (id,age) values (1,10)。

语法二:insert into 表名 values(值 1,值 2,...)。

例如:insert into user values(3,"wang",11)。

经过我的学习中发现了另外的一种的用法为占位符使用

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <sqlite3.h>

//使用预处理语句添加元素
int main(int argc,char * argv[])
{
    sqlite3 *db;
    char *mang = 0;
    int rc;
    char *err_msg = 0;
    //1:连接数据库
    rc = sqlite3_open("./test.db",&db);//打开当前目录下的数据库
    if(rc)
    {
        //非0表示打开失败
        fprintf(stderr,"Can't open database: %s\n",sqlite3_errmsg(db));
    }else
    {
        //打开成功
        fprintf(stderr,"Opened database successfully\n");
    }

    // 插入数据的SQL语句(使用占为符?)
    const char *sql = 
        "INSERT INTO files (FILENAME,DATE,SIZE)VALUES(?,?,?);";

    sqlite3_stmt *stmt;

    rc = sqlite3_prepare_v2(db,sql,-1,&stmt,NULL);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "准备语句失败: %s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        return 1;
    }

    //绑定参数(索引从1开始)
    sqlite3_bind_text(stmt,1,"flie4.mp4",-1,SQLITE_STATIC);// FILENAME
    sqlite3_bind_text(stmt,2,"2025-04-21",-1,SQLITE_STATIC);//DATE
    sqlite3_bind_int(stmt,3,4096);//SIZE

    //执行插入
    rc = sqlite3_step(stmt);
    if(rc != SQLITE_DONE)
    {
        fprintf(stderr, "插入失败: %s\n", sqlite3_errmsg(db));
        sqlite3_finalize(stmt);
        sqlite3_close(db);
        return 1;
    }
    // 释放预处理语句资源
    sqlite3_finalize(stmt);
    printf("数据插入成功!\n");
    
    sqlite3_close(db);//关闭数据库
    return 0;
}
cpp 复制代码
SQLITE_API int sqlite3_prepare_v2(
  sqlite3 *db,            /* Database handle */
  const char *zSql,       /* SQL statement, UTF-8 encoded */
  int nByte,              /* Maximum length of zSql in bytes. */
  sqlite3_stmt **ppStmt,  /* OUT: Statement handle */
  const char **pzTail     /* OUT: Pointer to unused portion of zSql */
);

参数绑定函数后很多种,区别就在于对应的数据类型

|-----------------------|--------|
| 函数 | 数据类型 |
| sqlite3_bind_int() | 整数 |
| sqlite3_bind_double() | 浮点数 |
| sqlite3_bind_text() | 字符串 |
| sqlite3_bind_blob() | 二进制数据 |
| sqlite3_bind_null() | NULL 值 |

cpp 复制代码
SQLITE_API int sqlite3_step(sqlite3_stmt*);//插入函数

插入一条语句的话这样使用是没有问题的,那既然插入一条语句是这样的那么插入多条语句应该怎么实现。那就引出来一个全新的概念那就是事务。

对于事务这个概念就要引出ACID特性

|-------------------------|--------------------------------|
| 特性 | 描述 |
| ​原子性​​ (Atomicity) | 事务内的操作要么全部成功,要么全部回滚(不可分割的最小单元) |
| 一致性​​ (Consistency) | 事务执行后数据库必须保持有效状态(满足约束、触发器等规则) |
| 隔离性​​ (Isolation) | 并发事务之间互不干扰(通过锁机制实现) |
| 持久性​​ (Durability) | 事务提交后,修改永久保存(即使系统崩溃) |

在SQLite3中的事务用法

命令 作用
BEGIN TRANSACTION 开启事务(默认进入 DEFERRED 模式,首次读操作时获取锁)
COMMIT 提交事务(持久化更改)
ROLLBACK 回滚事务(撤销所有未提交的操作)
SAVEPOINT name 创建保存点(支持嵌套事务)
RELEASE SAVEPOINT name 释放保存点(提交到该点的操作)
ROLLBACK TO name 回滚到指定保存点

使用示例:

cpp 复制代码
//插入多条语句
int main() {
    sqlite3 *db;
    char *err_msg = NULL;
    int rc;

    // 打开数据库
    rc = sqlite3_open("test.db", &db);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "无法打开数据库: %s\n", sqlite3_errmsg(db));
        return 1;
    }

    // 开启事务(大幅提升批量插入速度)
    rc = sqlite3_exec(db, "BEGIN TRANSACTION;", NULL, NULL, &err_msg);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "事务开启失败: %s\n", err_msg);
        sqlite3_free(err_msg);
        sqlite3_close(db);
        return 1;
    }

    // 准备插入语句
    const char *sql = "INSERT INTO files (FILENAME, DATE, SIZE) VALUES (?, ?, ?);";
    sqlite3_stmt *stmt;
    rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "预处理失败: %s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        return 1;
    }

    // 示例数据(假设从数组或文件读取)
    const char *filenames[] = {"file1.txt", "file2.pdf", "file3.jpg","flie4.mp4"};
    const char *dates[] = {"2023-10-05", "2023-10-06", "2023-10-07","2023-10-07"};
    const int sizes[] = {1024, 2048, 3072,4096};

    // 插入多条数据
    for (int i = 0; i < 3; i++) {
        // 绑定参数
        sqlite3_bind_text(stmt, 1, filenames[i], -1, SQLITE_STATIC); // FILENAME
        sqlite3_bind_text(stmt, 2, dates[i], -1, SQLITE_STATIC);     // DATE
        sqlite3_bind_int(stmt, 3, sizes[i]);                         // SIZE

        // 执行插入
        rc = sqlite3_step(stmt);
        if (rc != SQLITE_DONE) {
            fprintf(stderr, "插入失败: %s\n", sqlite3_errmsg(db));
            sqlite3_exec(db, "ROLLBACK;", NULL, NULL, NULL); // 回滚事务
            sqlite3_finalize(stmt);
            sqlite3_close(db);
            return 1;
        }

        // 重置语句(不清除绑定)
        sqlite3_reset(stmt);
    }

    // 提交事务
    rc = sqlite3_exec(db, "COMMIT;", NULL, NULL, &err_msg);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "提交失败: %s\n", err_msg);
        sqlite3_free(err_msg);
    }

    // 释放资源
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    printf("成功插入 %d 条数据!\n", 3);
    return 0;
}

5:删除表数据

删除表中数据:

语法:delete from 表名 [满足条件]。

例如:

delete from user(删除表中所有数据)。

delete from user where id = 1(删除id=1的数据)。

删除表中的内容除了可以一次删除一条语句之外还可以一下删除具有相同的名字的所有数据。

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <sqlite3.h>
#include <string.h>
//删除表内容
/**
 * 删除表中数据(按文件名或日期)
 * @param db        数据库句柄
 * @param condition 条件类型:"filename" 或 "date"
 * @param value     条件值(如文件名或日期字符串)
 * @return          1: 成功, 0: 失败
 */
int delete_records(sqlite3 *db, const char *condition, const char *value) {
    sqlite3_stmt *stmt = NULL;
    char *err_msg = NULL;
    int rc;

    // 根据条件类型生成 SQL 语句
    const char *sql;
    if (strcmp(condition, "filename") == 0) {
        sql = "DELETE FROM files WHERE FILENAME = ?;";
    } else if (strcmp(condition, "date") == 0) {
        sql = "DELETE FROM files WHERE DATE = ?;";
    } else {
        fprintf(stderr, "无效的条件类型: 仅支持 'filename' 或 'date'\n");
        return 0;
    }

    // 准备预处理语句
    rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "预处理失败: %s\n", sqlite3_errmsg(db));
        return 0;
    }

    // 绑定参数(索引从 1 开始)
    sqlite3_bind_text(stmt, 1, value, -1, SQLITE_STATIC);

    // 执行删除操作
    rc = sqlite3_step(stmt);
    if (rc != SQLITE_DONE) {
        fprintf(stderr, "删除失败: %s\n", sqlite3_errmsg(db));
        sqlite3_finalize(stmt);
        return 0;
    }

    // 获取删除的行数
    int rows_affected = sqlite3_changes(db);
    printf("成功删除 %d 条数据\n", rows_affected);

    // 释放资源
    sqlite3_finalize(stmt);
    return 1;
}
int main(int argc,char * argv[])
{
    sqlite3 *db;
    int rc;

    //1:连接数据库
    rc = sqlite3_open("./test.db",&db);//打开当前目录下的数据库
    if(rc)
    {
        //非0表示打开失败
        fprintf(stderr,"Can't open database: %s\n",sqlite3_errmsg(db));
    }else
    {
        //打开成功
        fprintf(stderr,"Opened database successfully\n");
    }
    
    // // 示例 1:按文件名删除(删除 file1.txt)
    // if (!delete_records(db, "filename", "file1.txt")) {
    //     sqlite3_close(db);
    //     return 1;
    // }

    //示例 2:按日期删除(删除所有日期为 2025-04-21 的记录)
    if (!delete_records(db, "date", "2025-04-21")) {
        sqlite3_close(db);
        return 1;
    }

    // 关闭数据库
    sqlite3_close(db);
    return 0;
}

6:修改表数据

修改表中数据:

语法:update 表名 set 表字段 = 值 [满足条件]。

例如:

update user set id = 1 where name = 'li'。

update user set id = 1 where name = "li" and passwd = "123"。

update user set id = 2 where name = "li" or name = "zhao"。

使用示例:

cpp 复制代码
#include <stdio.h>
#include <sqlite3.h>

/**
 * 安全更新数据项(原子化操作)
 * @param db_name    数据库文件名
 * @param table_name 表名
 * @param old_value  旧数据值(需存在)
 * @param new_value  新数据值(需唯一)
 * @return           1: 成功, 0: 失败
 */
int update_data_item(const char* db_name,const char* table_name,const char* old_value,const char* new_value) 
{
    sqlite3 *db = NULL;
    sqlite3_stmt *stmt = NULL;
    char *sql = NULL;
    int rc, ret = 0;

    // 打开数据库
    if (sqlite3_open(db_name, &db) != SQLITE_OK) {
        fprintf(stderr, "数据库连接失败: %s\n", sqlite3_errmsg(db));
        return 0;
    }

    // 开启事务
    if (sqlite3_exec(db, "BEGIN;", NULL, NULL, NULL) != SQLITE_OK) {
        fprintf(stderr, "事务开启失败: %s\n", sqlite3_errmsg(db));
        goto cleanup;
    }

    // ------------------- 检查新值是否唯一 -------------------
    sql = sqlite3_mprintf("SELECT COUNT(*) FROM %w WHERE FILENAME=?;", table_name);
    rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
    sqlite3_free(sql);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "唯一性检查预处理失败: %s\n", sqlite3_errmsg(db));
        goto rollback;
    }

    sqlite3_bind_text(stmt, 1, new_value, -1, SQLITE_STATIC);
    if (sqlite3_step(stmt) != SQLITE_ROW) {
        fprintf(stderr, "唯一性检查执行失败\n");
        goto rollback;
    }

    if (sqlite3_column_int(stmt, 0) > 0) {
        fprintf(stderr, "错误: 新值 '%s' 已存在\n", new_value);
        goto rollback;
    }
    sqlite3_finalize(stmt);
    stmt = NULL;

    // ------------------- 执行更新操作 -------------------
    sql = sqlite3_mprintf("UPDATE %w SET FILENAME=? WHERE FILENAME=?;", table_name);
    rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
    sqlite3_free(sql);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "更新预处理失败: %s\n", sqlite3_errmsg(db));
        goto rollback;
    }

    sqlite3_bind_text(stmt, 1, new_value, -1, SQLITE_STATIC);
    sqlite3_bind_text(stmt, 2, old_value, -1, SQLITE_STATIC);
    
    if (sqlite3_step(stmt) != SQLITE_DONE) {
        fprintf(stderr, "更新执行失败: %s\n", sqlite3_errmsg(db));
        goto rollback;
    }

    // 验证实际更新行数
    if (sqlite3_changes(db) == 0) {
        fprintf(stderr, "错误: 旧值 '%s' 不存在\n", old_value);
        goto rollback;
    }

    // 提交事务
    if (sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL) != SQLITE_OK) {
        fprintf(stderr, "提交失败: %s\n", sqlite3_errmsg(db));
        goto rollback;
    }

    ret = 1; // 成功标志
    printf("[%s] %s → %s\n", table_name, old_value, new_value);

rollback:
    if (!ret) sqlite3_exec(db, "ROLLBACK;", NULL, NULL, NULL);
cleanup:
    if (stmt) sqlite3_finalize(stmt);
    sqlite3_close(db);
    return ret;
}

// 示例用法
int main() {
    // 将 test.db 数据库 files 表中 "file3.jpg" 改为 "video.mp4"
    int success = update_data_item("test.db", "files", "video.mp4", "会议室1上午关键记录.mp4");
    printf("操作结果: %s\n", success ? "成功" : "失败");
    return 0;
}

7:查找数据

cpp 复制代码
//查表
#include <stdio.h>
#include <stdlib.h>
#include <sqlite3.h>
//SQL语句用法
//使用查表操作主要是sqlite3_exec()的回调函数
typedef int (*sqlite3_callback)(
    void*,    /* Data provided in the 4th argument of sqlite3_exec() */
    int,      /* The number of columns in row */
    char**,   /* An array of strings representing fields in the row */
    char**    /* An array of strings representing column names */
    );
// 第一个参数:即第四个参数传入的数据
// 第二个参数:行中的列数
// 第三个参数:表示行中字段的字符串数组,即各行中的数据
// 第四个参数:表示列名的字符串数组,创建链表时设置的
// 执行流程:查表,是否还有符合条件数据。有,执行sqlite3_callback()函数;没有,退出
// 回调函数
int callback(void *data, int argc, char **argv, char **azColName)
{
    int i;
    //fprintf(stderr, "%s ", (const char*)data);
    for(i=0; i<argc; i++){
       printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
    }
    printf("\n");
    return 0;
}
int main(int argc,char* argv[])
{
    sqlite3 *db;
    char *mang = 0;
    int rc;
    char *err_msg = 0;
    const char* data = "Table";
    //1:连接数据库
    rc = sqlite3_open("./test.db",&db);//打开当前目录下的数据库
    if(rc)
    {
        //非0表示打开失败
        fprintf(stderr,"Can't open database: %s\n",sqlite3_errmsg(db));
    }else
    {
        //打开成功
        fprintf(stderr,"Opened database successfully\n");
    }
    // 创建表查询表的SQL语句
    const char *sql = 
        "SELECT * FROM files";

    //执行SQL命令创建表
    rc = sqlite3_exec(db,sql,callback,(void *)data,&err_msg);
    if( rc != SQLITE_OK ){
        fprintf(stderr, "SQL error: %s\n", err_msg);
        sqlite3_free(err_msg);
    }else{
        fprintf(stdout, "Operation done successfully\n");
    }

    sqlite3_close(db);//关闭数据库
    return 0;
}
//占位符用法
int main() {
    sqlite3 *db;
    sqlite3_stmt *stmt = NULL;
    char *err_msg = NULL;
    int rc;

    // 打开数据库
    rc = sqlite3_open("test.db", &db);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "无法打开数据库: %s\n", sqlite3_errmsg(db));
        return 1;
    }

    // 准备查询语句(示例:查询所有数据)
    const char *sql = "SELECT FILENAME, DATE, SIZE FROM files;";
    rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
    if (rc != SQLITE_OK) {
        fprintf(stderr, "预处理失败: %s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        return 1;
    }

    // 遍历结果集
    printf("文件列表:\n");
    printf("----------------------------------\n");
    while (sqlite3_step(stmt) == SQLITE_ROW) {
        // 提取各列数据(列索引从 0 开始)
        const char *filename = sqlite3_column_text(stmt, 0);  // 第0列:FILENAME
        const char *date = sqlite3_column_text(stmt, 1);      // 第1列:DATE
        int size = sqlite3_column_int(stmt, 2);               // 第2列:SIZE

        printf("文件名: %-12s  日期: %-10s  大小: %d字节\n", filename, date, size);
    }
    printf("----------------------------------\n");

    // 检查是否因错误退出循环
    if (sqlite3_errcode(db) != SQLITE_DONE) {
        fprintf(stderr, "查询未完整执行: %s\n", sqlite3_errmsg(db));
    }

    // 释放资源
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    return 0;
}

对于数据库的使用我觉得其核心功能是对数据的处理也就是经典四字真言"增删改查";当掌握其中的使用方法后就基本会使用这个数据库的方法了。

相关推荐
爱编程的小新☆2 分钟前
【MySQL】初识数据库
数据库·mysql
LVerrrr29 分钟前
Missashe考研日记-day24
学习·考研
veminhe34 分钟前
MySQL性能调优(三):MySQL中的系统库(简介、performance_schema)
数据库·mysql
执笔论英雄2 小时前
【DeepSeek 学习推理】Llumnix: Dynamic Scheduling for Large Language Model Serving
人工智能·学习·语言模型
降世神童2 小时前
【KWDB创作者计划】_针对KWDB时序数据库(多副本集群环境)进行压力测试
数据库·压力测试·时序数据库
0509152 小时前
测试基础笔记第九天
数据库·笔记·oracle
二年级程序员2 小时前
多表查询之嵌套查询
数据库·sql·mysql
techdashen2 小时前
性能比拼: Redis vs Dragonfly
数据库·redis·缓存
虾球xz2 小时前
游戏引擎学习第236天:GPU 概念概述
c++·学习·游戏引擎
胡斌附体2 小时前
mysql增加字段并添加索引怎样写语句合适
数据库·sql·mysql