数据持久化之数据库

数据持久化之数据库
数据库是数据持久化最重要的方式,也是开发中最常用的方式。
数据库的最大特点就是增、删、改、查,便于复杂数据的统一管理以及灵活使用。
需要导入库sqlite3.dylib。
数据库的本质是一个文件,存储于硬盘之上。



数据库流程:
1.引入库sqlite3.0.dylib
2.使用sqlite3.0dylib类对数据库进行操作
3.使用sqlite3_stmt类以及SQL语句进行数据的操作


优点:解决了归档查找数据困难的问题
缺点:需要对SQL语句比较了解


1.数据库的打开或者关闭
sqlite3_open()打开数据库的函数,返回值为整型,指打开操作的结果,若结果等于SQLITE_OK这个常量,则说明成功打开数据库。若打开失败则会返回相应的错误信息。
int sqlite3_open(const char*, sqlite3**);
int sqlite3_close(sqlite3*);
sqlite3_open() 的第一个参数为数据库文件名,第二个参数的类型sqlite3为一个结构体,它用于保存建立的数据库连接。当执行成功时,这两个均返回 SQLITE_OK, 失败则返回错误代码,可调用sqlite3_errmsg()或者sqlite3_errmsg16()给出错误描述。


2.预编译
sqlite3_prepare()要执行sql语句,必须先把它编译成字节码。
int sqlite3_prepare_v2(
  sqlite3 *db,
  const char *zSql,
  int nByte,
  sqlite3_stmt **ppStmt,
  const char **pzTail
);此函数需要一个数据库连接的指针,将给定的SQL文本转换为预声明语句对象并返回一个指向它的指针,这个函数并不执行SQL语句。SQL语句中可以带有“?”,它代表不确定的值,当需要对这些“?”赋值时,可以使用sqlite3_bind_*()函数族:
1.int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
int sqlite3_bind_double(sqlite3_stmt*, int, double);
int sqlite3_bind_int(sqlite3_stmt*, int, int);
int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
int sqlite3_bind_null(sqlite3_stmt*, int);
int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*));
int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);


3.执行sql语句
 这 一例程的功能是执行sqlite3_prepare()例程处理过的SQL语句,当返回的结果的第一行可以被获取时,这一例程将会返回,若要获得下一行的 结果,可再此调用这一例程,若执行的是无返回结果的SQL语句(例如INSERT),该例程将在一此调用中完成并返回。
    当SQL语句执行成功时,此例程将返回SQLITE_DONE,当SQL语句执行成功且SQL返回一个单行结果集,此例程返回SQLITE_ROW,否则将返回错误代码,比如,如果不能打开数据库文件则会返回SQLITE_BUSY。
当返回值为SQLITE_ROW时,如需要对返回结果进行处理时,可以使用sqlite3_column_*()函数族:
const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
double sqlite3_column_double(sqlite3_stmt*, int iCol);
int sqlite3_column_int(sqlite3_stmt*, int iCol);
sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
int sqlite3_column_type(sqlite3_stmt*, int iCol);
sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
其中参数 iCol为列的序号,从0开始。


4.sqlite3_column()
对 于SELECT语句,在使用上去sqlite3_step运行之后,需要将结果读出来。其实sqlit3_column()是一系列函数的总称,他们共同 的作用是从当前的结果按列号取出值。比如一个SELCET语句运行完之后,其中一条结果为1“张三”“男”。这个结果就包含三列,那么就可以利用该函数, 找到某一特定列的值,根据值类型的不同,需要调用不同的函数,比如针对第一列,类型为整数,就调用sqlite3_column_int(stmt,0) 来返回第一列的值;而在第二列的数据类型是文本text,调用sqlit3_column_text(stmt,0)得到第二列的文本信息。
还有其他版本:
*sqlite3_column_blob()
  *sqlite3_column_bytes()
  *sqlite3_column_bytes16()
  *sqlite3_column_count()
  *sqlite3_column_double()
  *sqlite3_column_int()
  *sqlite3_column_int64()
  *sqlite3_column_text()
  *sqlite3_column_text16()
  *sqlite3_column_type()
  *sqlite3_column_value()


