C语言与sqlite3入门
c语言与sqlite3入门
- 1 sqlite3数据类型
- 2 sqlite3指令
- 3 sqlite3的sql语法
- 3.1 创建表create
- 3.2 删除表drop
- 3.3 插入数据insert into
- 3.4 查询select from
- 3.5 where子句
- 3.6 修改数据update
- 3.7 删除数据delete
- 3.8 排序Order By
- 3.9 分组GROUP BY
- 3.10 约束
- 4 c语言执行sqlite3
- 4.1 下载c源码
- 4.2 cmake编译运行
- 5 创建或打开数据库
- 6 sqlite3_exec
- 7 sqlite3_prepare
- 7.1 sqlite3_prepare_v2
- 7.2 sqlite3_bind
- 7.3 sqlite3_step
- 7.4 sqlite3_column
- 7.5 sqlite3_reset
- 8 读写blob型数据
- 参考
1 sqlite3数据类型
- NULL 空
- INTEGER 整形
- REAL 浮点
- TEXT 文本
- BLOB binary large object二进制对象,一般存图像,声音,自定义结构体
2 sqlite3指令
sqlite3 test.db # 打开数据库, 没有就创建.databases #查看所有的数据库位置。

3 sqlite3的sql语法
3.1 创建表create
CREATE TABLE COMPANY(ID INT PRIMARY KEY NOT NULL,NAME TEXT NOT NULL,AGE INT NOT NULL,ADDRESS CHAR(50),SALARY REAL
);
3.2 删除表drop
DROP TABLE COMPANY;
3.3 插入数据insert into
INSERT INTO COMPANY VALUES (7, 'James', 24, 'Houston', 10000.00 );
或者
INSERT INTO COMPANY(id, name, age, address, salary) VALUES (7, 'James', 24, 'Houston', 10000.00 );
用第二种更严谨一些
假如没有设置值,为NULL或者0
INSERT INTO COMPANY(ID, name, age) VALUES (8, '张三', 11);
3.4 查询select from
SELECT ID, NAME, SALARY FROM COMPANY ;
3.5 where子句
select * from与where name like 'a%'都是会查询所有表的内容,一般禁用。
逻辑与或子句
SELECT * FROM COMPANY WHERE AGE >= 25 OR SALARY >= 65000
不为空
查询age不为空的记录
SELECT * FROM COMPANY WHERE AGE IS NOT NULL
模糊查询
所有名字以ki开头的
SELECT * FROM COMPANY WHERE NAME LIKE 'Ki%';
in
年龄为25或27的记录
SELECT * FROM COMPANY WHERE AGE IN ( 25, 27 );
年龄不为25且不为27
SELECT * FROM COMPANY WHERE AGE NOT IN ( 25, 27 );
子查询
年龄大于所有65000薪水以上员工年龄的记录
SELECT * FROM COMPANY WHERE AGE > (SELECT AGE FROM COMPANY WHERE SALARY > 65000);
3.6 修改数据update
UPDATE COMPANY SET ADDRESS = 'Texas' WHERE ID = 6;
3.7 删除数据delete
DELETE FROM COMPANY WHERE ID = 7;
3.8 排序Order By
其实默认就是升序,ASC是升序,DESC就是降序。
SELECTselect_list
FROMtable
ORDER BYcolumn_1 ASC,column_2 DESC;
3.9 分组GROUP BY
比如可以按照年龄来分组,看看不同年龄的平均薪资。
SELECT AGE, avg(SALARY) from COMPANY GROUP BY AGE;

3.10 约束
CREATE TABLE COMPANY(ID INT PRIMARY KEY NOT NULL,NAME TEXT NOT NULL UNIQUE,AGE INT NOT NULL CHECK(AGE > 0),ADDRESS CHAR(50),SALARY REAL DEFAULT 50000.00
);
主键约束:PRIMARY KEY,ID作为主键,不能有重复值,一般也不能为NULL。
NOT NULL: 不为空,该列不能有NULL
CEHCK 添加修改记录时,需要符合check条件。
DEFAULT 设置默认值。
4 c语言执行sqlite3
4.1 下载c源码
打开 c源码sqlite3下载页面 下载其中的source code源码,下第一个就好。

