简体   繁体   English

sqlite iPhone读取数据的最佳实践

[英]sqlite iphone best practice for reading data

I'm trying to make an app, that reads from an SQLite3 database. 我正在尝试制作一个从SQLite3数据库读取的应用程序。 I plan to pre-load data during development, so the app does not need to modify anything in the database, only read from it, make queries, etc. 我计划在开发过程中预加载数据,因此该应用程序无需修改数据库中的任何内容,只需从数据库中读取内容,进行查询等即可。

What is the best practice for solely reading data? 仅读取数据的最佳实践是什么? Should I open the database, read the data, and close it, with each query? 我应该在每次查询时打开数据库,读取数据并关闭数据吗? The app will be making many small queries and a few large ones. 该应用程序将进行许多小查询和一些大查询。 Is it better to have the database open for the duration of the app, or open/close it with each fetch? 在应用程序运行期间打开数据库还是在每次获取时打开/关闭数据库,这样更好吗?

Reading: 读:

1. For queries, it's important to re-use compiled statements. 1.对于查询,重用已编译的语句很重要。
2. Make sure you use parameters so you can re-use those compiled queries 2.确保使用参数,以便可以重新使用那些已编译的查询

When you call sqlite3_prepare_v2, it compiles the statement and gives you a reference to the statement back. 当您调用sqlite3_prepare_v2时,它将编译该语句并为您提供对该语句的引用。 Find a way to save that off and re-use it. 找到一种方法可以节省下来并重新使用它。 See the code below for *statement. 请参阅下面的代码以查看* statement。 You pass &statement into prepare. 您通过&statement进行准备。

Also, note the use of ? 另外,请注意使用? for parameters. 用于参数。 If you're going to re-use the statement, it's important to call sqlite3_reset() againt the statement, rebind the inputs from the program (parameters) and execute it again. 如果要重用该语句,请再次调用sqlite3_reset()语句,重新绑定程序(参数)的输入并再次执行,这一点很重要。

sqlite3_stmt    *statement;
NSString *querySQL = @"update contacts set name=?,address=?,phone=? where id=?";
NSLog(@"query: %@", querySQL);
const char *query_stmt = [querySQL UTF8String];

// preparing a query compiles the query so it can be re-used.
// find a way to save off the *statement so you can re-use it.
sqlite3_prepare_v2(_contactDb, query_stmt, -1, &statement, NULL);  

// use sqlite3_bind_xxx functions to bind in order values to the params   
sqlite3_bind_text(statement, 1, [[contact name] UTF8String], -1, SQLITE_STATIC);
sqlite3_bind_text(statement, 2, [[contact address] UTF8String], -1, SQLITE_STATIC);
sqlite3_bind_text(statement, 3, [[contact phone] UTF8String], -1, SQLITE_STATIC);
sqlite3_bind_int64(statement, 4, [[contact id] longLongValue]);

Always check the return codes! 务必检查返回码! and log or handle the errors. 并记录或处理错误。

    rc = sqlite3_step(stmt);
    switch (rc)
    {
        case SQLITE_ROW:
            // ...
            break;

        case SQLITE_OK:
        case SQLITE_DONE:
            break;

        default:
            // ....
            }

            return NO;
    }

if you get an error, log or get the eror message to provide more info: 如果出现错误,请登录或获取错误消息以提供更多信息:

- (NSString*)errorMessage
{
    return [NSString stringWithCString:sqlite3_errmsg(_sqlite3) encoding:NSUTF8StringEncoding];    
}

As per you question you want to read data from database. 按照您的疑问,您想从数据库中读取数据。 So following are the answer of you questions. 因此,以下是您的问题的答案。

  1. No need to open db each time when you fire the query. 触发查询时,无需每次都打开db。 Just one it one time. 一次只一次。 It is better if you create singleton class and open db in it for first time when it initiate. 最好创建单例类并在启动时第一次在其中打开db。
  2. Use following code method which will work for all select queries which has conditional select, group by etc. 使用以下代码方法将对具有条件选择,分组依据等的所有选择查询起作用。
  3. I) it takes Output/result column names as input array ii ) TableName iii) Where condition iv)OrderBy clause v)group By clause I)将输出/结果列名称作为输入数组ii)TableName iii)条件iv)OrderBy子句v)group By子句