5.销毁预编译的SQL语句
int sqlite3_finalize(sqlite3_stmt *pStmt);
    sqlite3_finalize 和sqlite3_prepare 是相对的,当使用sqlite3_prepare 编译的SQL在使用完后,应该使用sqlite3_finalize 语句来释放掉它。
    如果要多次使用处理过的SQL语句,且要更换里面绑定的参数,可以使用
int sqlite3_reset(sqlite3_stmt *pStmt);
来清除处理过的SQL语句里面绑定的所有参数,然后调用sqlite3_bind_*()函数族重新绑定参数即可。

6.sqlite3_exec()
为执行sql语句提供一种便捷的方法,只需要将sql语句的字符串(char *)传递给该函数即可,我们指定回调函数来处理执行后的返回值。不过,一般情况下,sqlie3_exec()函数多用于运行任何不返回数据的命令。它用于执行更新、插入、删除操作。



其他常用的还有:
sqlit3_column_count()统计列数
sqlit3_data_count()返回当前记录的列数
sqlit3_get_table()获取被查询的表的内容
sqlite3_srrmsg()返回错误信息
sqlite3_free()释放动态构造的sqlite语句
sqlite3_reset()重载sqlite语句


不太常用的API
sqlite3_column_database_name()获取数据库名
sqlite3_column_table_name()获取表名
sqlite3_origin_name()获取源名(索引名)
sqlite3_table_column_metadata()获取一列的详细信息(表名,建表类型)





//添加一个对象
+ (BOOL)addName:(NSString *)name phone:(NSString *)phone age:(int)age
{
    sqlite3 *db = [DataBase openDB];//打开数据库
    sqlite3_stmt *stmt = nil;
    BOOL success = NO;//默认添加失败
    int result = sqlite3_prepare_v2(db, "insert into classA(name,phone,age) values(?,?,?)", -1, &stmt, nil);//准备SQL语句
    if(SQLITE_OK == result)//语句无误
    {
        sqlite3_bind_text(stmt, 1, [name UTF8String], -1, nil);
        sqlite3_bind_text(stmt, 2, [phone UTF8String], -1, nil);
        sqlite3_bind_int(stmt, 3, age);
        if(SQLITE_DONE == sqlite3_step(stmt))
        {
            success = YES;//添加成功
        }
    }
    sqlite3_finalize(stmt);
    return success;
}




//根据ID删除对象
+ (BOOL)deleteByID:(int)ID
{
    sqlite3 *db = [DataBase openDB];
    sqlite3_stmt *stmt= nil;
    BOOL success = NO;//默认删除失败
    int result  = sqlite3_prepare_v2(db, "delete from classA where ID = ?", -1, &stmt, nil);
    if(SQLITE_OK == result)
    {
        sqlite3_bind_int(stmt, 1, ID);
        if(SQLITE_DONE == sqlite3_step(stmt))
        {
            success = YES;
        }
    }
    sqlite3_finalize(stmt);
    return success;
}




//更新
+ (BOOL)updateName:(NSString *)name phone:(NSString *)phone age:(int)age whereIDEqual:(int)ID
{
    sqlite3 *db = [DataBase openDB];//打开数据库
    sqlite3_stmt *stmt = nil;
   
    BOOL success = NO;//默认更新失败
   
    int result = sqlite3_prepare_v2(db, "update classA set name = ?,phone = ?,age = ? where ID = ?", -1, &stmt, nil);//准备SQL语句
    if(result == SQLITE_OK)//语句无误
    {
        sqlite3_bind_text(stmt, 1, [name UTF8String], -1, nil);//1表示第一个?
        sqlite3_bind_text(stmt, 2, [phone UTF8String], -1, nil);//2表示第二个?
        sqlite3_bind_int(stmt, 3, age);
        sqlite3_bind_int(stmt, 4, ID);
        if(sqlite3_step(stmt) == SQLITE_DONE)
        {
            success = YES;//更新成功
        }
    }
    sqlite3_finalize(stmt);
    return success;
}