放入项目的sqlite文件夹中,除开我已经创建的两个数据库,项目结果应该长这样。

随便写一个c,获取sqlite3版本
#include <stdio.h>
#include "sqlite3.h"
int main(void)
{printf("%s\n", sqlite3_libversion());return 0;
}
4.2 cmake编译运行
在CMakeLists.txt中写
cmake_minimum_required (VERSION 3.5)project(test)
add_definitions("-Wall -g")include_directories (sqlite)add_executable(${PROJECT_NAME} ${PROJECT_SOURCE_DIR}/test.c ${PROJECT_SOURCE_DIR}/sqlite/sqlite3.c)
target_link_libraries (${PROJECT_NAME} pthread dl)add_executable(sqliteShell ${PROJECT_SOURCE_DIR}/sqlite/shell.c ${PROJECT_SOURCE_DIR}/sqlite/sqlite3.c)
target_link_libraries (sqliteShell pthread dl)
写好后cd打开build文件夹执行cmake和makefile
cmake .. & make
# 再执行test
./test

假如没有修改文件结构(增删文件/修改文件位置),只是修改了文件内容。
再次编译代码不需要再次运行cmake了,运行make即可
make
./test
5 创建或打开数据库
sqlite3_open函数,打开数据库,没有就创建一个。
第一个参数就是数据库位置,相对位置是相对于程序执行时的位置,不是c文件所在位置
第二个是双指针的通道
sqlite3 *db = NULL;
int rc = sqlite3_open("../test.db", &db);
关闭
sqlite3_close(db);
如下方就可以创建一个表,并且插入一些值来使用
#include <stdio.h>
#include "sqlite3.h"
int main(void)
{sqlite3 *db = NULL;char *err_msg = NULL;int rc = sqlite3_open("../test.db", &db);if(rc != SQLITE_OK){fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));sqlite3_close(db);return 1;}const char *sql = "DROP TABLE IF EXISTS Cars;" "CREATE TABLE Cars(Id INT, Name TEXT, Price INT);" "INSERT INTO Cars VALUES(1, 'Audi', 52642);" "INSERT INTO Cars VALUES(2, 'Mercedes', 57127);" "INSERT INTO Cars VALUES(3, 'Skoda', 9000);" "INSERT INTO Cars VALUES(4, 'Volvo', 29000);" "INSERT INTO Cars VALUES(5, 'Bentley', 350000);" "INSERT INTO Cars VALUES(6, 'Citroen', 21000);" "INSERT INTO Cars VALUES(7, 'Hummer', 41400);" "INSERT INTO Cars VALUES(8, 'Volkswagen', 21600);";rc = sqlite3_exec(db, sql, NULL, NULL, &err_msg);if(rc != SQLITE_OK){fprintf(stderr, "SQL error: %s\n", err_msg);sqlite3_free(err_msg);sqlite3_close(db);return 1;}sqlite3_close(db);return 0;}
6 sqlite3_exec
sqlite3_exec是执行sql语句的函数,算是最重要的函数。
sqlite3*, //数据库
const char* sql,//sql语句
*callback, //回调
void* data, //回调的参数
char **errmsq //错误信息
const char * = "SELECT * FROM car";
char* dataName = "test";
char *err_msg = NULL;
int rc = sqlite3_exec(db, sql, callback, dataName, &err_msg);int callback(void* para, int columnCount, char** columnValue, char** columnName){}
callback在每查询到一行数据的时候就调用一次,所以每次得到的是一行数据。
其中callback只能自己传一个参数,但是自身有4个参数。
- para 传来的参数
- columnCount 列数
- columnValue 一维的字符串数组,保存的是每一列数据。
- columnName 一维字符串数组,列名。
比如下方获取所有的test.db中的数据,打印出来。
#include <stdio.h>
#include "sqlite3.h"int callback(void *, int, char **, char **);int main(void)
{sqlite3 *db = NULL;char *err_msg = NULL;int rc = sqlite3_open("../test.db", &db);if (rc != SQLITE_OK) {fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));sqlite3_close(db);return 1;}const char *sql = "SELECT * FROM Cars";char* dataName = "test";rc = sqlite3_exec(db, sql, callback, dataName, &err_msg);if (rc != SQLITE_OK ) {fprintf(stderr, "Failed to select data\n");fprintf(stderr, "SQL error: %s\n", err_msg);sqlite3_free(err_msg);sqlite3_close(db);return 1;}sqlite3_close(db);return 0;
}int callback(void* para, int columenCount, char** columnValue, char** columnName)
{for (int i = 0; i < columenCount; ++i){printf("%s = %s\n", columnName[i], (columnValue[i] ? columnValue[i] : "NULL"));}printf("\n");return 0;
}
7 sqlite3_prepare
exec使用起来简单,它在执行的过程中,有一个编译再执行的过程。
假如有多个insert语句,exec需要每inset一次都需要编译一次,效率低。
对于结构相同的语句,我们是否可以先编译,于是有了一个prepare,先编译,再插入变量执行。
最开始有一个控制变量sqlite3_stmt的句柄,其中stmt的全称应该是statement。
sqlite3_stmt *pstmt;
7.1 sqlite3_prepare_v2
先需要准备一个模板
int sqlite3_prepare_v2(sqlite3 *db, /* 数据库通道 */const char *zSql, /* sql语句 */int nByte, /* sql语句长度,一般填入-1自动计算 */sqlite3_stmt **ppStmt, /* 准备语句的控制权柄 */const char **pzTail /* sql语句超出了nByte后存放位置,一般把nByte设置足够大,这个设置为NULL即可 */
);
下面是一个模板的代码,将插入语句设置为模板,其中需要插入的内容用?代替
sqlite3_stmt *pStmt = NULL;
char *pzTail = NULL;
const char *sql = "INSERT INTO person(name, age, sex) VALUES(?,?,?);";
rc = sqlite3_prepare_v2(pdb, sql, strlen(sql), &pStmt, pzTail);
用prepare语句后可以先编译。
7.2 sqlite3_bind
这个函数就是设置插入值。
有三个函数,用于插入不同类型值。
int sqlite3_bind_int(sqlite3_stmt*, int, int);
int sqlite3_bind_doubule(sqlite3_stmt*, int, double);
int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int, void(*)(void*));
int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int, void(*)(void*))
- 句柄handle
- 需要赋值的是sql语句中的第几个参数,从1开始。
- 插入值,text和blob是指针。
- 插入值长度(strlen/sizeof)。
- 绑定blob类型的析构函数,一般可以设置为NULL
那么现在我们需要插入值来形成一个sql语句就可以这么写
const char * name = "iceylia";
age = 100;
sex = "未知";
sqlite3_bind_text(pstmt, 1, name, strlen(name), NULL);
sqlite3_bind_int(pstmt, 2, age);
sqlite3_bind_text(pstmt, 3, sex, strlen(sex), NULL);
7.3 sqlite3_step
插入值后执行sql语句,用sqlite3_step
rc = sqlite3_step(pstmt);
返回值有两个需要注意的返回值
- SQLITE_DONE: 表示执行完毕
- SQLITE_ROW: 当使用select语句时,会得到多个数据,每次只能读取一行的值,
比如获取表中所有参数,需要多次使用sqlite3_step获取列。
const char *sql = "SELECT * FROM Cars;";
const char *pzTail;
rc = sqlite3_prepare_v2(db, sql, -1, &pStmt, &pzTail);
while(sqlite3_step(pStmt)==SQLITE_ROW){printf("id = %d\n", sqlite3_column_int(pStmt, 0));
}

