FMDB的简单应用(4篇)

来源:互联网 发布:家庭网络需要交换机吗 编辑:程序博客网 时间:2024/04/30 04:51

转截地址:http://blog.csdn.net/demon1900demon/article/details/23602535

转截地址:http://www.mobiledevor.com/post/34.html

转截地址:http://blog.devtang.com/blog/2012/04/22/use-fmdb/

转截地址:http://www.cnblogs.com/wuhenke/archive/2012/02/07/2341656.html

 

FMDB

https://github.com/ccgus/fmdb

This is an Objective-C wrapper around SQLite: http://sqlite.org/

这是对 SQLite 的封装:http://sqlite.org/

Read the SQLite FAQ:

http://www.sqlite.org/faq.html

Since FMDB is built on top of SQLite, you're going to want to read this page top to bottom at least once. And while you're there, make sure to bookmark the SQLite Documentation page: http://www.sqlite.org/docs.html

因为 FMDB 建立在 SQLite 之上,所以,你至少应该把 SQLite 文档看一遍。看的时候,将 http://www.sqlite.org/docs.html 网址添加到你的浏览器书签中吧。

FMDB Class Reference:

http://ccgus.github.io/fmdb/html/index.html

Automatic Reference Counting (ARC) or Manual Memory Management?

You can use either style in your Cocoa project. FMDB Will figure out which you are using at compile time and do the right thing.

FMDB 支持 ARC 与 非ARC 。

Usage

There are three main classes in FMDB:

FMDB 包含了 3 个主要的类:

  1. FMDatabase - Represents a single SQLite database. Used for executing SQL statements.
  2. FMResultSet - Represents the results of executing a query on an FMDatabase.
  3. FMDatabaseQueue - If you're wanting to perform queries and updates on multiple threads, you'll want to use this class. It's described in the "Thread Safety" section below.
  4. FMDatabase - 代表了单一的一个 SQLite 数据库。用来执行 SQL 语句的。
  5. FMResultSet - 在 FMDatabase 上执行了查询操作后展示的结果。
  6. FMDatabaseQueue - 如果你想在不同的线程中同时执行查询和更新操作,你会用到这个类。在最下面有对其的描述。

Database Creation

An FMDatabase is created with a path to a SQLite database file. This path can be one of these three:

通过给定一个 SQLite 数据库文件的路径来创建 FMDatabase,这个文件路径可由下面 3 种方式提供:

  1. A file system path. The file does not have to exist on disk. If it does not exist, it is created for you.
  2. An empty string (@""). An empty database is created at a temporary location. This database is deleted with the FMDatabase connection is closed.
  3. NULL. An in-memory database is created. This database will be destroyed with the FMDatabaseconnection is closed.
  4. 一个系统文件路径,这个文件路径不一定需要存在,如果不存在,它会自动为你创建。
  5. 一个空的字符串 @“”,它会为你创建一个临时的数据库文件。当 FMDatabase 关闭后,这个数据库就会被删除掉。
  6. 如果参数为 NULL ,那就会在内存中创建一个数据库,当 FMDatabase 关闭后,这个数据库就会被删除掉。

(For more information on temporary and in-memory databases, read the sqlite documentation on the subject:http://www.sqlite.org/inmemorydb.html)

FMDatabase *db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];

Opening

Before you can interact with the database, it must be opened. Opening fails if there are insufficient resources or permissions to open and/or create the database.

在你能使用数据库之前,你必须先打开它。如果系统资源不足,或者你没有权限打开或者创建数据库都会导致打开失败。

if (![db open]) {    [db release];    return;}

