数据库存储接口
This commit is contained in:
parent
22fd8927c3
commit
f726d015ae
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
Loading…
Reference in New Issue