c++ - sqlite3 事务和 exec 调用

标签 c++ database sqlite

我有一整套数据要插入到表格中。我试图让它插入/更新所有内容或回滚。我打算在事务中执行此操作,但我不确定 sql_exec() 命令是否执行相同的操作。

我的目标是遍历列表。 根据主键从每次迭代中选择。

If result was found:
  append update to string;
else
  append insert to string;

然后在遍历循环之后,我会得到一个巨大的字符串并说:

sql_exec(字符串); sql_close(db);

我应该这样做吗?我打算在循环的每次迭代中都这样做,但我不认为如果出现错误就进行全局回滚。

最佳答案

不,您不应该将所有内容附加到一个巨大的字符串中。如果这样做,您将需要分配一大堆内存,并且很难为每个单独的语句创建良好的错误消息,因为整个字符串只会出现一个错误。当 SQLite 必须再次将其解析回其单独的语句时,为什么要花费所有这些努力来构建一个大字符串?

相反,正如@Chad 建议的那样,您应该只在 BEGIN 语句上使用 sqlite3_exec(),这将开始一个事务。然后 sqlite3_exec() 依次执行每个语句,最后 sqlite3_exec() COMMITROLLBACK 取决于一切如何去。 BEGIN 语句将启动一个事务,之后执行的所有语句都将在该事务内,因此一起提交或回滚。这就是 ACID 中的“A”代表;原子性,因为事务中的所有语句都将被提交或回滚,就好像它们是单个原子操作一样。

此外,如果某些数据在每个语句中变化,例如从文件中读取,您可能不应该使用 sqlite3_exec()。如果你这样做,一个错误很容易给你留下一个SQL injection。漏洞。例如,如果您通过附加字符串构造查询,并且要插入像 char *str = "it's a string" 这样的字符串,如果您没有正确引用它,您的语句可能会出现像 INSERT INTO table VALUES ('it's a string');,这将是一个错误。或者,如果有人恶意将数据写入此文件,那么他们可能会导致您执行他们想要的任何 SQL 语句(imagine 如果字符串是 "'); DROP TABLE my_important_table; --") .您可能认为没有恶意的人会提供输入,但如果有人将混淆 SQL 解析器的字符放入字符串中,您仍然会遇到意外问题。

相反,您应该使用 sqlite3_prepare_v2()sqlite3_bind_...() (其中 ... 是类型,如 intdoubletext)。为此,您可以使用 char *query = "INSERT INTO table VALUES (?)" 之类的语句,将 ? 替换为您想要参数的位置开始,使用 sqlite3_prepare_v2(db, query, -1, &stmt, NULL) 准备它,使用 sqlite3_bind_text(stmt, 1, str, -1, SQLITE_STATIC) 绑定(bind)参数>,然后执行带有sqlite3_step(stmt)的语句.如果该语句返回任何数据,您将得到 SQLITE_ROW,并且可以使用各种 sqlite3_columne_...() 访问数据职能。请务必仔细阅读文档;我给出的一些示例参数可能需要根据您的使用方式进行更改。

是的,这比调用 sqlite3_exec() 要麻烦一些,但是如果您的查询有任何从外部源(文件、用户输入)加载的数据,这是唯一的方法正确地做。 sqlite3_exec() 如果查询的整个文本都包含在您的源代码中,例如 BEGINCOMMITROLLBACK 语句,或没有来自程序外部的任何部分的预写查询,如果有任何意外字符串可能进入的机会,您只需要准备/绑定(bind)。

最后,您不需要查询数据库中是否已经存在某些内容,然后再插入或更新它。您可以执行 INSERT OR REPLACE 查询,这将插入一条记录,或者用匹配的主键替换一条记录,这相当于选择然后执行 INSERTUPDATE,但更快更简单。查看INSERT"on conflict"文档以获取更多详细信息。

关于c++ - sqlite3 事务和 exec 调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13278679/

相关文章:

c++ - OpenGL 单个 VBO 与多个 VBO

mysql - 无法连接到 mysql 数据库 [strato]

android - 在另一个 Activity 中访问在一个 Activity 中创建的数据库

java - 如何安装更大的 sqlite 数据库,作为安装其他应用程序的奖励?

python - 从 sqlite3 远程数据库读取

c++ - 编译器优化如何影响代码逻辑?

C# 与 Mono 还是 C++? (运行Ubuntu)

c++ - 在编译时复制 C/C++ 函数

ruby-on-rails - 如何在不首先删除数据库的情况下将带有 Rails 的数据库迁移到第一个修订版?

php - 平面文件数据库