Executing Updates(执行更新

Any sort of SQL statement which is not a SELECT statement qualifies as an update. This includes CREATEUPDATEINSERTALTERCOMMITBEGINDETACHDELETEDROPENDEXPLAINVACUUM, and REPLACEstatements (plus many more). Basically, if your SQL statement does not begin with SELECT, it is an update statement.

任何 SQL 语句,如果不是 SELECT 语句都会被看做是一个 updata 操作。包含 CREATEUPDATEINSERTALTERCOMMITBEGINDETACHDELETEDROPENDEXPLAINVACUUM, 以及 REPLACE。所以请注意,如果你的 SQL 语句不是以 SELECT 开始的,那是一个更新操作哦。

Executing updates returns a single value, a BOOL. A return value of YES means the update was successfully executed, and a return value of NO means that some error was encountered. You may invoke the -lastErrorMessage and -lastErrorCode methods to retrieve more information.

执行更新操作会返回一个 BOOL 值。YES 代表更新成功,NO 表示出现了某些错误。你可以调用 -lastErrorMessage 和 -lastErrorCode 方法来寻找错误的信息。

Executing Queries(执行查询

SELECT statement is a query and is executed via one of the -executeQuery... methods.

查询语句 SELECT 通过 -executeQuery.. 中的一些方法来实现。

Executing queries returns an FMResultSet object if successful, and nil upon failure. Like executing updates, there is a variant that accepts an NSError ** parameter. Otherwise you should use the -lastErrorMessageand -lastErrorCode methods to determine why a query failed.

查询成功会返回一个 FMResultSet 对象,失败返回 nil。与执行更新操作一样,有一个变量来接收一个 NSError 参数。当然,你也可以使用 -lastErrorMessage 和 -lastErrorCode 方法来检测为何查询失败。

In order to iterate through the results of your query, you use a while() loop. You also need to "step" from one record to the other. With FMDB, the easiest way to do that is like this:

为了能迭代检索处所有你的查询结果,你可以使用 while() 循环。你需要使用 “step” 来从一条记录跳到另外一条记录。在 FMDB 当中,下面展示的就是最简单的方式。

FMResultSet *s = [db executeQuery:@"SELECT * FROM myTable"];while ([s next]) {    //retrieve values for each record}

You must always invoke -[FMResultSet next] before attempting to access the values returned in a query, even if you're only expecting one:

你必须经常调用方法 -[FMResultSet next] ,哪怕你只是查找一条记录。

FMResultSet *s = [db executeQuery:@"SELECT COUNT(*) FROM myTable"];if ([s next]) {    int totalCount = [s intForColumnIndex:0];}

FMResultSet has many methods to retrieve data in an appropriate format:

FMResultSet 有许多方法来匹配数据格式:

  • intForColumn:
  • longForColumn:
  • longLongIntForColumn:
  • boolForColumn:
  • doubleForColumn:
  • stringForColumn:
  • dateForColumn:
  • dataForColumn:
  • dataNoCopyForColumn:
  • UTF8StringForColumnName:
  • objectForColumnName:

Each of these methods also has a {type}ForColumnIndex: variant that is used to retrieve the data based on the position of the column in the results, as opposed to the column's name.

上面的每一个方法中都有一个 {type}ForColumnIndex:自己的版本,用来匹配数据,基于查询结果中的记录。

Typically, there's no need to -close an FMResultSet yourself, since that happens when either the result set is deallocated, or the parent database is closed.

尤其注意,你不要自己关闭 FMResultSet 。当父数据库关闭,或者是结果集被丢弃,它会自动关闭。

Closing(关闭

When you have finished executing queries and updates on the database, you should -close the FMDatabaseconnection so that SQLite will relinquish any resources it has acquired during the course of its operation.

当你已经执行了查询,更新了数据库,你应该使用 -close 来关闭数据库的连接,让 SQLite 释放你执行那些操作的资源而提高效率。

[db close];

Transactions(事务

FMDatabase can begin and commit a transaction by invoking one of the appropriate methods or executing a begin/end transaction statement.

FMDatabase 可以提交一个事务,通过调用 begin/end 事务语句。

Data Sanitization(数据处理

When providing a SQL statement to FMDB, you should not attempt to "sanitize" any values before insertion. Instead, you should use the standard SQLite binding syntax:

当你提供一条 SQL 语句给 FMDB 时,你不要直接给语句中的变量附上值。你应该使用标准的 SQLite 绑定的语法规则:

INSERT INTO myTable VALUES (?, ?, ?)

The ? character is recognized by SQLite as a placeholder for a value to be inserted. The execution methods all accept a variable number of arguments (or a representation of those arguments, such as an NSArrayNSDictionary, or a va_list), which are properly escaped for you.

?会被识别成一个将要被替换的值。所有的的执行方法都接受不同类型的变量(包括 NSArray , NSDictionary 或者一个 va_list),你会喜欢的。

Alternatively, you may use named parameters syntax:

作为选择,你也可以使用明着参数的语法规则:

INSERT INTO myTable VALUES (:id, :name, :value)

The parameters must start with a colon. SQLite itself supports other characters, but internally the Dictionary keys are prefixed with a colon, do not include the colon in your dictionary keys.

参数之前必须加上冒号。 SQLite 本身支持很多种字符,但是 OC 中字典对象的前缀就是冒号,所以,不要在你的字典 key 值前包含冒号。

NSDictionary *argsDict = [NSDictionary dictionaryWithObjectsAndKeys:@"My Name", @"name", nil];[db executeUpdate:@"INSERT INTO myTable (name) VALUES (:name)" withParameterDictionary:argsDict];

Thus, you SHOULD NOT do this (or anything like this):

因此,你不要这样子写(或者类似这样子的):

[db executeUpdate:[NSString stringWithFormat:@"INSERT INTO myTable VALUES (%@)", @"this has \" lots of ' bizarre \" quotes '"]];

Instead, you SHOULD do:

你应该这样子写:

[db executeUpdate:@"INSERT INTO myTable VALUES (?)", @"this has \" lots of ' bizarre \" quotes '"];

All arguments provided to the -executeUpdate: method (or any of the variants that accept a va_list as a parameter) must be objects. The following will not work (and will result in a crash):

所有提供给 -executeUpdate:方法的参数必须是一个对象。下面的写法是错误的,会导致崩溃。

[db executeUpdate:@"INSERT INTO myTable VALUES (?)", 42];

The proper way to insert a number is to box it in an NSNumber object:

插入一个数字类型的,需要使用 NSNumber 对象:

[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:42]];

Alternatively, you can use the -execute*WithFormat: variant to use NSString-style substitution:

作为一项选择,你可以使用 -exexute*WithFormat:来提交 NSString 方式的语句:

[db executeUpdateWithFormat:@"INSERT INTO myTable VALUES (%d)", 42];

Internally, the -execute*WithFormat: methods are properly boxing things for you. The following percent modifiers are recognized: %@%c%s%d%D%i%u%U%hi%hu%qi%qu%f%g%ld%lu%lld, and %llu. Using a modifier other than those will have unpredictable results. If, for some reason, you need the % character to appear in your SQL statement, you should use %%.

本质上,-excute*WithFormat:方法也是一个?的方式。下面的百分号的方式是能够被识别的: %@%c%s%d%D%i%u%U%hi%hu%qi%qu%f%g%ld%lu%lld, 和 %llu。你使用了其他修饰语而不是这些会导致预料不到的结果。由于某些原因,你需要使用 % 出现在你的 SQL 语句中,你应该使用 %%。

Using FMDatabaseQueue and Thread Safety.(使用数据库队列以及线程安全

Using a single instance of FMDatabase from multiple threads at once is a bad idea. It has always been OK to make a FMDatabase object per thread. Just don't share a single instance across threads, and definitely not across multiple threads at the same time. Bad things will eventually happen and you'll eventually get something to crash, or maybe get an exception, or maybe meteorites will fall out of the sky and hit your Mac Pro. This would suck.

使用一个数据库的单例,用多线程来处理是很愚蠢的。通常,不同的线程处理一个不同的 FMDatabase 对象是安全的。请不要创建数据库单例,并在不同的线程中访问,如果实在不行,也不要让不同的线程同时访问这一个数据库对象。如果你坚持这么做,那经常就会出现一些莫名其妙的崩溃,异常,或者从天而降的陨石砸坏你的苹果电脑,别这么干哦。

So don't instantiate a single FMDatabase object and use it across multiple threads.

所以,不要创建一个 FMDatabase 单例对象,然后在不同的线程中访问。

Instead, use FMDatabaseQueue. It's your friend and it's here to help. Here's how to use it:

你可以使用 FMDatabaseQueue,线程安全就靠它了:

First, make your queue.

首先,创建你的queue。

FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath];

Then use it like so:

然后这么用:

[queue inDatabase:^(FMDatabase *db) {    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]];    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]];    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]];    FMResultSet *rs = [db executeQuery:@"select * from foo"];    while ([rs next]) {        …    }}];

