Ios sqlite3\u准备\u v2/sqlite3\u执行
关于sqlite3的几个问题: 1.何时需要使用第一种方法,何时需要使用第二种方法?他们之间有什么不同Ios sqlite3\u准备\u v2/sqlite3\u执行,ios,objective-c,sqlite,Ios,Objective C,Sqlite,关于sqlite3的几个问题: 1.何时需要使用第一种方法,何时需要使用第二种方法?他们之间有什么不同 sqlite3_prepare_v2(_contactDB, sql_stmt_getIdRecepteur, -1, &sqlStatement, NULL); 及 2.何时最适合使用“sqlite3\U exec”而不是“sqlite3\U prepare\U v2” 3.当需要使用第一个、第二个或第三个时: while(sqlite3_step(sqlStatement) ==
sqlite3_prepare_v2(_contactDB, sql_stmt_getIdRecepteur, -1, &sqlStatement, NULL);
及
2.何时最适合使用“sqlite3\U exec”而不是“sqlite3\U prepare\U v2”
3.当需要使用第一个、第二个或第三个时:
while(sqlite3_step(sqlStatement) == SQLITE_ROW){}
if(sqlite3_step(sqlStatement) == SQLITE_ROW){}
if(sqlite3_step(sqlStatement) == SQLITE_DONE){}
提前感谢您回答问题1,在大多数情况下,您需要验证结果是否等于SQLITE_OK,以确保您的命令成功运行。(SQLITE_OKisinttype**)。因此,优选第二种 对于问题2,函数sqlite3_exec用于运行任何不返回数据的命令,包括更新、插入和删除。从数据库中检索数据几乎不需要更多的工作。函数sqlite3\u prepare\u v2可用于选择(在
SQL
中)。通常,createtable通常使用第一个表
对于问题3,中的表示循环,而中的表示条件。通常,如果从db中检索数据,则需要一个循环来遍历*返回数组**。例如,如果向db插入数据,可以使用SQLITE_DONE检查您的操作
顺便说一句,在大多数情况下,IOS中首选核心数据
if
语句。如果失败,则调用sqlite3\u errmsg()
来检索错误的C字符串描述sqlite3\u prepare\u v2
(而不是sqlite3\u exec
):
- 一个是返回数据,因此将调用
,然后调用一个或多个函数,对每行数据重复该过程;或sqlite3\u步骤
- 一种是使用将值绑定到SQL中的
占位符?
sqlite3\u exec
;(b)SQL不返回任何数据。sqlite3_exec更简单,但只应在这些特定情况下使用
请注意:关于?
占位符的这一点非常重要:应避免手动构建SQL语句(例如,使用stringWithFormat
或Swift字符串插值),尤其是在插入的值包括最终用户输入的情况下。例如,如果使用使用用户输入创建的INSERT
、UPDATE
、或DELETE
语句调用sqlite3\u exec
(例如,将用户提供的某个值插入数据库),则可能会发现未转义的引号和转义符号所产生的问题,其中一个还面临SQL注入攻击
例如,如果由于用户输入而提供了commentString
,这将是不可取的:
NSString *sql = [NSString stringWithFormat:@"INSERT INTO COMMENTS (COMMENT) VALUES ('%@')", commentString];
if (sqlite3_exec(database, [sql UTF8String], NULL, NULL, NULL) != SQLITE_OK) {
NSLog(@"Insert failure: %s", sqlite3_errmsg(database));
}
相反,你应该:
const char *sql = "INSERT INTO COMMENTS (COMMENT) VALUES (?)";
if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL) != SQLITE_OK) {
NSLog(@"Prepare failure: %s", sqlite3_errmsg(database));
return;
}
if (sqlite3_bind_text(statement, 1, [commentString UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK) {
NSLog(@"Bind 1 failure: %s", sqlite3_errmsg(database));
sqlite3_finalize(statement);
return;
}
if (sqlite3_step(statement) != SQLITE_DONE) {
NSLog(@"Step failure: %s", sqlite3_errmsg(database));
}
sqlite3_finalize(statement);
注意,如果此正确的实现感觉工作量太大,则可以使用,这将简化为:
if (![db executeUpdate:@"INSERT INTO COMMENTS (COMMENT) VALUES (?)", commentString]) {
NSLog(@"Insert failure: %@", [db lastErrorMessage]);
}
这提供了sqlite3\u prepare\u v2
方法的严格性,但提供了sqlite3\u exec
接口的简单性while(sqlite3_step(sqlStatement) == SQLITE_ROW) { ... }
或者,更好的做法是,如果您想进行正确的错误处理,您可以:
int rc;
while ((rc = sqlite3_step(sqlStatement)) == SQLITE_ROW) {
// process row here
}
if (rc != SQLITE_DONE) {
NSLog(@"Step failure: %s", sqlite3_errmsg(database));
}
检索单行数据时,可能会:
if (sqlite3_step(sqlStatement) != SQLITE_ROW) {
NSLog(@"Step failure: %s", sqlite3_errmsg(database));
}
if (sqlite3_step(sqlStatement) != SQLITE_DONE) {
NSLog(@"Step failure: %s", sqlite3_errmsg(database));
}
执行不会返回任何数据的SQL时,可能会:
if (sqlite3_step(sqlStatement) != SQLITE_ROW) {
NSLog(@"Step failure: %s", sqlite3_errmsg(database));
}
if (sqlite3_step(sqlStatement) != SQLITE_DONE) {
NSLog(@"Step failure: %s", sqlite3_errmsg(database));
}
当使用SQLite C接口时,您可以看到需要做一些工作才能正确地完成它。在这个名为的接口周围有一个很薄的Objective-C包装器,它不仅简化了与SQLite数据库的交互,而且更加健壮。我刚刚找到的对#2的最新答案是:使用
sqlite3_exec
(或者在循环中使用sqlite3_prepare_v2
)当sql\u stmt\u getIdRecepteur
实际包含多个sql语句时。从:
这些例程只编译zSql中的第一条语句,因此*pzTail左指未编译的语句
sqlite3\u exec
包括一个内部循环,该循环多次调用sqlite3\u prepare\u v2
,直到编译整个输入字符串。如果您不使用sqlite3\u exec
,并且在一个字符串中有多个SQL语句,那么您需要检查pzTail
从sqlite3\u prepare\u v2
返回的值,谢谢您的回答。当然,这应该在文档中!谢谢,顺便说一句,这里有一个小问题,虽然它没有详细说明什么时候方便函数,sqlite3\u exec
,是合适的,什么时候不合适。他们让你来推断。但它确实讨论了基本界面。很高兴知道。非常感谢在后台线程中运行所有这些时,我应该使用SQLITE\u TRANSIENT
吗@罗伯/任何人。我在谷歌搜索时发现了。@LalKrishna-是的,我们应该使用SQLITE\u TRANSIENT
。我已经相应地更新了这个。仅供参考,它与背景或前景无关:问题在于您是否希望SQLite使用复制语义。十有八九,您确实希望使用SQLITE\u TRANSIENT
。正如文档中所说,“SQLITE_TRANSIENT值意味着内容在不久的将来可能会发生变化,SQLITE应该在返回之前制作自己的内容私有副本。”