iOS Sqlite数据库


iOS Sqlite数据库

本章内容概述

  • Sqlite 简介
  • 在命令行使用Sqlite
  • 使用Sqlite实现表的增、删、查、改
  • Sqlite和UITableView结合使用

22.1 Sqlite 简介

sqlite是一个开源的嵌入式数据库引擎,广泛应用在嵌入式设备操作系统中,例如,早期的Symbian、android、ios等系统中。

Sqlite的官方站点是:http://sqlite.org/index.html ,更多详细用法可以从该站点找到。标准的sql语言在sqlite数据库中都支持。这里我们需要了解的是sqlite中的数据类型。

表22.1 sqlite数据类型

名称 描述
NULL 空值
INTEGER 带符号的整型,具体取决有存入数字的范围大小
REAL 浮点数字,存储为8-byte IEEE浮点数
TEXT 字符串文本
BLOB 二进制对象

22.2 在命令行使用Sqlite

Mac提供了对sqlite的支持,可以通过命令行的方法来创建数据库和表。可以在命令行通过sql语句来操作数据库和表。

在Mac系统中打开Terminal终端,使用sqlite3命令来打开或创建数据库。例如,在终端输入sqlite3 test.db 就可以在当前目录下创建一个test.db数据库。我们通过下面步骤来创建一个数据库test.db 并在该库中创建一个UserTbl数据表,并对该并进行增、删、查、改等操作。

  1. 打开终端输入如下命令,可以创建一个数据库。

sqlite3 test.db

图22.1 使用sqlite3命令创建数据库

  1. 如上图所示,当前的提示符变成了sqlite,这里我们可以输入.help需求帮助。

图22.2 使用sqlite3命令帮助

这些命令很多,常用的有查看当前目录下的数据库.databases,查看当前库下面的表.tables以及查看表结构.schema tablename等命令。

  1. 下面我们来在test.db数据库中创建一个UserTbl表。

create table UserTbl(uid integer primary key autoincrement,username text,pwd text);

这里uid是主键并且是自动增加的。

  1. 下面通过insert into sql语言插入几条记录。
insert into UserTbl(username,pwd)values(`tom`,`123`);
insert into UserTbl(username,pwd)values(`kite`,`456`);
  1. 使用下面sql语言可以查询到uid=1的用户。
select username,pwd from UserTbl where uid=1;
  1. 下面是删除uid为1的用户。
delete from UserTbl where uid=1;
  1. 下面是修改uid为2的用户名称。
update UserTbl set username=`big kite`; where uid=2;

以上是sqlite命令行操作的常用sql语言,这些语句在实际的项目测试和项目开发中都能应用得到。

22.3 使用Sqlite实现表的增、删、查、改

在上一节我们讲述了如何在命令行进行数据库和表的操作,实际开发当中我们更多的是通过程序api接口来实现表的增、删、查、改等操作。本节我们将通过程序的方式实现sqlite的增、删、查、改。

在程序中使用sqlite数据库需要导入sqlite数据库的动态库libsqlite3.dylib。选择项目名称,在右边的"TARGET"中的"Build Phases"中选择"Link Binary With Libraries"中选择"+"添加。如下图所示。

图22.3 为项目添加sqlite动态库

并且在程序中需要导入#import "/usr/include/sqlite3.h"头文件。

Sqlite数据库编程中,使用了一组以sqlite3打头的函数,来实现数据库和表的操作。通过下面表格我们先来认识一下这些函数。

表22.2 sqlite数据库函数

名称 描述
sqlite3 表示数据库对象
sqlite3_open 打开数据库
sqlite3_close 关闭数据库
sqlite3_exec 执行sql语句,例如,创建表
sqlite3_prepare_v2 预定义语句
sqlite3_bind_xxx 绑定数据
sqlite3_step 执行预定义语句
sqlite3_column_text 获得某列数据

sqlite数据库编程的基本步骤是:

  1. 创建或者打开库。
  2. 创建表
  3. 增、删、查、改操作。
  4. 关闭库。

下面通过一个案例来演示如何使用sqlite数据库,实现步骤如下所示:

  1. 创建一个项目,添加libsqlite3.dylib库。
  2. 在xib文件中添加5个按钮,分别实现创建库、创建表、插入、删除、更新和查询操作。
  3. 创建一个类Person和数据库中的Person表映射。