- (NSMutableArray *)runSelecteQueryForColumns: (NSArray *)p_columns ontableName: (NSString *)p_tableName withWhereClause: (NSString *)p_whereClause withOrderByClause: (NSString *)p_orederByCalause withGroupByClause: (NSString *)p_groupByClause
{


    NSMutableArray *l_resultArray = [[NSMutableArray alloc] init];

    if(!self.m_database)
    {
        if(![self openDatabase])
        {
            sqlite3_close(self.m_database);
            //NSLog(@"error in select : DB creating : %@",p_whereClause);
            return nil;

        }
    }

    NSMutableString *l_simpleQuery =[[NSMutableString alloc] initWithString:@"Select"] ;

    if(p_columns)
    {

        for(int l_row = 0 ; l_row < [p_columns count] ; l_row++)
        {
            if(l_row != [p_columns count]-1)
            {
                [l_simpleQuery appendString:[NSString stringWithFormat:@" %@,", [p_columns objectAtIndex:l_row]]];
            }
            else
            {
                [l_simpleQuery appendString:[NSString stringWithFormat:@" %@", [p_columns objectAtIndex:l_row]]];
            }
        }
    }
    else
    {
        [l_simpleQuery appendString:@" *"];
    }

    [l_simpleQuery appendString:[NSString stringWithFormat:@" From %@",p_tableName]];

    if(p_whereClause)
    {
        [l_simpleQuery appendString:[NSString stringWithFormat:@" %@",p_whereClause]];
    }
    if(p_groupByCaluase)
    {
        [l_simpleQuery appendString:[NSString stringWithFormat:@" %@",p_groupByCaluase]];
    }

    if(p_orederByCalause)
    {
        [l_simpleQuery appendString:[NSString stringWithFormat:@" %@",p_orederByCalause]];
    }


    //NSLog(@"Select Query: - %@",l_simpleQuery);

    const char *l_query_stmt = [l_simpleQuery UTF8String];

    sqlite3_stmt *l_statement = nil;

    int i = sqlite3_prepare_v2(self.m_database,
                               l_query_stmt, -1, &l_statement, NULL);

    if (i == SQLITE_OK)
    {

        while(sqlite3_step(l_statement) == SQLITE_ROW)
        {

            [l_resultArray addObject:[self createDictionary:l_statement]];

        }

        sqlite3_finalize(l_statement);


    }
    else
    {
        sqlite3_finalize(l_statement);
        //sqlite3_close(l_database);
        DDLogError(@"%@ - error in SQL :%@",THIS_FILE,l_simpleQuery);
        return nil;
    }
    //NSLog(@"RESULT %@",l_resultArray);
    return l_resultArray;

}

Use sqlite_open_v2 with the SQLITE_OPEN_READONLY flag. sqlite_open_v2SQLITE_OPEN_READONLY标志一起使用。 For example, I use the following method to open a database for reading only. 例如,我使用以下方法打开一个数据库以供只读。

  // Open for reading only.
- (int) openDatabaseAtPath:(NSString *) path
{
    if (database != nil)
    {
        sqlite3_close(self.database);
        [self setDatabase:nil];
    }

    int errorCode = SQLITE_OK;
    errorCode = sqlite3_open_v2([path UTF8String],
                                 &database,
                                 SQLITE_OPEN_READONLY,
                                 NULL);

    return errorCode;
}

除非将数据库复制到Documents目录,否则将通过资源目录使用DB,并且该目录是只读的。

When you open the database using sqlite_open_v2 and the SQLITE_OPEN_READONLY flag, SQLite opens the file itself in read-only mode, so even if your application, due to a bug, corrupts memory belonging to SQLite, the database will stay untouched. 当您使用sqlite_open_v2SQLITE_OPEN_READONLY标志打开数据库时,SQLite会以只读模式打开文件本身,因此,即使您的应用程序由于错误而损坏了属于SQLite的内存,数据库也将保持不变。

With this in mind, I'd keep the database open until the application quits. 考虑到这一点,我将保持数据库打开状态直到应用程序退出。 (You may wish to close it if you receive a low-memory notification and reopen it on demand, but opening and closing it for every query would be wasteful.) (如果收到内存不足的通知,请关闭它,然后按需重新打开它,但是为每个查询打开和关闭它都是浪费时间。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM