SQLite3的使用
2018-03-22 本文已影响29人
iChuck
SQLite3 的使用
一、什么是 SQLite
- SQLite 是一款轻型的嵌入式数据库,它占用的资源非常低,在嵌入式设备中可能只需要几百 K 的内存就足够了。它的处理速度比 MySQL、PostgreSQL 这两款数据库都还快。
二、数据存储数据的步骤
- 新建一个数据库
- 新建一张表(table)
- 添加多个字段(column,列,属性)
- 添加多行记录(row,每行存放多个对应的值)
三、SQL 语句种类
- 数据定义语句(DDL:Data Definition Language)
- 包括 create 和 drop 等操作
- 在数据库中创建表和删除表(create table 或 drop table)
- 数据操作语句(DML:Data Manipulation Language)
- 包括 inset、update、delete 等操作
- 数据查询语句(DQL:Data Query Language)
- 可以用来查询获得表中的数据
- select 用的最多的操作
- DQL 还有其他常用关键字 where、order by、group by、 having
四、SQLite 的字段类型
- integer:整型值
- real:浮点值
- text:文本字符串
- blob:二进制数据
- 实际上 SQLite 是无类型的,但为了保持良好的编程规范,方便程序员之间的交流,编写建表语句的时候最后还是加上每个字段的具体类型。
五、SQLite 的使用
- 在 iOS 中使用 SQLite3时,首先需要添加库文件 Libsqlite3.dylib 和导入头文件 #import <sqlite3.h>
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *sqlfile = [path stringByAppendingPathComponent:@"student.sqlite"];
int resutl = sqlite3_open(sqlfile.UTF8String, &_db);
if (resutl == SQLITE_OK) {
NSLog(@"打开成功!");
// 创建表
NSString *sql = @"CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT , name TEXT, age INTEGER, score REAL);";
/*
第一个参数: 需要执行SQL语句的数据库对象
第二个参数: 需要执行的SQL语句
第三个参数: 回调函数
第四个参数: 第三个参数的参数
第五个参数: 接收错误信息
*/
resutl = sqlite3_exec(_db, sql.UTF8String, NULL, NULL, NULL);
if (resutl == SQLITE_OK) {
NSLog(@"创建表成功!");
} else{
NSLog(@"创建表失败!");
}
} else {
NSLog(@"打开失败!");
}
- 插入数据
NSString *sql = @"INSERT INTO t_student(age, score, name) VALUES ('28', 100, 'jonathan');";
resutl = sqlite3_exec(_db, sql.UTF8String, NULL, NULL, NULL);
if (resutl == SQLITE_OK) {
NSLog(@"添加数据成功!");
}
- 修改数据
NSString *sql = @"UPDATE t_student SET name = 'LNJ';";
resutl = sqlite3_exec(_db, sql.UTF8String, NULL, NULL, NULL);
if (resutl == SQLITE_OK) {
NSLog(@"修改数据成功!");
}
- 删除数据
NSString *sql = @"DELETE FROM t_student WHERE id = 1; ";
resutl = sqlite3_exec(_db, sql.UTF8String, NULL, NULL, NULL);
if (resutl == SQLITE_OK) {
NSLog(@"删除数据成功!");
}
- 查询数据
- sqlite3操作中,所有 DML 语句都使用sqlite3_exec函数执行申请了语句即可,但是如果需要查询数据,不能使用sqlite3_exec,因为他没有返回给我们结果
NSString *sql = @"SELECT * FROM t_student;";
sqlite3_stmt *stemt = NULL;
/*
第一个参数:需要执行SQL语句的数据库
第二个参数:需要执行的SQL语句
第三个参数: 告诉系统SQL语句的长度, 如果传入一个小于0的数, 系统会自动计算
第四个参数:结果集, 里面存放所有查询到的数据(不严谨)
*/
sqlite3_prepare_v2(_db, sql.UTF8String, -1, &stemt, NULL);
// 判断有没有查询结果
while (sqlite3_step(stemt) == SQLITE_ROW) {
// 取出第一个字段的查询得结果
const unsigned char *name = sqlite3_column_text(stemt, 1);
// 取出第二个字段的查询得结果
int age = sqlite3_column_int(stemt, 2);
// 取出第三个字段的查询得结果
double score = sqlite3_column_double(stemt, 3);
NSLog(@"%s %d %f", name, age, score);
}
- 关闭数据库 close
Core Data
- 先创建 coreData 文件
- 在 coreData 里创建实体
- 直接可以从 xcode 里导出 model
- 创建NSPersistentContainer
@property (readonly, strong) NSPersistentContainer *persistentContainer;
- (void)saveContext;
// 实现
#pragma mark - Core Data stack
@synthesize persistentContainer = _persistentContainer;
- (NSPersistentContainer *)persistentContainer {
// The persistent container for the application. This implementation creates and returns a container, having loaded the store for the application to it.
@synchronized (self) {
if (_persistentContainer == nil) {
_persistentContainer = [[NSPersistentContainer alloc] initWithName:@"CoreData"];
[_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
if (error != nil) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
NSLog(@"Unresolved error %@, %@", error, error.userInfo);
abort();
}
}];
}
}
return _persistentContainer;
}
#pragma mark - Core Data Saving support
- (void)saveContext {
NSManagedObjectContext *context = self.persistentContainer.viewContext;
NSError *error = nil;
if ([context hasChanges] && ![context save:&error]) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(@"Unresolved error %@, %@", error, error.userInfo);
abort();
}
}
- 进行增删改查工作
appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
// 增加
Person *person = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:appDelegate.persistentContainer.viewContext];
person.name = [@"zhangsan" stringByAppendingString:@(arc4random_uniform(100)).stringValue];
person.age = arc4random_uniform(100);
person.sex = arc4random_uniform(100) / 2;
[appDelegate saveContext];
// 删除
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Person" inManagedObjectContext:appDelegate.persistentContainer.viewContext];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"age>50"];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setPredicate:predicate];
[request setEntity:entity];
NSArray *resultArray = [appDelegate.persistentContainer.viewContext executeFetchRequest:request error:nil];
NSLog(@"%@",resultArray);
if (resultArray.count > 0) {
for (Person *p in resultArray) {
[appDelegate.persistentContainer.viewContext deleteObject:p];
}
[appDelegate saveContext];
NSLog(@"删除实体完成");
} else {
NSLog(@"没有符合条件的结果");
}
// 修改
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Person" inManagedObjectContext:appDelegate.persistentContainer.viewContext];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"age<20"];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setPredicate:predicate];
[request setEntity:entity];
NSArray *resultArray = [appDelegate.persistentContainer.viewContext executeFetchRequest:request error:nil];
NSLog(@"%@",resultArray);
if (resultArray.count > 0) {
for (Person *p in resultArray) {
p.age += 10;
p.name = [p.name stringByAppendingString:@"lisi"];
}
[appDelegate saveContext];
NSLog(@"修改实体完成");
} else {
NSLog(@"没有符合条件的结果");
}
// 查询
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Person" inManagedObjectContext:appDelegate.persistentContainer.viewContext];
// NSPredicate *predicate = [NSPredicate predicateWithFormat:@"age>50"];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
// [request setPredicate:predicate];
[request setEntity:entity];
NSArray *resultArray = [appDelegate.persistentContainer.viewContext executeFetchRequest:request error:nil];
NSLog(@"%@",resultArray);
- 可以使用 NSPredicate 条件来筛选
- 每次操作完毕的时候都需要保存一下实体,确保数据库的数据为最新的
- 如果persistentContainer没有在 AppDelegate 根据项目一起创建,可以使用单利来实现,自定义persistentContainer。
FMDB 的使用
- fmdatabase 提供 SQLite 数据库的类,用于执行sql 语句
- fmresultset 用于查询数据
- fmdatabaequeue 在多线程下查询和更新数据库,避免线程阻塞
- 创建表
// 获取沙盒地址
NSString * path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
// 拼接路径
NSString * filePath = [path stringByAppendingPathComponent:@"person.sqlite"];
self.db = [FMDatabase databaseWithPath:filePath];
// 打开数据库创建表
if ([self.db open]) {
BOOL success = [self.db executeUpdate:@"create table if not exists t_person (id integer primary key autoincrement,name text not null,age integer,weight real default 120);"];
if (success) {
NSLog(@"创表成功");
}else{
NSLog(@"创表失败");
}
} else {
NSLog(@"打开失败");
}
- 插入数据直接使用DML 语句就可以了
// 在FMDB中可以用?当做占位符,但是:如果使用占位符,以后只能给占位符传递对象
BOOL success = [self.db executeUpdate:@"insert into t_person(name ,age,weight) values(?,?,?);",@"QLT",@"25",@"108"];
if (success) {
NSLog(@"插入成功");
}else{
NSLog(@"插入失败");
}
// 删除数据
BOOL success = [self.db executeUpdate:@"delete from t_person"];
if (success) {
NSLog(@"删除成功");
}else{
NSLog(@"删除失败");
}
// 更新数据
BOOL success = [self.db executeUpdate:@"update t_person set name = 'qlt' where weight = 108"];
if (success) {
NSLog(@"修改成功");
}else{
NSLog(@"修改失败");
}
- 查询数据,直接在executeQuery里执行 DQL 语句就可以了。
// FMResultSet结果集
FMResultSet * set = [self.db executeQuery:@"select id,name,age,weight from t_person;"];
if ([set next]) { // next 返回yes说明有数据
int ID = [set intForColumnIndex:0];
NSString * name = [set stringForColumnIndex:1];
double weight = [set doubleForColumnIndex:3];
NSLog(@"id = %d,name = %@,weight = %.1f",ID,name,weight);
}else{
NSLog(@"查询出错");
}
- FMDatabaseQueue 的基本用法
// 1.创建一个FMDatabaseQueue对象
// 只要创建数据库队列对象, FMDB内部就会自动给我们加载数据库对象
self.queue = [FMDatabaseQueue databaseQueueWithPath:filePath];
// 2 .执行操作
// 会通过block传递队列中创建好的数据库给我们
[self.queue inDatabase:^(FMDatabase *db) {
// 编写需要执行的代码
BOOL success = [db executeUpdate:@"CREATE TABLE IF NOT EXISTS t_student (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, score REAL DEFAULT 1);"];
if (success) {
NSLog(@"创建表成功");
}else
{
NSLog(@"创建表失败");
}
}];
// update
[self.queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
[db executeUpdate:@"UPDATE t_person SET weight = 1500 WHERE name = 'zs';"];
NSArray *array = @[@"abc"];
array[1];
[db executeUpdate:@"UPDATE t_person SET weight = 500 WHERE name = 'ls';"];
}];
// select
[self.queue inDatabase:^(FMDatabase *db) {
// FMResultSet结果集, 结果集其实和tablevivew很像
FMResultSet *set = [db executeQuery:@"SELECT id, name, score FROM t_student;"];
while ([set next]) { // next方法返回yes代表有数据可取
int ID = [set intForColumnIndex:0];
// NSString *name = [set stringForColumnIndex:1];
NSString *name = [set stringForColumn:@"name"]; // 根据字段名称取出对应的值
double score = [set doubleForColumnIndex:2];
NSLog(@"%d %@ %.1f", ID, name, score);
}
}];