#import <Foundation/Foundation.h>

@interface Person : NSObject

// id

@property(nonatomic)int pid;

// 姓名

@property(nonatomic,retain)NSString *name;

// 密码

@property(nonatomic,retain)NSString *pwd;

@end
  1. 创建一个数据库工具类DbUtil.h 在该类中实现增、删、查、改操作。
#import <Foundation/Foundation.h>

// 导入头文件

#import "/usr/include/sqlite3.h"

#import "Person.h"

// 定义数据库名称

#define kDbName @"test.db"

@interface DbUtil : NSObject

// 获得数据库文件路径方法

-(NSString*)getPath;

// 打开库

-(sqlite3*)open;

// 关闭库

-(void)close:(sqlite3*)db;

// 创建表

-(void)createTable:(sqlite3*)db;

// 插入

-(void)insert:(Person*)per;

// 删除

-(void)del:(int)pid;

// 更新

-(void)update:(Person*)per;

// 查询

-(NSMutableArray*)query;

// 根据id查询

-(Person*)findPerson:(int)pid;

@end
  1. 获得数据库保存路径,获得程序文档路径,并附加数据库名称即可。
// 获得数据库保存路径

-(NSString*)getPath{

    // 获得文件路径

    NSArray *docPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

    NSString *path = [docPaths objectAtIndex:0];

    // 创建数据库路径

    path = [path stringByAppendingPathComponent:kDbName];

    return  path;

}
  1. 打开数据库,声明sqlite3数据库对象,调用sqlite3_open函数,传递数据库文件路径和sqlite3二级指针打开库。
// 打开数据库

-(sqlite3*)open{

    // 声明数据库

    sqlite3 *database;

    // 获得数据库路径

    NSString *path = [self getPath];

    NSLog(@"%@",path);

    // 打开库

    NSInteger result = sqlite3\_open([path UTF8String], &amp;database);

    if (result==SQLITE\_OK) {

        // 返回数据库

        return database;

    }

    return nil;

}
  1. 关闭库,调用sqlite3_close函数,传递sqlite3对象关闭数据库。
// 关闭库

-(void)close:(sqlite3 *)db{

    if(db!=nil)

        sqlite3\_close(db);

}
  1. 创建表方法,准备创建表的sql语句,调用sqlite3_exec方法来执行。
// 创建表

-(void)createTable:(sqlite3 *)db{

    // 创建表sql语句

    char *sql = "create table PerTbl (pid integer primary key autoincrement, name text,pwd text) ";

    // 执行sql语句创建表

    int result = sqlite3\_exec(db, sql, 0, nil, nil);

    // 判断是否创建成功

    if (result==SQLITE\_OK) {

        NSLog(@"%@",@"create ok.");

    }else{

         NSLog(@"%@",@"create fail.");

    }

}
  1. 插入数据,插入数据需要打开数据库,准备sql语句,并准备预定义语句,绑定数据,并执行sql语句。
// 插入数据

-(void)insert:(Person *)per{

    // 打开数据库

    sqlite3 *db = [self open];

    // 插入sql语句

    char *sql = "insert into PerTbl(name,pwd)values(?,?) ";

    // 预定义语句

    sqlite3\_stmt *stmt;

    //准备预定义语句

    if(sqlite3\_prepare\_v2(db, sql , -1, &amp;stmt, nil)==SQLITE\_OK){

        // 绑定数据

        sqlite3\_bind\_text(stmt, 1, "tom", -1, nil);

        sqlite3\_bind\_text(stmt, 2, "123", -1, nil);

    }

    // 执行sql

    if(sqlite3\_step(stmt)==SQLITE\_DONE){

        NSLog(@"%@",@"insert ok.");

    }else{

        NSLog(@"%@",@"insert fail.");

    }

    // 释放语句

    sqlite3\_finalize(stmt);

    // 关闭数据库

    [self close:db];

}
  1. 删除数据的流程和插入数据的流程类似,这里不多赘述。
// 删除数据