An easy way to wrap things up in a transaction can be done like this:

对于多条查询语句事务的提交,可以这么做:

[queue inTransaction:^(FMDatabase *db, BOOL *rollback) {    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]];    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]];    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]];    if (whoopsSomethingWrongHappened) {        *rollback = YES;        return;    }    // etc…    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:4]];}];

FMDatabaseQueue will run the blocks on a serialized queue (hence the name of the class). So if you call FMDatabaseQueue's methods from multiple threads at the same time, they will be executed in the order they are received. This way queries and updates won't step on each other's toes, and every one is happy.

FMDatabaseQueue 运行在一个串行队列当中。所以,当你在不同的线程中调用了 FMDatabaseQueue 方法,他们将会被序列执行。这种处理方式,不同线程间不会互相干扰,每个线程都很happy^_^。

Note: The calls to FMDatabaseQueue's methods are blocking. So even though you are passing along blocks, they will not be run on another thread.

注意:调用 FMDatabaseQueue 方法是一个 block 。即使你在 block 中使用了 block,它也不会在其它线程中运行。

Making custom sqlite functions, based on blocks.(定制 sqlite 函数,基于 blocks

You can do this! For an example, look for "makeFunctionNamed:" in main.m

你可以定制哦!你在 main.m 文件中看看吧。







ios数据存储中关于Sqlite3使用第三方框架FMDB

 

ios数据存储中关于Sqlite 3使用第三方框架FMDB是本文要介绍的内容,主要讲述在iPhone上是采用sqlite进行数据存储是我一种比较习惯性的做法。一般在其他平台也比较习惯用sqlite,比如android。

ios开发上有一些封装好的第三方框架提供使用,更节省了许多时间。如:Sqlitepersistentobjects ,FMDB 。今天查找了这个两个框架,感觉FMDB的风格更符合我的使用,其实两者是各有优点的,只是看个人喜好而已。以下是FMDB的一些基本使用,FMDB框架其实只是一层很薄的封装,主要的类也就两个:FMDatabase和FMResultSet ;

其中的FMResultSet对象让我想起了android中sqlite的cursor集合啊。

FMDB的github地址是,https://github.com/ccgus/fmdb。

1、首先得实例化一个FMDatabase对象,这跟 Sqlitepersistentobjects 派生一个子类进行操作是不同。接着打开一个数据库(如果没有会创建一个数据库)

 

  1. //paths: ios下Document路径,Document为ios中可读写的文件夹     
  2. NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);    
  3. NSString *documentDirectory = [paths objectAtIndex:0];    
  4. //dbPath: 数据库路径,在Document中。     
  5. NSString *dbPath = [documentDirectory stringByAppendingPathComponent:@"Test.db"];    
  6. //创建数据库实例 db  这里说明下:如果路径中不存在"Test.db"的文件,sqlite会自动创建"Test.db"     
  7. FMDatabase *db= [FMDatabase databaseWithPath:dbPath] ;    
  8. if (![db open]) {    
  9. NSLog(@"Could not open db.");    
  10. return ;    
  11. }    
  12. //paths: ios下Document路径,Document为ios中可读写的文件夹  
  13. NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);  
  14. NSString *documentDirectory = [paths objectAtIndex:0];  
  15. //dbPath: 数据库路径,在Document中。  
  16. NSString *dbPath = [documentDirectory stringByAppendingPathComponent:@"Test.db"];  
  17. //创建数据库实例 db  这里说明下:如果路径中不存在"Test.db"的文件,sqlite会自动创建"Test.db"  
  18. FMDatabase *db= [FMDatabase databaseWithPath:dbPath] ;  
  19. if (![db open]) {  
  20. NSLog(@"Could not open db.");  
  21. return ;  
  22. }    

