Fal*_*per 3 c++ database sqlite
我有一整套要插入表格的数据.我试图让它插入/更新一切或回滚.我打算在一个事务中执行它,但我不确定sql_exec()命令是否做了同样的事情.
我的目标是遍历列表.根据主键从每次迭代中选择.
If result was found:
append update to string;
else
append insert to string;
Run Code Online (Sandbox Code Playgroud)
然后在遍历循环之后,我会有一个巨大的字符串并说:
sql_exec(字符串); SQL_CLOSE(分贝);
那是我应该怎么做的?我将在循环的每次迭代中执行此操作,但如果出现错误,我不认为全局回滚.
不,你不应该将所有东西都附加到一个巨大的字符串中.如果这样做,您将需要分配一大堆内存,并且为每个单独的语句创建良好的错误消息将更加困难,因为您只会为整个字符串收到一个错误.为什么要花费所有的努力,在SQLite只需要再次将其解析为单独的语句时构造一个大字符串?
相反,正如@Chad建议的那样,你应该只使用sqlite3_exec()一个BEGIN会开始交易的语句.然后sqlite3_exec()依次说出每个陈述,最后sqlite3_exec()是一个COMMIT或ROLLBACK取决于一切如何.该BEGIN语句将启动一个事务,之后执行的所有语句都将在该事务中,并因此一起提交或回滚.这就是ACID中的"A" 代表的意思; Atomic,因为事务中的所有语句都将被提交或回滚,就像它们是单个原子操作一样.
此外,sqlite3_exec()如果某些数据在每个语句中有所不同,例如从文件中读取,则可能不应该使用.如果你这样做,错误很容易让你注意到SQL注入错误.例如,如果您通过附加字符串来构造查询,并且您有char *str = "it's a string"要插入的字符串,如果您没有正确引用它,那么您的语句可能会出现INSERT INTO table VALUES ('it's a string');,这将是一个错误.或者,如果恶意某人可以将数据写入此文件,那么他们可能会导致您执行他们想要的任何SQL语句(想象一下如果该字符串是"'); 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(),但如果您的查询有从外部源(文件,用户输入)加载的任何数据,这是正确执行此操作的唯一方法.sqlite3_exec()如果查询的整个文本包含在您的源代码中,例如BEGIN和/ COMMIT或ROLLBACK语句,或预编写的查询没有来自您的程序之外的任何部分,则可以调用,如果有任何机会,您只需要准备/绑定意外的字符串可以进入.
最后,您不需要查询数据库中是否存在某些内容,然后插入或更新它.您可以执行INSERT OR REPLACE查询,该查询将插入记录,或者使用匹配的主键替换一个记录,这相当于选择然后执行INSERT或UPDATE更快,更简单.有关更多详细信息,请参阅INSERT和"on conflict"文档.