数据库存储接口

This commit is contained in:
GuanYuankai 2025-10-17 10:01:15 +08:00
parent 22fd8927c3
commit f726d015ae
2 changed files with 197 additions and 0 deletions

View File

@ -0,0 +1,151 @@
#include "data_storage.h"
#include <iostream>
#include <memory>
#include <mutex>
#include <chrono>
// 使用 Pimpl Idiom 来隐藏 SQLite 细节
// struct DataStorage::SQLiteDB {
// sqlite3* db_handle = nullptr;
// // 用于自动执行 finalize 的语句句柄
// std::unique_ptr<sqlite3_stmt, decltype(&sqlite3_finalize)> stmt_guard{nullptr, sqlite3_finalize};
// };
// 获取单例实例
DataStorage& DataStorage::getInstance() {
static DataStorage instance;
return instance;
}
DataStorage::~DataStorage() {
if (db_ && db_->db_handle) {
sqlite3_close(db_->db_handle);
std::cout << "Database connection closed." << std::endl;
}
}
bool DataStorage::initialize(const std::string& db_path) {
std::lock_guard<std::mutex> lock(mutex_);
if (db_ && db_->db_handle) {
return true; // 已经初始化过
}
db_ = std::make_unique<SQLiteDB>();
int rc = sqlite3_open(db_path.c_str(), &db_->db_handle);
if (rc != SQLITE_OK) {
std::cerr << "Cannot open database: " << sqlite3_errmsg(db_->db_handle) << std::endl;
return false;
}
// 创建表
if (!createTables()) {
sqlite3_close(db_->db_handle);
db_->db_handle = nullptr;
return false;
}
std::cout << "Database initialized successfully at: " << db_path << std::endl;
return true;
}
bool DataStorage::createTables() {
const char* create_raw_table_sql =
"CREATE TABLE IF NOT EXISTS raw_data ("
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
"device_id TEXT NOT NULL, "
"received_at_ms INTEGER NOT NULL, "
"raw_data BLOB NOT NULL, "
"protocol_type TEXT);";
const char* create_processed_table_sql =
"CREATE TABLE IF NOT EXISTS processed_data ("
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
"device_id TEXT NOT NULL, "
"timestamp_ms INTEGER NOT NULL, "
"data_json TEXT NOT NULL, "
"created_at_ms INTEGER DEFAULT (strftime('%s', 'now') * 1000));";
char* errMsg = nullptr;
int rc;
rc = sqlite3_exec(db_->db_handle, create_raw_table_sql, nullptr, nullptr, &errMsg);
if (rc != SQLITE_OK) {
std::cerr << "SQL error creating raw_data table: " << errMsg << std::endl;
sqlite3_free(errMsg);
return false;
}
rc = sqlite3_exec(db_->db_handle, create_processed_table_sql, nullptr, nullptr, &errMsg);
if (rc != SQLITE_OK) {
std::cerr << "SQL error creating processed_data table: " << errMsg << std::endl;
sqlite3_free(errMsg);
return false;
}
// 为 device_id 和 timestamp_ms 创建索引,加速查询
const char* create_processed_index_sql = "CREATE INDEX IF NOT EXISTS idx_device_timestamp ON processed_data(device_id, timestamp_ms);";
rc = sqlite3_exec(db_->db_handle, create_processed_index_sql, nullptr, nullptr, &errMsg);
if (rc != SQLITE_OK) {
std::cerr << "SQL error creating index: " << errMsg << std::endl;
sqlite3_free(errMsg);
return false; // 即使索引创建失败,表也成功创建了,可以酌情处理
}
return true;
}
bool DataStorage::storeRawData(const std::string& device_id, const std::string& raw_data, const std::string& protocol_type) {
std::lock_guard<std::mutex> lock(mutex_);
if (!db_ || !db_->db_handle) {
std::cerr << "Database not initialized." << std::endl;
return false;
}
const char* sql = "INSERT INTO raw_data (device_id, received_at_ms, raw_data, protocol_type) VALUES (?, ?, ?, ?);";
sqlite3_stmt* stmt;
int rc = sqlite3_prepare_v2(db_->db_handle, sql, -1, &stmt, nullptr);
if (rc != SQLITE_OK) {
std::cerr << "Failed to prepare statement for raw_data: " << sqlite3_errmsg(db_->db_handle) << std::endl;
return false;
}
// **重要**:这里的 stmt_guard 也需要修正
// 你之前的代码里是 std::unique_ptr<void, ...>,这也是错误的
// 应该是 sqlite3_stmt*
std::unique_ptr<sqlite3_stmt, decltype(&sqlite3_finalize)> stmt_guard(stmt, sqlite3_finalize);
sqlite3_bind_text(stmt, 1, device_id.c_str(), -1, SQLITE_STATIC);
sqlite3_bind_int64(stmt, 2, std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count());
sqlite3_bind_blob(stmt, 3, raw_data.c_str(), raw_data.size(), SQLITE_STATIC);
sqlite3_bind_text(stmt, 4, protocol_type.c_str(), -1, SQLITE_STATIC);
rc = sqlite3_step(stmt);
if (rc != SQLITE_DONE) {
std::cerr << "Failed to execute statement for raw_data: " << sqlite3_errmsg(db_->db_handle) << std::endl;
return false;
}
return true;
}
bool DataStorage::storeProcessedData(const UnifiedData& data) {
std::lock_guard<std::mutex> lock(mutex_);
if (!db_ || !db_->db_handle) {
std::cerr << "Database not initialized." << std::endl;
return false;
}
const char* sql = "INSERT INTO processed_data (device_id, timestamp_ms, data_json) VALUES (?, ?, ?);";
sqlite3_stmt* stmt;
int rc = sqlite3_prepare_v2(db_->db_handle, sql, -1, &stmt, nullptr);
if (rc != SQLITE_OK) {
std::cerr << "Failed to prepare statement for processed_data: " << sqlite3_errmsg(db_->db_handle) << std::endl;
return false;
}
// **重要**:这里的 stmt_guard 也需要修正
std::unique_ptr<sqlite3_stmt, decltype(&sqlite3_finalize)> stmt_guard(stmt, sqlite3_finalize);
sqlite3_bind_text(stmt, 1, data.device_id.c_str(), -1, SQLITE_STATIC);
sqlite3_bind_int64(stmt, 2, data.timestamp_ms);
sqlite3_bind_text(stmt, 3, data.data_json.c_str(), -1, SQLITE_STATIC);
rc = sqlite3_step(stmt);
if (rc != SQLITE_DONE) {
std::cerr << "Failed to execute statement for processed_data: " << sqlite3_errmsg(db_->db_handle) << std::endl;
return false;
}
return true;
}

