高效SQLite操作:基于C++模板元编程的自动化封装
在传统的SQLite操作中,开发者常常面临以下几个痛点:
- 手动编写CREATE TABLE语句:不仅繁琐,还容易因类型映射错误导致问题;
- 手动绑定参数:容易出现类型不匹配或参数索引错误;
- 频繁单条插入性能低下:大量磁盘I/O严重影响效率;
- 资源管理复杂:数据库连接、事务等需手动管理,容易发生资源泄露。
为解决上述问题,我提供了一种自动化方法,能够自动生成表创建语句、插入语句,实现类型映射与缓存管理。尽管Python代码生成或C++模板元编程均可实现该功能,本文选择基于C++模板元编程与变长参数机制,以兼顾性能与使用便捷性。
类型映射
通过模板将c++类型转换成SQLite类型。
template<typename T>
struct SQLiteType {static const char *value;
};template<> const char *SQLiteType<int64_t>::value = "INTEGER";
template<> const char *SQLiteType<int32_t>::value = "INTEGER";
template<> const char *SQLiteType<int8_t>::value = "INTEGER";
template<> const char *SQLiteType<float>::value = "REAL";
template<> const char *SQLiteType<double>::value = "REAL";
template<> const char *SQLiteType<const char *>::value = "TEXT";
template<> const char *SQLiteType<std::string>::value = "TEXT";
template<> const char *SQLiteType<bool>::value = "INTEGER";
生成表创建和数据插入语句
利用变长参数模板递归生成SQL语句,避免手动编写。
template<typename Last>static void generate_sql_var_type(std::ostringstream& oss, const std::pair<const char *, Last>& field) {oss << field.first << " " << SQLiteType<Last>::value << " NOT NULL";}template<typename T, typename... Args>static void generate_sql_var_type(std::ostringstream& oss,const std::pair<const char *, T>& first,const std::pair<const char *, Args>& ... rest) {oss << first.first << " " << SQLiteType<T>::value << " NOT NULL";if (sizeof...(rest) > 0) {oss << ", ";generate_sql_var_type(oss, rest...); // 递归处理剩余参数}}std::string generate_init_table_statement(const std::ostringstream& var_type_statement) {return "create table if not exists " + table_name + " (" + var_type_statement.str() + ");";}
用同样的方法生成数据插入语句。
template<typename Last>static void generate_sql_insert(std::ostringstream& oss_var, std::ostringstream& oss_val,const std::pair<const char *, Last>& field) {oss_var << field.first;oss_val << "?";}template<typename T, typename... Args>static void generate_sql_insert(std::ostringstream& oss_var,std::ostringstream& oss_val,const std::pair<const char *, T>& first,const std::pair<const char *, Args>& ... rest) {oss_var << first.first;oss_val << "?";if (sizeof...(rest) > 0) {oss_var << ", ";oss_val << ", ";generate_sql_insert(oss_var, oss_val, rest...); // 递归处理剩余参数}}std::string generate_insert_table_statement(const std::ostringstream& var, const std::ostringstream& val) {return "insert into " + table_name + " (" + var.str() + ") values (" + val.str() + ");";}
缓存
使用std::vector和std::tuple作为数据缓存,并在达到指定条数时自动触发批量写入。
std::vector<std::tuple<First, Rest...>> caches{};
绑定参数时展开tuple,实现自动参数绑定。
template<int Index = 0, typename... Ts>void bind_values_impl(SQLite::Statement& query, const std::tuple<Ts...>& t) {if constexpr (Index < sizeof...(Ts)) {query.bind(Index + 1, std::get<Index>(t));bind_values_impl<Index + 1>(query, t);}}
完整实现
#ifndef SQLITE_WRITER_HPP
#define SQLITE_WRITER_HPP#include <iostream>
#include <string>
#include <utility>
#include <sstream>
#include <vector>
#include <tuple>
#include "SQLiteCpp/SQLiteCpp.h"#define SQLITE_WRITER_SUCCESS 0
#define SQLITE_WRITER_NOT_INIT (-1)
#define SQLITE_WRITER_NOT_ENABLE (-2)
#define SQLITE_WRITER_CACHE_NOT_ENOUGH (-3)// 类型映射:C++ 类型 → SQLite 类型
template<typename T>
struct SQLiteType {static const char *value;
};template<> const char *SQLiteType<int64_t>::value = "INTEGER";
template<> const char *SQLiteType<int32_t>::value = "INTEGER";
template<> const char *SQLiteType<int8_t>::value = "INTEGER";
template<> const char *SQLiteType<float>::value = "REAL";
template<> const char *SQLiteType<double>::value = "REAL";
template<> const char *SQLiteType<const char *>::value = "TEXT";
template<> const char *SQLiteType<std::string>::value = "TEXT";
template<> const char *SQLiteType<bool>::value = "INTEGER";template<typename First, typename... Rest>
class SqliteWriter {
public:SqliteWriter() = delete;explicit SqliteWriter(const bool enable,const std::string& db_path,const std::string& table_name,const uint32_t cache_count,const std::pair<const char *, First>& first_field,const std::pair<const char *, Rest>& ... rest_field) :enable(enable), db_path(db_path), table_name(table_name), cache_count(cache_count) {std::ostringstream oss0{};generate_sql_var_type(oss0, first_field, rest_field...);init_table_statement = generate_init_table_statement(oss0);std::ostringstream oss1{};std::ostringstream oss2{};generate_sql_insert(oss1, oss2, first_field, rest_field...);insert_table_statement = generate_insert_table_statement(oss1, oss2);}~SqliteWriter() {if (enable) {write_immediately();}}int32_t init() {if (!enable) {return SQLITE_WRITER_NOT_ENABLE;}db = std::make_unique<SQLite::Database>(db_path, SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE);db->exec("PRAGMA journal_mode = WAL");db->exec("PRAGMA synchronous = OFF");db->exec(init_table_statement);caches.reserve(cache_count);return SQLITE_WRITER_SUCCESS;}template<typename... Values>int32_t write_cache(const Values& ... values) {if (!enable) {return SQLITE_WRITER_NOT_ENABLE;}caches.emplace_back(values...);if (caches.size() < cache_count) {return SQLITE_WRITER_CACHE_NOT_ENOUGH;}return write_immediately();;}template<typename... Values>int32_t write_cache(Values&& ... values) {if (!enable) {return SQLITE_WRITER_NOT_ENABLE;}caches.emplace_back(std::forward<Values>(values)...);if (caches.size() < cache_count) {return SQLITE_WRITER_CACHE_NOT_ENOUGH;}return write_immediately();}const std::string& get_init_table_statement() {return init_table_statement;}const std::string& get_insert_table_statement() {return insert_table_statement;}protected:template<typename Last>static void generate_sql_var_type(std::ostringstream& oss, const std::pair<const char *, Last>& field) {oss << field.first << " " << SQLiteType<Last>::value << " NOT NULL";}template<typename T, typename... Args>static void generate_sql_var_type(std::ostringstream& oss,const std::pair<const char *, T>& first,const std::pair<const char *, Args>& ... rest) {oss << first.first << " " << SQLiteType<T>::value << " NOT NULL";if (sizeof...(rest) > 0) {oss << ", ";generate_sql_var_type(oss, rest...); // 递归处理剩余参数}}template<typename Last>static void generate_sql_insert(std::ostringstream& oss_var, std::ostringstream& oss_val,const std::pair<const char *, Last>& field) {oss_var << field.first;oss_val << "?";}template<typename T, typename... Args>static void generate_sql_insert(std::ostringstream& oss_var,std::ostringstream& oss_val,const std::pair<const char *, T>& first,const std::pair<const char *, Args>& ... rest) {oss_var << first.first;oss_val << "?";if (sizeof...(rest) > 0) {oss_var << ", ";oss_val << ", ";generate_sql_insert(oss_var, oss_val, rest...); // 递归处理剩余参数}}std::string generate_init_table_statement(const std::ostringstream& var_type_statement) {return "create table if not exists " + table_name + " (" + var_type_statement.str() + ");";}std::string generate_insert_table_statement(const std::ostringstream& var, const std::ostringstream& val) {return "insert into " + table_name + " (" + var.str() + ") values (" + val.str() + ");";}int32_t write_immediately() {if (db == nullptr) {return SQLITE_WRITER_NOT_INIT;}SQLite::Transaction transaction(*db);SQLite::Statement query(*db, insert_table_statement);for (const auto& cache: caches) {query.reset();bind_values(query, cache);query.exec();}transaction.commit();caches.clear();return SQLITE_WRITER_SUCCESS;}void bind_values(SQLite::Statement& query, const std::tuple<First, Rest...>& values) {bind_values_impl(query, values);}template<int Index = 0, typename... Ts>void bind_values_impl(SQLite::Statement& query, const std::tuple<Ts...>& t) {if constexpr (Index < sizeof...(Ts)) {query.bind(Index + 1, std::get<Index>(t));bind_values_impl<Index + 1>(query, t);}}protected:std::vector<std::tuple<First, Rest...>> caches{};std::unique_ptr<SQLite::Database> db{nullptr};bool enable{true};std::string db_path{};std::string table_name{};uint32_t cache_count{};std::string init_table_statement{};std::string insert_table_statement{};
};#endif //SQLITE_WRITER_HPP
总结
该封装库极大简化了SQLite操作流程,提升了开发效率与代码可靠性,同时保持了C++应用的性能优势。适用于需要高效、可靠数据库操作的各种C++应用场景。