gpt4 book ai didi

c++ - 组织 sqlite3 C/C++ 准备语句(避免全局代码困惑)

转载 作者:太空狗 更新时间:2023-10-29 21:46:00 26 4
gpt4 key购买 nike

我正在编写一个应用程序,它需要使用准备好的语句来获得性能优势,但我想知道当您的应用程序包含数十个(如果不是数百个)准备好的语句时,您如何管理它而不让它变得一团糟全局代码?您是否只需要在与使用它们的地方完全不同的地方准备构造函数/函数中的所有语句?

使用 sqlite_exec 很好,因为查询就在您实际使用它的地方,但是对于准备好的语句,我最终将它们放在完全不同的代码区域,它模糊/混淆了哪些变量需要绑定(bind)实际使用它们的函数。

具体来说,现在我只有一个具有私有(private)变量的数据库单例,

sqlite3_stmt *insertPacketCount;
sqlite3_stmt *insertPortContacted;
sqlite3_stmt *insertPacketSize;
sqlite3_stmt *computePacketSizeVariance;
...

构造函数对 sqlite3_prepare_v2 进行了数十次调用,

// Set up all our prepared queries
res = sqlite3_prepare_v2(db,
"INSERT OR IGNORE INTO packet_counts VALUES(?1, ?2, ?3, 1);",
-1, &insertPacketCount, NULL);
expectReturnValueAndFail(SQLITE_OK);
...

以及在其他地方使用它们的实际功能,

void Database::IncrementPacketCount(std::string ip, std::string interface, std::string type, uint64_t increment)
{
int res;

res = sqlite3_bind_text(incrementPacketCount, 1, ip.c_str(), -1, SQLITE_STATIC);
expectReturnValue(SQLITE_OK);
res = sqlite3_bind_text(incrementPacketCount, 2, interface.c_str(), -1, SQLITE_STATIC);
expectReturnValue(SQLITE_OK);
res = sqlite3_bind_text(incrementPacketCount, 3, type.c_str(), -1, SQLITE_STATIC);
expectReturnValue(SQLITE_OK);
res = sqlite3_bind_int(incrementPacketCount, 4, increment);
expectReturnValue(SQLITE_OK);

res = sqlite3_step(incrementPacketCount);
expectReturnValue(SQLITE_DONE);
res = sqlite3_reset(incrementPacketCount);
expectReturnValue(SQLITE_OK);
}

在使用准备好的查询的函数内部,我一直不得不乏味地回到准备语句来弄清楚绑定(bind)索引是什么。

抱歉,如果这含糊不清,但是否有任何库或方法可以在不牺牲任何性能/安全性的情况下组织此类事情(比如仅附加字符串和调用 sqlite_exec)?

最佳答案

您不应将查询字符串从查询执行中移开。如果您编写一个仅在第一次需要时准备语句的辅助函数,您还可以避免在开始时准备所有语句:

void Database::PrepareStatementIfNeeded(sqlite3_stmt **stmt,
const std::string& sql)
{
if (*stmt == NULL) {
res = sqlite3_prepare_v2(db, sql.c_str(), -1, stmt, NULL);
...
}
}

(但你还是要确保全部敲定。)

此外,如果您给参数名称而不是数字,您可以使用 sqlite3_bind_parameter_index获取正确的索引:

void BindParam(sqlite3_stmt *stmt,
const char *name,
const std::string& value) // overload for other types
{
int index = sqlite3_bind_parameter_index(stmt, name);
if (index == 0)
error...;
int res = sqlite3_bind_text(stmt, index, value.c_str(), -1, SQLITE_TRANSIENT);
...
}

void Database::IncrementPacketCount(...)
{
PrepareStatementIfNeeded(&incrementPacketCount,
"INSERT OR IGNORE INTO packet_counts"
" VALUES(:ip, :intf, :type, 1)");
BindParameter(incrementPacketCount, "ip", ip);
BindParameter(incrementPacketCount, "intf", interface);
BindParameter(incrementPacketCount, "type", type);
...
}

(那些 sqlite3_step/sqlite3_reset 调用看起来好像你在重复它们无数次;也为它们创建一个辅助函数。)

关于c++ - 组织 sqlite3 C/C++ 准备语句(避免全局代码困惑),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16180195/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com