接下来,我们可以通过这个数据库对象进行操作了。操作主要是update和queries。

首先是创建表。

 

  1. //创建一个名为User的表,有两个字段分别为string类型的Name,integer类型的 Age     
  2. [db executeUpdate:@"CREATE TABLE User (Name text,Age integer)"];    
  3. //创建一个名为User的表,有两个字段分别为string类型的Name,integer类型的 Age  
  4. [db executeUpdate:@"CREATE TABLE User (Name text,Age integer)"];  

这样我们就有了一张表了。接下我们对表进行操作。插入数据!注意插入的数据使用了通配符,这跟iphone直接使用sqlite借口的绑定变量是一样的,后面的通配符匹配的数据。

 

  1. //插入数据使用OC中的类型 text对应为NSString integer对应为NSNumber的整形     
  2. [db executeUpdate:@"INSERT INTO User (Name,Age) VALUES (?,?)",@"老婆",[NSNumber numberWithInt:20]]    
  3. //插入数据使用OC中的类型 text对应为NSString integer对应为NSNumber的整形  
  4. [db executeUpdate:@"INSERT INTO User (Name,Age) VALUES (?,?)",@"老婆",[NSNumber numberWithInt:20]]  

接下来是更新数据。

 

  1. //更新数据 将“老婆”更改为“宝贝”     
  2. [db executeUpdate:@"UPDATE User SET Name = ? WHERE Name = ? ",@"老婆",@"宝贝"];    
  3. //更新数据 将“老婆”更改为“宝贝”  
  4. [db executeUpdate:@"UPDATE User SET Name = ? WHERE Name = ? ",@"老婆",@"宝贝"];  