7.4 sqlite3_column
上面的示例代码中使用了sqlite3_column,这是获取查询到的数据的函数
同样有三个,第二个参数是列号,从0开始。
int sqlite3_column_int(sqlite3_stmt*, int iCol);
double sqlite3_column_double(sqlite3_stmt*, int iCol);
const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
7.5 sqlite3_reset
将bind绑定的值全部取消清楚,方便重新绑定
int sqlite3_reset(sqlite3_stmt *pStmt);
这么做的目的就是在比如插入多个数据,绑定了一个人的数据,然后需要绑定第二个的时候需要清空statement。
8 读写blob型数据
读入
建表时定义一个blob,插入时用statement插入
const char *newSql = "INSERT INTO Images(Data) VALUES(?)";
rc = sqlite3_prepare_v2(db, newSql, -1, &pStmt, NULL);
sqlite3_bind_blob(pStmt, 1, &data, sizeof(data), NULL);
读取,也用statement读取,用column读取。
myData *pData = (myData*)sqlite3_column_blob(pStmt, 0);

下面是一个完整的读取写入代码。
#include <stdio.h>
#include "sqlite3.h"
#include <string.h>typedef struct
{int value1;double value2;
} myData;int main(void)
{sqlite3 *db = NULL;char *err_msg = NULL;int rc = sqlite3_open("../test.db", &db);if (rc != SQLITE_OK){fprintf(stderr, "Cannot open database: %s\n",sqlite3_errmsg(db));sqlite3_close(db);return 1;}const char *sql = "DROP TABLE IF EXISTS Images;""CREATE TABLE Images(Id INTEGER PRIMARY KEY, Data BLOB);";rc = sqlite3_exec(db, sql, NULL, NULL, &err_msg);if (rc != SQLITE_OK){fprintf(stderr, "Failed to select data\n");fprintf(stderr, "SQL error: %s", err_msg);sqlite3_free(err_msg);sqlite3_close(db);return 1;}sqlite3_stmt *pStmt = NULL;const char *newSql = "INSERT INTO Images(Data) VALUES(?)";rc = sqlite3_prepare_v2(db, newSql, -1, &pStmt, NULL);myData data = {100, 0.156};sqlite3_bind_blob(pStmt, 1, &data, sizeof(data), SQLITE_STATIC);rc = sqlite3_step(pStmt);if (rc != SQLITE_DONE){printf("execution failed: %s", sqlite3_errmsg(db));}sqlite3_finalize(pStmt);char *sql2 = "SELECT Data FROM Images WHERE Id = 1";pStmt = NULL;rc = sqlite3_prepare_v2(db, sql2, -1, &pStmt, NULL);if (rc != SQLITE_OK ) {fprintf(stderr, "Failed to prepare statement\n");fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));sqlite3_close(db);return 1;} rc = sqlite3_step(pStmt);int bytes = 0;if (rc == SQLITE_ROW){bytes = sqlite3_column_bytes(pStmt, 0);}myData *pData = (myData*)sqlite3_column_blob(pStmt, 0);printf("bytes: %d, %d, %lf\n", bytes, pData->value1, pData->value2);rc = sqlite3_finalize(pStmt); sqlite3_close(db);return 0;
}
参考
C语言操作SQLite3简明教程
深入理解SQLite3之sqlite3_exec及回调函数
玩转SQLite-11:C语言高效API之sqlite3_prepare系列函数
相关文章:
C语言与sqlite3入门
c语言与sqlite3入门 1 sqlite3数据类型2 sqlite3指令3 sqlite3的sql语法3.1 创建表create3.2 删除表drop3.3 插入数据insert into3.4 查询select from3.5 where子句3.6 修改数据update3.7 删除数据delete3.8 排序Order By3.9 分组GROUP BY3.10 约束 4 c语言执行sqlite34.1 下载…...
Rancher(v2.6.3)——安装Rancher
[详细安装说明请查看Rancher安装说明文档]:https://gitee.com/WilliamWangmy/snail-knowledge/blob/master/Rancher/Rancher%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3.md#1%E5%AE%89%E8%A3%85rancher Rancher部署Mysql(单机版):http…...
Aapche Nutch建立自己的搜索引擎
sudo apt install default-jdk‘ java -version openjdk version "11.0.22" 2024-01-16 vi .bashrc export JAVA_HOME/usr/lib/jvm/java-11-openjdk-amd64 爬梯子下载源代码 Apache Nutch™ – Downloads mkdir -p urls cd urls touch seed.txt 里面放入我的网站…...
阅读笔记(ICIP2023)Rectangular-Output Image Stitching
“矩形输出”图像拼接 Zhou, H., Zhu, Y., Lv, X., Liu, Q., & Zhang, S. (2023, October). Rectangular-Output Image Stitching. In 2023 IEEE International Conference on Image Processing (ICIP) (pp. 2800-2804). IEEE. 0. 摘要 图像拼接的目的是将两幅视场重叠的…...
就业班 第二阶段 2401--3.26 day6 Shell初识 连接vscode
远程连接vs_code可能出现的问题 C:\Users\41703\.ssh 验证远程主机的身份,如果连不上vscode,可以尝试删除这里面的公钥代码。 重新安装那个扩展,排除扩展本身的问题 谁连过我,并操作了什么 curl https://gitea.beyourself.org.c…...
碳课堂|什么是碳资产?企业如何进行碳资产管理?
碳资产是绿色资产的重要类别,在全球气候变化日益严峻的背景下备受关注。在“双碳”目标下,碳资产管理是企业层面实现碳减排目标和低碳转型的关键。 一、什么是碳资产? 碳资产是以碳减排为基础的资产,是企业为了积极应对气候变化&…...
如何使用 ChatGPT 进行编码和编程
文章目录 一、初学者1.1 生成代码片段1.2 解释功能 二、自信的初学者2.1 修复错误2.2 完成部分代码 三、中级水平3.1 研究库3.2 改进旧代码 四、进阶水平4.1 比较示例代码4.2 编程语言之间的翻译 五、专业人士5.1 模拟 Linux 终端 总结 大多数程序员都知道,ChatGPT …...
学习java第二十四天
spring框架中有哪些不同类型的事件 Spring 提供了以下5种标准的事件: 上下文更新事件(ContextRefreshedEvent):在调用 ConfigurableApplicationContext 接口中的refresh方法时被触发。 上下文开始事件(ContextStart…...
中小型集群部署,Docker Swarm(集群)使用及部署应用介绍
1、Docker Swarm简介 说到集群,第一个想到的就是k8s,但docker官方也提供了集群和编排解决方案,它允许你将多个 Docker 主机连接在一起,形成一个“群集”(Swarm),并可以在这个 Swarm 上运行和管…...
gateway做负载均衡
在Spring Cloud中,Gateway可以通过配置文件来实现负载均衡。以下是一个简单的配置示例,它演示了如何将请求代理到名为service-instance的服务的两个不同实例。 spring:cloud:gateway:routes:- id: service-instance-routeuri: lb://service-instancepre…...
pytorch中的torch.hub.load()
pytorch提供了torch.hub.load()函数加载模型,该方法可以从网上直接下载模型或是从本地加载模型。官方文档 torch.hub.load(repo_or_dir, model, *args, sourcegithub, trust_repoNone, force_reloadFalse, verboseTrue, skip_validationFalse, **kwargs)参数说明&a…...
R语言学习——Rstudio软件
R语言免费但有点难上手,是数据挖掘的入门级别语言,拥有顶级的可视化功能。 优点: 1统计分析(可以实现各种分析方法)和计算(有很多函数) 2强大的绘图功能 3扩展包多,适合领域多 …...
触发器的工艺结构原理及选型参数总结
🏡《总目录》 目录 1,概述2,工作原理3,结构特点4,工艺流程4.1,掩膜制作4.2,晶片生长4.3,晶片切割4.4,晶片清洗4.5,掩膜光刻4.6,金属沉积5,选型参数5.1,触发类型5.2,触发频率...
Hana数据库 No columns were bound prior to calling SQLFetch or SQLFetchScroll
在php调用hana数据库的一个sql时报错了,查表结构的sql: select * from sys.table_columns where table_name VBAP SQLSTATE[SL009]: <<Unknown error>>: 0 [unixODBC][Driver Manager]No columns were bound prior to calling SQLFetch …...
DevOps是什么
DevOps 是一种将软件开发 (Dev) 和 IT运维 (Ops) 结合起来的实践、文化和哲学,旨在缩短系统开发生命周期,提供高质量的软件持续交付。它涉及多个关键实践和工具,其核心目的是加强开发和运维团队之间的协作和通信。以下是构成DevOps的一些重要…...
windows下的vscode + opencv4.8.0(C++) 配置
1.添加环境变量 D:\mingw64\bin 2.安装vscode 3.下载opencv 4.8.0 4.程序引用第三方库(opencv为例) 打开CMakeLists.txt,引入头文件,使用include_directories 加入头文件所在目录。静态链接库link_directories # 头文件 include_directories(D:/ope…...
微信小程序之多视频暂停播放,超出可视区域停止播放视频在自定义组件中实现案例
项目页面存在多个视频时,只播放视频可见范围内单个视频播放的解决方案 QQ录屏20240326175303 在自定义组件中无onPageScroll(e)监听页面滚动的函数所以在自定义组件中用<scroll-view>标签包裹所有组件(以下为WXML页面源码) <scroll…...
Java 加载外部 Jar 中的类并通过反射调用类中的方法
目录 问题 类加载器 获取外部 jar 包中的类以及方法 调用外部 jar 包中的方法 问题 工作中遇到一个需求,客户端将第三方的 jar 包上传到服务器中,系统需要解析出上传的 jar 中所有类以及类下的方法(方法名,方法输入参数类型&…...
Arduino+ESP8266+华为云物联网平台实现智能开关
前言 最近在做一个物联网项目,涉及到智能开关的开发。目前已经实现简单的TCP通信远程控制,但是考虑到后期的设备管理以及设备通信所需要的技术和服务器的维护成本,我决定将设备接入云平台。本文将详细阐述如何利用华为云的物联网平台&#x…...
使用 python 拆分 excel 文件
文章目录 1、安装虚拟环境(在特定文件夹内)2、脚本 split.sh3、运行脚本(在特定文件夹内)4、结果 1、安装虚拟环境(在特定文件夹内) brew install python3 xcode-select --install python3 -m venv my_pan…...
[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...
微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
Python 包管理器 uv 介绍
Python 包管理器 uv 全面介绍 uv 是由 Astral(热门工具 Ruff 的开发者)推出的下一代高性能 Python 包管理器和构建工具,用 Rust 编写。它旨在解决传统工具(如 pip、virtualenv、pip-tools)的性能瓶颈,同时…...
解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist
现象: android studio报错: [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决: 不要动CMakeLists.…...
企业大模型服务合规指南:深度解析备案与登记制度
伴随AI技术的爆炸式发展,尤其是大模型(LLM)在各行各业的深度应用和整合,企业利用AI技术提升效率、创新服务的步伐不断加快。无论是像DeepSeek这样的前沿技术提供者,还是积极拥抱AI转型的传统企业,在面向公众…...
多元隐函数 偏导公式
我们来推导隐函数 z z ( x , y ) z z(x, y) zz(x,y) 的偏导公式,给定一个隐函数关系: F ( x , y , z ( x , y ) ) 0 F(x, y, z(x, y)) 0 F(x,y,z(x,y))0 🧠 目标: 求 ∂ z ∂ x \frac{\partial z}{\partial x} ∂x∂z、 …...
【iOS】 Block再学习
iOS Block再学习 文章目录 iOS Block再学习前言Block的三种类型__ NSGlobalBlock____ NSMallocBlock____ NSStackBlock__小结 Block底层分析Block的结构捕获自由变量捕获全局(静态)变量捕获静态变量__block修饰符forwarding指针 Block的copy时机block作为函数返回值将block赋给…...
电脑桌面太单调,用Python写一个桌面小宠物应用。
下面是一个使用Python创建的简单桌面小宠物应用。这个小宠物会在桌面上游荡,可以响应鼠标点击,并且有简单的动画效果。 import tkinter as tk import random import time from PIL import Image, ImageTk import os import sysclass DesktopPet:def __i…...
从零手写Java版本的LSM Tree (一):LSM Tree 概述
🔥 推荐一个高质量的Java LSM Tree开源项目! https://github.com/brianxiadong/java-lsm-tree java-lsm-tree 是一个从零实现的Log-Structured Merge Tree,专为高并发写入场景设计。 核心亮点: ⚡ 极致性能:写入速度超…...
虚幻基础:角色旋转
能帮到你的话,就给个赞吧 😘 文章目录 移动组件使用控制器所需旋转:组件 使用 控制器旋转将旋转朝向运动:组件 使用 移动方向旋转 控制器旋转和移动旋转 缺点移动旋转:必须移动才能旋转,不移动不旋转控制器…...
