当前位置: 首页 > news >正文

高效SQLite操作:基于C++模板元编程的自动化封装

在传统的SQLite操作中,开发者常常面临以下几个痛点:

  1. 手动编写CREATE TABLE语句:不仅繁琐,还容易因类型映射错误导致问题;
  2. 手动绑定参数:容易出现类型不匹配或参数索引错误;
  3. 频繁单条插入性能低下:大量磁盘I/O严重影响效率;
  4. 资源管理复杂:数据库连接、事务等需手动管理,容易发生资源泄露。

为解决上述问题,我提供了一种自动化方法,能够自动生成表创建语句、插入语句,实现类型映射与缓存管理。尽管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++应用场景。

http://www.dtcms.com/a/461556.html

相关文章:

  • uniApp App内嵌H5打开内部链接,返回手势(左滑右滑页面)会直接关闭H5项目
  • 文字排版网站网站建设的宣传词
  • K8s学习笔记(十七) pod优雅终止流程
  • Redis-基础介绍
  • Redis常用数据库及单线程模式
  • Subword-Based Tokenization策略之BPE与BBPE
  • 网站关键词用热门的还是冷门青岛天河小学网站建设
  • 个人域名备案 网站名称一元购网站建设流程图
  • 企业级灰度发布架构:基于Nginx的精细化流量治理与平滑演进实践
  • 【滑动窗口专题】第一讲:长度最小的子数组
  • 软考-系统架构设计师 基于架构的软件开发方法详细讲解
  • 电子电气架构 --- 操作系统的基本概念
  • 苏州做网站公司电话wordpress资源分享网
  • 手机能建设网站企业的做网站
  • Unity笔记(十一)——换装、Spine骨骼动画、3D动画相关
  • 面向汽车网络安全的轻量级加密技术
  • 《投资-114》价值投资者的认知升级与交易规则重构 - 从大规模分工的角度看,如何理解“做正确的事”,即满足下游正确的需求
  • 添加一路AXI总线对DDR进行读写时,XDMA测试不通过
  • 基于python的机器学习(十)—— 评估算法(三)
  • 男女做那个的的视频网站检察院门户网站建设成效
  • Oracle的SID是什么
  • Oracle大会临近,23ai 本地版会发布吗?
  • 【Python刷力扣hot100】11. Container With Most Water
  • 通信建设网站做网站主页上主要放哪些内容
  • 《常用 IDL(接口定义语言)详解与对比》
  • 做二手房产网站多少钱河南建设工程信息网站
  • K230基础-获取触摸坐标
  • Linux应用--网络编程
  • 鸟哥的Linux私房菜 第三部分: 学习shell与shell script
  • 鸿蒙中 UDP 数据包发不出去?一文教你从权限到代码彻底排查!