再接下来,就是删除数据啦。

 

  1. //删除数据     
  2. [db executeUpdate:@"DELETE FROM User WHERE Name = ?",@"老婆"];    
  3. //删除数据  
  4. [db executeUpdate:@"DELETE FROM User WHERE Name = ?",@"老婆"];  

update的基本操作就这几个,接下来是queries!

 

  1. //返回数据库中第一条满足条件的结果     
  2. NSString *aa=[db stringForQuery:@"SELECT Name FROM User WHERE Age = ?",@"20"];    
  3. //返回数据库中第一条满足条件的结果  
  4. NSString *aa=[db stringForQuery:@"SELECT Name FROM User WHERE Age = ?",@"20"];  

这样我们就查询返回了一条数据,那当我们想要查询放返回多条数据怎么办呢?不用愁,之前我就提到了FMDB中的另外一个主要的类,FMResultSet,这是一个结果集!返回多条数据时FMDB会将数据放在这个结果集中,然后我们在对这个结果集进行查询操作!很简单。

 

  1. FMResultSet *rs=[db executeQuery:@"SELECT * FROM User"];    
  2. rs=[db executeQuery:@"SELECT * FROM User WHERE Age = ?",@"20"];    
  3. while ([rs next]){    
  4. NSLog(@"%@ %@",[rs stringForColumn:@"Name"],[rs stringForColumn:@"Age"]);    
  5. }    
  6. FMResultSet *rs=[db executeQuery:@"SELECT * FROM User"];  
  7. rs=[db executeQuery:@"SELECT * FROM User WHERE Age = ?",@"20"];  
  8. while ([rs next]){  
  9. NSLog(@"%@ %@",[rs stringForColumn:@"Name"],[rs stringForColumn:@"Age"]);  
  10. }  

更多的 FMResultSet方法有:

 

  1. intForColumn:   
  2. longForColumn:   
  3. longLongIntForColumn:   
  4. boolForColumn:   
  5. doubleForColumn:   
  6. stringForColumn:   
  7. dateForColumn:   
  8. dataForColumn:   
  9. dataNoCopyForColumn:   
  10. UTF8StringForColumnIndex:   
  11. objectForColumn:  

具体查看一下类就行了! 好了,对于FMDB的使用就这样,是不是很简单呢,其实这个些封装sqlite的框架都是万变不离其宗的,只要你掌握了sql就行了!

小结:iPhone数据存储中关于Sqlite 3使用第三方框架FMDB的内容介绍完了,希望本文对你有所帮助

 

 

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

在iOS开发中使用FMDB

前言

SQLite (http://www.sqlite.org/docs.html) 是一个轻量级的关系数据库。iOS SDK很早就支持了SQLite,在使用时,只需要加入 libsqlite3.dylib 依赖以及引入 sqlite3.h 头文件即可。但是,原生的SQLite API在使用上相当不友好,在使用时,非常不便。于是,开源社区中就出现了一系列将SQLite API进行封装的库,而FMDB (https://github.com/ccgus/fmdb) 则是开源社区中的优秀者。

FMDB在使用上相当方便。以下是一个简单的例子:

1234567891011
NSString* docsdir = [NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES) lastObject];NSString* dbpath = [docsdir stringByAppendingPathComponent:@"user.sqlite"];FMDatabase* db = [FMDatabase databaseWithPath:dbpath];[db open];FMResultSet *rs = [db executeQuery:@"select * from people"];while ([rs next]) {    NSLog(@"%@ %@",        [rs stringForColumn:@"firstname"],        [rs stringForColumn:@"lastname"]);}[db close];

可以看到,使用FMDB后的数据库代码清晰明了,比原生的API优雅多了。另外,FMDB同时兼容ARC和非ARC工程,会自动根据工程配置来调整相关的内存管理代码。

使用说明

该使用说明主要翻译自fmdb的github项目说明文档: https://github.com/ccgus/fmdb