-(void)del:(int)pid{

    // 打开数据库

    sqlite3 *db = [self open];

    // 准备sql

    char *sql = "delete from PerTbl where pid=? ";

    // 定义预定义语句

    sqlite3\_stmt *stmt;

    // 准备预定义语句

    if(sqlite3\_prepare\_v2(db, sql , -1, &amp;stmt, nil)==SQLITE\_OK){

        // 绑定数据

        sqlite3\_bind\_int(stmt, 1, pid);

    }

    // 执行语句

    if(sqlite3\_step(stmt)==SQLITE\_DONE){

        NSLog(@"%@",@"del ok.");

    }else{

        NSLog(@"%@",@"del fail.");

    }

    // 是否资源

    sqlite3\_finalize(stmt);

    // 关闭数据库

    [self close:db];

}
  1. 更新数据。
// 更新

-(void)update:(Person *)per{

    // 打开库

    sqlite3 *db = [self open];

    // sql

    char *sql = "update PerTbl set name =?,pwd=? where pid=?";

    // 声明预定义语句

    sqlite3\_stmt *stmt;

    // 准备预定义

    if(sqlite3\_prepare\_v2(db, sql , -1, &amp;stmt, nil)==SQLITE\_OK){

        // 绑定数据

        sqlite3\_bind\_text(stmt, 1, [[per name] UTF8String], -1, nil);

        sqlite3\_bind\_text(stmt, 2, [[per pwd]UTF8String], -1, nil);

        sqlite3\_bind\_int(stmt, 3, [per pid]);

    }

    // 执行预定义语句

    if(sqlite3\_step(stmt)==SQLITE\_DONE){

        NSLog(@"%@",@"update ok.");

    }else{

        NSLog(@"%@",@"update fail.");

    }

    // 释放资源

    sqlite3\_finalize(stmt);

    // 关闭数据库

    [self close:db];

}
  1. 查询数据,查询流程和插入、删除类似,不同的地方是循环调用sqlite3_step方法获得数据,并使用sqlite3_column_xxx方法获得列数据。
// 查询

-(NSMutableArray*)query{

    // 打开数据库

    sqlite3 *db = [self open];

    // 查询sql

    char *sql = " select pid,name,pwd from PerTbl ";

    // 预定义语句

    sqlite3\_stmt *stmt;

    // 可变数组

    NSMutableArray *array = [NSMutableArray arrayWithCapacity:10];

    // 准备预定义语句

    if(sqlite3\_prepare\_v2(db, sql , -1, &amp;stmt, nil)==SQLITE\_OK){

        // 循环获得数据

        while (sqlite3\_step(stmt)==SQLITE\_ROW) {

            // 获得第一列数据

            int pid = sqlite3\_column\_int(stmt, 0);

            // 第二列

            const char *name = (char*)sqlite3\_column\_text(stmt, 1);

            // 第三列

            char *pwd = (char*)sqlite3\_column\_text(stmt, 2);

            // 实例化Person

            Person *per = [[Person alloc]init];

            // 赋值

            [per setPid:pid];

            [per setPwd:[NSString stringWithUTF8String:pwd]];

            [per setName:[NSString stringWithUTF8String:name]];

            // 添加到数组

            [array addObject:per];

        }

    }

    // 是否资源

    sqlite3\_finalize(stmt);

    // 关闭数据库

    [self close:db];

    return array;

}
  1. 以上是数据的处理方法,下面在界面按钮的事件方法中调用上述方法实现数据库的维护。
// 创建表

- (IBAction)create:(id)sender {

    sqlite3 *db;

    db = [util open];

    [util createTable:db];

    [util close:db];

}

// 插入数据

- (IBAction)insert:(id)sender {

    Person *per = [[Person alloc]init];

    [per setPid:1];

    [per setName:@"tom"];

    [per setPwd:@"123"];

    [util insert:per];

}

// 删除数据

- (IBAction)delete2:(id)sender{

    [util del:1];

}

// 更新数据

- (IBAction)update:(id)sender {

    Person *per = [[Person alloc]init];

    [per setPid:3];

    [per setName:@"tom3"];

    [per setPwd:@"333"];

    [util update:per];

}

// 查询数据

- (IBAction)query:(id)sender {

    [util query];

}
  1. 程序运行结果如下所示。

图22.4 实现数据库的增、删、查、改

22.4 Sqlite和UITableView结合使用

