当前位置:首页 > 数据库 > SQlite

c – sqlite3事务和exec调用

我有一整套要插入表格的数据.我试图让它插入/更新一切或回滚.我打算在一个事务中执行它,但我不确定sql_exec()命令是否做了同样的事情.

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

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

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

sql_exec(字符串);
SQL_CLOSE(分贝);

那是我应该怎么做的?我将在循环的每次迭代中执行此操作,但如果出现错误,我不认为全局回滚.

解决方法:

不,你不应该将所有东西都附加到一个巨大的字符串中.如果这样做,您将需要分配一大堆内存,并且为每个单独的语句创建良好的错误消息将更加困难,因为您只会为整个字符串收到一个错误.为什么要花费所有的努力,在SQLite只需要再次将其解析为单独的语句时构造一个大字符串?

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

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

相反,您应该使用sqlite3_prepare_v2()sqlite3_bind_...()(其中……是类型,如int或double或text).为了做到这一点,你使用像char * query =“INSERT INTO table VALUES(?)”这样的语句,你用它替换?对于您希望参数的位置,使用sqlite3_prepare_v2(db,query,-1,& stmt,NULL)进行准备,使用sqlite3_bind_text(stmt,1,str,-1,SQLITE_STATIC)绑定参数,然后执行语句使用sqlite3_step(stmt).如果语句返回任何数据,您将获得SQLITE_ROW,并可以使用各种sqlite3_columne_...()函数访问数据.务必仔细阅读文档;我给出的一些示例参数可能需要根据您使用它的方式进行更改.

是的,这比调用sqlite3_exec()更麻烦,??但如果您的查询有任何从外部源(文件,用户输入)加载的数据,这是正确执行此操作的唯一方法.如果查询的整个文本包含在源代码中,例如BEGIN和COMMIT或ROLLBACK语句,或预编写的查询没有来自程序外部的任何部分,则可以调用sqlite3_exec(),只需要准备/如果有意外的字符串可能进入,则绑定.

最后,您不需要查询数据库中是否存在某些内容,然后插入或更新它.您可以执行INSERT OR REPLACE查询,该查询将插入记录,或者使用匹配的主键替换一个记录,这相当于选择然后执行INSERT或UPDATE,但更快更简单.有关更多详细信息,请参阅INSERT“on conflict”文档.


【说明】本文章由站长整理发布,文章内容不代表本站观点,如文中有侵权行为,请与本站客服联系(QQ:254677821)!