综合实战项目:四大数据库系统实战
说实话,做了这么多年嵌入式开发,我最大的体会就是——没有哪个数据库能包打天下。你想想看,一个学生管理系统用SQLite就够了,但电商订单你敢用SQLite?分分钟崩给你看。
今天这个综合实战项目,我把四个最常用的数据库都拉出来遛遛。每个系统我都亲手写过,踩过的坑也不少。咱们一个一个来。
项目一:学生管理系统(SQLite)
SQLite这东西,说白了就是个文件数据库。我最早接触它是在一个手持设备项目上,当时觉得「就这?」后来才发现,轻量级场景下它真香。
学生管理系统的核心就三件事:增删改查。咱们用C语言调用SQLite的API,几行代码就能搞定。
#include <sqlite3.h>
sqlite3 *db;
char *err_msg = 0;
// 打开数据库(没有就自动创建)
sqlite3_open("student.db", &db);
// 建表
const char *sql =
"CREATE TABLE IF NOT EXISTS students("
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
"name TEXT NOT NULL,"
"age INTEGER,"
"score REAL);";
sqlite3_exec(db, sql, 0, 0, &err_msg);
// 插入数据
sql = "INSERT INTO students(name, age, score) VALUES('张三', 20, 88.5);";
sqlite3_exec(db, sql, 0, 0, &err_msg);
sqlite3_close(db);
个人经验:SQLite的并发写入是个坑。我曾经在一个多线程项目里同时写数据库,结果频繁报「database is locked」。后来加了个互斥锁才解决。记住:SQLite适合单线程或低并发场景。
项目二:电商订单系统(MySQL)
电商系统,那数据量可不是闹着玩的。MySQL配合C语言的MySQL Connector/C库,才能扛住高并发。
我记得有一次双十一,订单表瞬间涌入几十万条数据。如果不用连接池,光创建连接就能把服务器拖垮。
#include <mysql/mysql.h>
MYSQL *conn;
MYSQL_RES *res;
MYSQL_ROW row;
conn = mysql_init(NULL);
mysql_real_connect(conn, "localhost", "root", "password", "ecommerce", 0, NULL, 0);
// 创建订单表
mysql_query(conn,
"CREATE TABLE orders("
"order_id BIGINT PRIMARY KEY,"
"user_id INT,"
"amount DECIMAL(10,2),"
"status TINYINT,"
"create_time DATETIME"
") ENGINE=InnoDB;");
// 批量插入(用事务提高性能)
mysql_query(conn, "START TRANSACTION;");
for(int i = 0; i < 1000; i++) {
char sql[256];
sprintf(sql, "INSERT INTO orders VALUES(%ld, %d, %.2f, 1, NOW());",
order_id, user_id, amount);
mysql_query(conn, sql);
}
mysql_query(conn, "COMMIT;");
mysql_close(conn);
避坑指南:我曾经在MySQL中直接用单条INSERT插入上万条数据,结果花了十几秒。后来改成批量插入+事务,速度提升了上百倍。另外,记得给order_id加索引,不然查询慢到你怀疑人生。
项目三:实时排行榜(Redis)
Redis做排行榜,那简直是天生一对。它的有序集合(Sorted Set)就是为这个场景设计的。
我做过一个游戏排行榜,玩家分数实时更新。如果用MySQL,每次排序都要全表扫描,延迟高得离谱。换成Redis,毫秒级响应。
#include <hiredis/hiredis.h>
redisContext *c = redisConnect("127.0.0.1", 6379);
// 玩家得分更新
redisCommand(c, "ZADD leaderboard 1000 player_001");
redisCommand(c, "ZADD leaderboard 1500 player_002");
redisCommand(c, "ZADD leaderboard 800 player_003");
// 获取前十名
redisReply *reply = redisCommand(c, "ZREVRANGE leaderboard 0 9 WITHSCORES");
if(reply->type == REDIS_REPLY_ARRAY) {
for(int i = 0; i < reply->elements; i += 2) {
printf("玩家: %s, 分数: %s\n",
reply->element[i]->str,
reply->element[i+1]->str);
}
}
freeReplyObject(reply);
redisFree(c);
小技巧:Redis的数据结构要选对。排行榜用ZSET,缓存用STRING,消息队列用LIST。我见过有人用STRING存排行榜数据,每次更新都全量替换,那效率...嗯,你懂的。
项目四:日志分析系统(MongoDB)
MongoDB处理日志,优势在于它的文档模型。日志本身就是半结构化数据,用关系型数据库反而别扭。
我之前做一个运维平台,每天几百万条日志。用MongoDB的聚合管道,几秒钟就能统计出错误分布。
#include <mongoc/mongoc.h>
mongoc_client_t *client;
mongoc_collection_t *collection;
bson_t *doc;
client = mongoc_client_new("mongodb://localhost:27017");
collection = mongoc_client_get_collection(client, "logs", "system_logs");
// 插入日志
doc = BCON_NEW(
"timestamp", BCON_DATE_TIME(time(NULL)),
"level", BCON_UTF8("ERROR"),
"module", BCON_UTF8("auth"),
"message", BCON_UTF8("用户登录失败"),
"ip", BCON_UTF8("192.168.1.100")
);
mongoc_collection_insert_one(collection, doc, NULL, NULL, NULL);
bson_destroy(doc);
// 聚合查询:统计各模块错误数
bson_t *pipeline = BCON_NEW(
"pipeline", "[",
"{", "$match", "{", "level", BCON_UTF8("ERROR"), "}", "}",
"{", "$group", "{",
"_id", "$module",
"count", "{", "$sum", BCON_INT32(1), "}",
"}", "}",
"{", "$sort", "{", "count", BCON_INT32(-1), "}", "}",
"]"
);
mongoc_cursor_t *cursor = mongoc_collection_aggregate(
collection, MONGOC_QUERY_NONE, pipeline, NULL, NULL);
mongoc_cursor_destroy(cursor);
mongoc_collection_destroy(collection);
mongoc_client_destroy(client);
核心要点:MongoDB的索引设计很关键。日志查询通常按时间范围,所以给timestamp建索引是必须的。另外,日志数据量大,建议用分片集群,不然单机存不下。
四大数据库对比总结
| 数据库 | 适用场景 | 数据模型 | 并发能力 | 我的推荐 |
|---|---|---|---|---|
| SQLite | 嵌入式、单机、小数据量 | 关系型 | 低 | 学生管理、配置存储 |
| MySQL | Web应用、电商、高并发 | 关系型 | 高 | 订单系统、用户中心 |
| Redis | 缓存、排行榜、实时数据 | 键值对 | 极高 | 排行榜、会话管理 |
| MongoDB | 日志、物联网、大数据 | 文档型 | 高 | 日志分析、监控系统 |
这四个项目做完,基本上C语言操作主流数据库的套路你就都掌握了。说实话,数据库编程的核心就两点:连接管理和SQL(或命令)执行。剩下的就是针对不同数据库的特性做优化。
我建议你从SQLite开始练手,它最简单。然后挑战MySQL,感受一下高并发下的连接池设计。Redis和MongoDB可以并行学习,它们的数据模型和传统关系型完全不同,能打开你的思路。
最后说一句:数据库选型没有银弹。别听网上说「Redis快就全用Redis」,也别觉得「MongoDB时髦就抛弃MySQL」。合适的才是最好的。我见过太多项目因为选错数据库,后期重构成本高得吓人。