SQLite是一款轻型的嵌入式数据库,占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了,处理速度很快。数据库的存储结构和excel很像,以表(table)为单位。
学习在iOS中使用SQLite之前,最好先学会SQL语句,SQL中的常用关键字有
select、insert、update、delete、from、create、where、desc、order、by、group、table、alter等等。
这里不介绍SQL,如果需要学习的请直接移步w3cSchool。这里直接上代码,介绍在iOS中使用SQLite的方法。
使用sqlite需要现在项目中导入libsqlite3.dylib,并在程序文件中导入sqlite3.h头文件。
sqlite3 *_db; //数据库
//获取数据库文件路径
NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *sqlitePath = [doc stringByAppendingPathComponent:@"student.sqlite"];
//打开数据库,如果数据库文件不存在,程序会自动创建
int result = sqlite3_open(sqlitePath.UTF8String, &_db);
if (result == SQLITE_OK) {
NSLog(@"成功打开数据库");
const char *sql = "create table if not exists t_student (id integer primary key autoincrement, name text, age integer);";
char *error = NULL;
int result = sqlite3_exec(_db, sql, NULL, NULL, &error);
if (result == SQLITE_OK) {
NSLog(@"成功创建表student");
}else {
NSLog(@"创建表失败");
}
}else{
NSLog(@"打开数据库失败");
}
- (IBAction)insertBtnClick:(id)sender {
NSString *sql = [NSString stringWithFormat:@"insert into t_student (name, age) values('jack', 10);"];
char *error = NULL;
int result = sqlite3_exec(_db, sql.UTF8String, NULL, NULL, &error);
if (result == SQLITE_OK) {
NSLog(@"插入成功");
}else{
NSLog(@"插入失败");
}
}
}
- (IBAction)updateBtnClick:(id)sender {
//把年龄为10的学生姓名更改为mike
NSString *sql = [NSString stringWithFormat:@"update t_student set name='mike' where and age=10"];
char *error = NULL;
int result = sqlite3_exec(_db, sql.UTF8String, NULL, NULL, &error);
}
- (IBAction)deleteBtnClick:(id)sender {
//一次性删除表中的全部数据,如果要删除某条数据,可以使用where关键字
const char *sql = "delete from t_student;";
char *error = NULL;
int result = sqlite3_exec(_db, sql, NULL, NULL, &error);
}
通过上面的代码可以看出,增删改操作的步骤基本上只有2步:
查询可以说是数据库管理中最重要的一个操作,因此单独拿出来讲。
- (IBAction)queryBtnClick:(id)sender {
const char *sql = "select id, name, age from t_student s where s.name like ? and s.age > 20;";
//存放查询结果集
sqlite3_stmt *stmt = NULL;
//检测查询语句的合法性
//第三个参数表示查询语句的最大长度,设为-1程序会自动计算
int result = sqlite3_prepare_v2(_db, sql, -1, &stmt, NULL);
if (result == SQLITE_OK) {
NSLog(@"查询语句是合法的");
//设置占位符(也就是上面sql语句中的问号-?)的内容
//%是sql中的通配符之一,在这里使用需要连续写两个%%,程序才会理解为sql中的通配符
//%%mike%%表示查询条件为名字中间含有mike即可,前面和后面的值不管
//如果占位符的值为int类型,则使用sqlite3_bind_int
sqlite3_bind_text(stmt, 1, "%%mike%%", -1, NULL);
//查询到一行数据
while (sqlite3_step(stmt) == SQLITE_ROW) {
//获取第0、1、2列的数据
int sid = sqlite3_column_int(stmt, 0);
const unsigned char *sname = sqlite3_column_text(stmt, 1);
int sage = sqlite3_column_int(stmt, 2);
NSLog(@"查询成功-->%d, %s, %d", sid, sname, sage);
if (sqlite3_step(stmt) == SQLITE_DONE) {
NSLog(@"查询完毕");
}
}
//不需要stmt的时候就把它释放
sqlite3_finalize(stmt);
}else {
NSLog(@"查询失败");
}
}
一般情况下,查询语句的编写都使用占位符赋值,而不是接收传过来的参数后直接赋值,这是因为SQL有一个漏洞叫注入漏洞。比如一个人要输入一个帐号密码来登录某个系统,他可以这么做:
帐号: 123 ’ or 1 = 1 or ’ ’ = ’
密码:(随便写一个)123456
则在程序中,查询语句就会变成这样:
select * from t_user where account='123' or 1 = 1 or ' ' = ' ' and password='123456';
所以,为了解决这个问题,查询语句一般都先使用占位符,之后再进行赋值。
//查询t_student中的行数
int count = 0;
const char *sql_count = "select count(*) from t_student";
sqlite3_stmt *stmt2 = NULL;
int result2 = sqlite3_prepare_v2(_db, sql_count, -1, &stmt2, NULL);
if (result2 == SQLITE_OK) {
if (sqlite3_step(stmt2) == SQLITE_ROW) {
count = sqlite3_column_int(stmt2, 0);
NSLog(@"查询完毕");
}
sqlite3_finalize(stmt2);
NSLog(@"%d", count);
}
SQLite中,外键是默认关闭的,如果要开启,则应该执行下面这条语句。
sqlite3_exec(_db, "PRAGMA foreign_keys = ON", NULL, NULL, NULL);
且每次连接(操作)数据库时,如果需要使用外键的功能,都需要执行这条语句。
const char *sql_stu =
"create table if not exists t_student (id integer primary key autoincrement, name text not null, age integer, class_id integer, constraint fk_t_student_class_id_t_class_id foreign key(class_id) references t_class(id) on delete cascade on update cascade);";
const char *sql_class =
"create table if not exists t_class (id integer primary key autoincrement, name text not null unique);";
上面sql_stu的最后一句的意思是,创建一个名为 fk_t_student_class_id_t_class_id 的外键约束,把表t_student中的”class_id”和表t_class中的”id”关联起来。on delete cascade的意思是级联删除,比如说表t_student中某一行数据的calss_id为11,如果表t_class中id为11的数据被删除,则表t_student中calss_id为11的那行数据也会被删除。on update cascade同理。
for(int i=0; i<20; i++){
NSString *sql_stu = [NSString stringWithFormat:
@"insert into t_student (name, age, class_id) values('jack-%d', %d, %d);", i+1, i+10, i+1]; NSString *sql_class = [NSString stringWithFormat: @"insert into t_class (name) values('computer science-%d');", i+1];
}
//把class表中id为12的改为30,测试级联更新
sqlite3_exec(_db, "PRAGMA foreign_keys = ON", NULL, NULL, NULL);
NSString *sql_class = [NSString stringWithFormat:@"update t_class set id=%d where id=%d", 30, 12];
执行上面的代码,t_student表中class_id为12的也更新为30.
const char *sql =
"select s.id, s.name, s.age, c.name from (t_student s inner join t_class c on s.class_id = c.id) where s.name like ? and c.name like ? order by s.age desc;";
......//后面的步骤一样
如果学过SQL,那么在iOS中使用SQLite就不成问题了,唯一需要注意的是sql语句的编写,不要漏了逗号、分号或者括号,不要写错字母。
打开数据库并创表的步骤分为以下4步:
插入、更新、删除则只需要上面4步中的最后两步。
而查询操作则分为以下6步:
以上。