引入相关文件

首先将FMDB从github上clone下来,然后将以下文件copy到你的工程中:

12345678910
FMDatabase.hFMDatabase.mFMDatabaseAdditions.hFMDatabaseAdditions.mFMDatabasePool.hFMDatabasePool.mFMDatabaseQueue.hFMDatabaseQueue.mFMResultSet.hFMResultSet.m

建立数据库

建立数据库只需要如下一行即可,当该文件不存在时,fmdb会自己创建一个。如果你传入的参数是空串:@”” ,则fmdb会在临时文件目录下创建这个数据库,如果你传入的参数是 NULL,则它会建立一个在内存中的数据库。

1
FMDatabase *db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];

打开数据库

使用如下语句,如果打开失败,可能是权限不足或者资源不足。通常打开完操作操作后,需要调用close方法来关闭数据库。

12345678
if (![db open]) {    // error     return;}// some operation// ...[db close];

执行更新操作

除了Select操作之外,其它的都是更新操作。更新操作使用如下方法,如果有错误,可以用error参数中获得。

1
-[FMDatabase executeUpdate:error:withArgumentsInArray:orVAList:]

执行查询操作

查询操作示例如下。注意:即使操作结果只有一行,也需要先调用FMResultSet的next方法。

123456789
FMResultSet *s = [db executeQuery:@"SELECT * FROM myTable"];while ([s next]) {    //retrieve values for each record}FMResultSet *s = [db executeQuery:@"SELECT COUNT(*) FROM myTable"];if ([s next]) {    int totalCount = [s intForColumnIndex:0];}

FMDB提供如下多个方法来获取不同类型的数据:

1234567891011
intForColumn:longForColumn:longLongIntForColumn:boolForColumn:doubleForColumn:stringForColumn:dateForColumn:dataForColumn:dataNoCopyForColumn:UTF8StringForColumnIndex:objectForColumn:

通常情况下,你并不需要关闭FMResultSet,因为相关的数据库关闭时,FMResultSet也会被自动关闭。

数据参数

通常情况下,你可以按照标准的SQL语句,用?表示执行语句的参数,如:

1
INSERT INTO myTable VALUES (?, ?, ?)

然后,可以我们可以调用executeUpdate方法来将?所指代的具体参数传入,通常是用变长参数来传递进去的,如下:

12
NSString *sql = @"insert into User (name, password) values (?, ?)";[db executeUpdate:sql, user.name, user.password];

这里需要注意的是,参数必须是NSObject的子类,所以象int,double,bool这种基本类型,需要封装成对应的包装类才行,如下所示:

1234
// 错误,42不能作为参数[db executeUpdate:@"INSERT INTO myTable VALUES (?)", 42];// 正确,将42封装成 NSNumber 类[db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:42]];

线程安全

如果我们的app需要多线程操作数据库,那么就需要使用FMDatabaseQueue来保证线程安全了。切记不能在多个线程中共同一个FMDatabase对象并且在多个线程中同时使用,这个类本身不是线程安全的,这样使用会造成数据混乱等问题。

使用FMDatabaseQueue很简单,首先用一个数据库文件地址来初使化FMDatabaseQueue,然后就可以将一个闭包(block)传入inDatabase方法中。在闭包中操作数据库,而不直接参与FMDatabase的管理。

12345678910111213141516171819202122232425262728
// 创建,最好放在一个单例的类中FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath];// 使用[queue inDatabase:^(FMDatabase *db) {    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]];    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]];    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]];    FMResultSet *rs = [db executeQuery:@"select * from foo"];    while ([rs next]) {        // …    }}];// 如果要支持事务[queue inTransaction:^(FMDatabase *db, BOOL *rollback) {    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:1]];    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:2]];    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:3]];    if (whoopsSomethingWrongHappened) {        *rollback = YES;        return;    }    // etc…    [db executeUpdate:@"INSERT INTO myTable VALUES (?)", [NSNumber numberWithInt:4]];}];

工具

为了查看Sqlite中的数据,一个好的图形化界面的数据库管理程序是必不可少的。mysql有phpMyAdmin,那么sqlite呢?

我主要使用的是Firefox的一个名为SQLite Manager的插件,安装此插件后,可以直接打开后缀名为sqlite的数据库文件。SQLite Manager提供一个图形化的界面来执行数据查询或更改操作。如下图所示:

总结

FMDB将SQLite API进行了很友好的封装,使用上非常方便,对于那些使用纯Sqlite API来进行数据库操作的app,可以考虑将其迁移到基于FMDB上,这对于以后数据库相关功能的开发维护,可以提高不少效率。

我在学习fmdb的时候做了一个小工程用于练习,我把它放到github上了。感兴趣的可以自行下载:https://github.com/tangqiaoboy/FmdbSample

 

 

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

Sqlite第三方类库FMDB的使用

 

首先到这裡下载FMDB的source code,接著在解开的档案裡,把src资料夹下除了fmdb.m的档案加入到自己的iOS专案,最后在专案中加入libsqlite3.dylib这个函式库就可以了。啥?有人问為什麼不用加入fmdb.m?简单讲,这个档案是fmdb的使用说明。裡面的註解清楚,范例又简单,如果有兴趣,直接看fmdb.m,大概就会用fmdb了。
以下介绍几个常用的指令,分享给大家:
-打开/关闭资料库

使用资料库的第一件事,就是建立一个资料库。要注意的是,在iOS环境下,只有document directory 是可以进行读写的。在写程式时用的那个Resource资料夹底下的东西都是read-only。因此,建立的资料库要放在document 资料夹下。方法如下: 

1NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
2NSString *documentDirectory = [paths objectAtIndex:0];
3NSString *dbPath = [documentDirectory stringByAppendingPathComponent:@"MyDatabase.db"];
4FMDatabase *db = [FMDatabase databaseWithPath:dbPath] ;
5if (![db open]) {
6   NSLog(@“Could not open db.”);
7   return ;
8}

建立table 

如果是新建的资料库档,一开始是没有table的。建立table的方式很简单:

1[db executeUpdate:@"CREATE TABLE PersonList (Name text, Age integer, Sex integer, Phone text, Address text, Photo blob)"];

这是FMDB裡很常用的指令,[FMDatabase_object executeUpdate:]后面用NSString塞入SQLite语法,就解决了。因為这篇主要是在讲FMDB,所以SQLite的语法就不多说了,上述程式码建立了一个名為PersonList的table,裡面有姓名、年龄、性别、电话、地址和照片。(嗯….很范例的一个table)

-插入资料
插入资料跟前面一样,用executeUpdate后面加语法就可以了。比较不同的是,因為插入的资料会跟Objective-C的变数有关,所以在string裡使用?号来代表这些变数。

1[db executeUpdate:@"INSERT INTO PersonList (Name, Age, Sex, Phone, Address, Photo) VALUES (?,?,?,?,?,?)",
2 
3@"Jone", [NSNumber numberWithInt:20], [NSNumber numberWithInt:0], @“091234567”, @“Taiwan, R.O.C”, [NSData dataWithContentsOfFile: filepath]];

其中,在SQLite中的text对应到的是NSString,integer对应NSNumber,blob则是NSData。该做的转换FMDB都做好了,只要了解SQLite语法,应该没有什麼问题才是。
-更新资料
太简单了,不想讲,请看范例:
1[db executeUpdate:@"UPDATE PersonList SET Age = ? WHERE Name = ?",[NSNumber numberWithInt:30],@“John”];

-取得资料
取得特定的资料,则需使用FMResultSet物件接收传回的内容:

01FMResultSet *rs = [db executeQuery:@"SELECT Name, Age, FROM PersonList"];
02 
03while ([rs next]) {
04 
05NSString *name = [rs stringForColumn:@"Name"];
06 
07int age = [rs intForColumn:@"Age"];
08 
09}
10 
11[rs close];

用[rs next]可以轮询query回来的资料,每一次的next可以得到一个row裡对应的数值,并用[rs stringForColumn:]或[rs intForColumn:]等方法把值转成Object-C的型态。取用完资料后则用[rs close]把结果关闭。
-快速取得资料
在有些时候,只会query某一个row裡特定的一个数值(比方只是要找John的年龄),FMDB提供了几个比较简便的方法。这些方法定义在FMDatabaseAdditions.h,如果要使用,记得先import进来。
view source
print
1//找地址
2 
3NSString *address = [db stringForQuery:@"SELECT Address FROM PersonList WHERE Name = ?",@"John”];
4 
5//找年齡
6 
7int age = [db intForQuery:@"SELECT Age FROM PersonList WHERE Name = ?",@"John”];

 

 

 

原创粉丝点击