//信息条数
+ (int)count
{
    sqlite3 *db = [DataBase openDB];//打开数据库
    sqlite3_stmt *stmt = nil;
    int result  = sqlite3_prepare_v2(db, "select count(*) from classA", -1, &stmt, nil);//准备SQL语句
    if(result == SQLITE_OK)//语句无误
    {
        if(SQLITE_ROW == sqlite3_step(stmt))
        {
            int count = sqlite3_column_int(stmt, 0);
            sqlite3_finalize(stmt);
            return count;
        }
    }
    sqlite3_finalize(stmt);
    return 0;
}



//根据ID找对象
+ (Person *)findByID:(int)ID
{
    sqlite3 *db = [DataBase openDB];//打开数据库
    sqlite3_stmt *stmt = nil;
   
    int result = sqlite3_prepare_v2(db, "select * from classA where ID = ?", -1, &stmt, nil);//准备SQL语句
    if(result == SQLITE_OK)//语句无误
    {
        sqlite3_bind_int(stmt, 1, ID);//替换"?",1表示第一个?
        if(SQLITE_ROW == sqlite3_step(stmt))//单步执行
        {
            const unsigned char *name = sqlite3_column_text(stmt, 1);
            const unsigned char *phone = sqlite3_column_text(stmt, 2);
            int age = sqlite3_column_int(stmt, 3);
            Person *p = [[Person alloc] initWithID:ID name:[NSString stringWithUTF8String:(char *)name] phone:[NSString stringWithUTF8String:(char *)phone] age:age];
            sqlite3_finalize(stmt);//释放stmt对象
            return [p autorelease];
        }
    }
    sqlite3_finalize(stmt);
    return nil;
}




//找到所有对象
+ (NSMutableArray *)findAll
{
    sqlite3 *db = [DataBase openDB];//打开数据库
    sqlite3_stmt *stmt = nil;//陈述,是一个可以执行SQL语句的对象
    int result = sqlite3_prepare_v2(db, "select * from classA", -1, &stmt, nil);//准备SQL语句
    if(result == SQLITE_OK)
    {
        NSMutableArray *allObject = [[NSMutableArray alloc] init];
        while (SQLITE_ROW == sqlite3_step(stmt))//单步执行SQL语句
        {
            int ID = sqlite3_column_int(stmt, 0);//select结果集的第一列(第一个字段)
            const unsigned char *name = sqlite3_column_text(stmt, 1);//select结果集的第二列(第二个字段)
            const unsigned char *phone = sqlite3_column_text(stmt, 2);//select结果集的第三列(第三个字段)
            int age = sqlite3_column_int(stmt, 3);
            Person *p = [[Person alloc] initWithID:ID name:[NSString stringWithUTF8String:(char *)name] phone:[NSString stringWithUTF8String:(char *)phone] age:age];
            [allObject addObject:p];
            [p release];
        }
        sqlite3_finalize(stmt);//释放stmt对象
        return [allObject autorelease];
    }
    sqlite3_finalize(stmt);
    return nil;
}







以下是打开和关闭
static sqlite3 *dbPoint = nil;

+ (sqlite3 *)openDB
{
    if(dbPoint)
    {
        return dbPoint;
    }
    //目标路径
    NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0];
    NSString *sqlFilePath = [docPath stringByAppendingPathComponent:@"StudentDB.sqlite"];

    //原始路径
    NSString *orignFilePath = [[NSBundle mainBundle] pathForResource:@"StudentDB" ofType:@"sqlite"];
   
    NSLog(@"%@\n%@",sqlFilePath,orignFilePath);
    NSFileManager *fm = [NSFileManager defaultManager];
    if([fm fileExistsAtPath:sqlFilePath] == NO)//如果doc下没有数据库,从bundle里面拷贝过来
    {
        NSError *err = nil;
        if([fm copyItemAtPath:orignFilePath toPath:sqlFilePath error:&err] == NO)//如果拷贝失败
        {
            NSLog(@"open database error %@",[err localizedDescription]);
            return nil;
        }
    }
    NSLog(@"open DB at path:%@",sqlFilePath);
    sqlite3_open([sqlFilePath UTF8String], &dbPoint);
    return dbPoint;
}


+ (void)closeDB
{
    if(dbPoint)
    {
        sqlite3_close(dbPoint);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值