View File

@ -0,0 +1,46 @@
// /app/src/dataStorage/data_storage.h
#ifndef DATA_STORAGE_H
#define DATA_STORAGE_H
#include <string>
#include <memory>
#include <mutex>
#include <chrono>
#include <sqlite3.h> // SQLite 的头文件
// 包含 UnifiedData 的定义,并解决重定义问题
// 如果 unified_data.h 在 /app/src/protocol/ 目录下
#include "protocol/iprotocol_adapter.h"
// 如果 unified_data.h 在 /app/src/ 目录下
// #include "../unified_data.h"
class DataStorage {
public:
static DataStorage& getInstance();
DataStorage(const DataStorage&) = delete;
DataStorage& operator=(const DataStorage&) = delete;
bool initialize(const std::string& db_path);
bool storeRawData(const std::string& device_id, const std::string& raw_data, const std::string& protocol_type = "");
bool storeProcessedData(const UnifiedData& data);
private:
DataStorage() = default;
~DataStorage();
// SQLite 的实现细节,对外隐藏
struct SQLiteDB {
sqlite3* db_handle = nullptr;
// 正确的 unique_ptr 定义:管理 sqlite3_stmt*,删除器是 sqlite3_finalize
std::unique_ptr<sqlite3_stmt, decltype(&sqlite3_finalize)> stmt_guard{nullptr, sqlite3_finalize};
};
// 使用 Pimpl 指针
std::unique_ptr<SQLiteDB> db_;
std::mutex mutex_;
bool createTables();
};
#endif // DATA_STORAGE_H