在上一节我们只是孤立、枯燥的来演示了sqlite数据库的用法,实现项目当中数据库中的数据需要漂亮的界面加以维护的,本节将sqlite数据库和UITableView结合在一起来讲述它们的组合应用。

本节我们将在上一节的基础上创建如下图所示的程序。导航栏中有添加和删除按钮,点击添加按钮弹出对话框实现添加,点击删除按钮删除数据,表格视图显示当前数据库中的数据。

图22.5 Sqlite和UITableView结合使用

该程序的实现步骤如下:

  1. 创建一个项目,在界面上添加UITableView。
  2. 在.h控制器头文件中实现表视图数据源协议和代理协议,以及警告视图代理协议,表格视图属性、数据源属性、数据库工具类属性和导航按钮属性。
#import <UIKit/UIKit.h>

#import "DbUtil.h"

// 实现表视图数据源协议和代理协议,以及警告视图代理协议

@interface AmakerViewController : UIViewController<UITableViewDataSource,UITableViewDelegate,UIAlertViewDelegate>

// 表格视图属性

@property (strong, nonatomic) IBOutlet UITableView *tableView;

// 数据源属性

@property(nonatomic,strong)NSMutableArray *dataSource;

// 数据库工具类属性

@property(nonatomic,strong)DbUtil *util;

// 导航按钮属性

@property(nonatomic,strong)UIBarButtonItem *addItem,*delItem;

@end
  1. 在控制器.m的实现文件中的viewDidLoad方法中,实例化数据库工具类,创建表,查询数据库数据并赋值给数据源,实例化导航按钮并绑定插入和删除方法。
- (void)viewDidLoad

{

    [super viewDidLoad];

    // 实例化数据库工具类

 self.util = [[DbUtil alloc]init];

    // 创建表

    [self.util createTable];

    // 查询数据

    self.dataSource = [self.util query];

    // 添加按钮

    self.addItem = [[UIBarButtonItem alloc]initWithTitle:@"Add" style:UIBarButtonItemStylePlain target:self action:@selector(add)];

    self.navigationItem.rightBarButtonItem = self.addItem;

    // 删除按钮

    self.delItem = [[UIBarButtonItem alloc]initWithTitle:@"Del" style:UIBarButtonItemStylePlain target:self action:@selector(del)];

    self.navigationItem.leftBarButtonItem = self.delItem;

}
  1. 点击导航栏的添加按钮显示添加对话框。
// 使用对话框添加

-(void)add{

    UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Add" message:nil delegate:self cancelButtonTitle:@"Add" otherButtonTitles:@"Cancel", nil];

    alert.alertViewStyle = UIAlertViewStyleLoginAndPasswordInput;

    [alert show];

}
  1. 点击删除按钮更改表格视图的编辑模式。
// 删除方法,更改表格的编辑状态

-(void)del{

    BOOL result = [self.tableView isEditing];

    if (result) {

        [self.tableView setEditing:NO];

        self.delItem.title=@"Del";

    }else{

        [self.tableView setEditing:YES];

        self.delItem.title = @"Done";

    }

}
  1. 在对话框的代理方法中实现添加数据。获得输入框的数据,根据该数据创建Person对象,调用数据库工具类添加数据,并重新加载表。
// 添加数据

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{

    UITextField *nameTf = [alertView textFieldAtIndex:0];

    UITextField *pwdTf = [alertView textFieldAtIndex:1];

    NSString *name = nameTf.text;

    NSString *pwd = pwdTf.text;

    Person *p = [[Person alloc]init];

    p.name = name;

    p.pwd = pwd;

    nameTf.text=@"";

    pwdTf.text=@"";

    [self.util insert:p];

    [self.tableView reloadData];

}
  1. 实现表格视图的代理方法,查询数据库作为表格行返回值。
// 表格行数

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{

    self.dataSource = [self.util query];

    return [self.dataSource count];

}
  1. 实现表格视图代理的获得表单元方法,将数据库数据显示在表格中。
// 表格单元

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

    static NSString *cid = @"cid";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cid];

    if (cell==nil) {

        cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cid];

    }

    Person *p = [self.dataSource objectAtIndex:[indexPath row]];

    cell.textLabel.text = p.name;

    cell.detailTextLabel.text = p.pwd;

    return cell;

}