微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

5.SQLite面相对象通用封装

1.由来

在学习sqlite的时候,发现OC中提供的API是面向过程的方式,如果在开发中用到,那么每次都会重复的去走这个流程,打开数据库,执行sql,细节上的处理等。于是就在sqlite3的基础上,进行了通用封装,在以后的开发中直接使用即可,提高开发效率。
代码托管:https://github.com/zhangint/OCSQLite/tree/master

2.注意

该封装只是针对通用的接口和使用方式,使用起来也比较简单,sql语句,数据类型,数据值即可。
1.认表的第一列为主键,创建表的时候需要注意。
2.如若有什么特殊功能或者细节控制,则该接口并不适用。
3.并不提供线程安全保证,需要用户自己进行控制。

3.运行效果接口说明

查询效果

插入效果:

接口说明:
为了满足多行多列数据的插入和查询,采用了二位数组的方式,当某一列的数据值为空时,需填充[NSNull null];
直接贴头文件内容吧,描述的也很清晰
内部定义数据说明

//sqlite支持的5种数据类型
typedef NS_ENUM(NSInteger,DataType)
{
    DTNULL = 0,//NULL
    DTINT,//整数
    DTREAL,//浮点数
    DTTEXT,//文本数据
    DTBLOB          //二进制数据
};

文件接口

//@brief:打开数据库文件
//@param:dbFile 数据库文件路径
//@return: 0 成功 其它 失败的错误
- (NSInteger)openDB:(Nsstring *)dbFile;

//@brief:关闭数据库连接
//@return: YES 成功 NO 失败
- (NSInteger)closeDB;

//@breif: sql命令,返回执行状态
//@return: 0 成功
// 其它 错误
//@attention: 主要执行查询,状态获取
- (NSInteger)execsql:(Nsstring *)sql;

//@brief: 执行SQL查询语句
//@param: dataType 指定查询返回的数据类型(注意需为DataType的枚举值
//@return: 返回为双重数组,第一层为一行数据封装,第二层为列数据封装

- (NSArray<NSArray *> *)sqlQuery:(Nsstring *)sql
                                    dataType:(NSArray<NSNumber *> *)dataType;

//@brief: 数据插入
//@param: sql 插入的sql语句
// data 绑定的值,而为数组形式,先封装一行数据,然后再封装
// datatype 每一列数据的值
//@return: >=0 影响的行数
// -1 失败
//@attention: 内部不检测值和类型是否匹配,需用户自己校验
- (NSInteger)sqlInsert:(Nsstring*)sql data:(NSArray<NSArray *> *)data datatype:(NSArray *)datatype;

//@brief: 根据错误码,返回错误描述信息
- (Nsstring *)lastError:(NSInteger)errcode;

4.测试用例

1.多行数据插入

- (void)insertClicked:(id)sender
{
    //在插入数据的时候,先创建表
    Nsstring *sql = @"create table if not exists test_table_1 \ (id integer primary key autoincrement,\ name,\ passwd,\ address,\ age,\ photo,\ rank)";

    NSLog(@"create table status:%ld",[_dbcon execsql:sql]);

    //构造一行的数据
    NSMutableArray *rowData_1 = [[NSMutableArray alloc] init];
    [rowData_1 addobject:@"zhangint"];
    [rowData_1 addobject:@"123456"];
    [rowData_1 addobject:@"chengdu"];
    [rowData_1 addobject:[NSNumber numberWithInt:25]];
    Nsstring *pic1 = [[NSBundle mainBundle] pathForResource:@"zhangint" ofType:nil];
    NSData *pic1_data = [NSData dataWithContentsOfFile:pic1];
    unsigned char* msg = (unsigned  char*)[pic1_data bytes];
    [rowData_1 addobject:pic1_data];  //二进制
    [rowData_1 addobject:[NSNumber numberWithFloat:2.3]];               //浮点数

    NSMutableArray *rowData_2 = [[NSMutableArray alloc] init];
    [rowData_2 addobject:@"love dog"];
    [rowData_2 addobject:@"56789"];
    [rowData_2 addobject:[NSNull null]];                                //string为空
    [rowData_2 addobject:[NSNumber numberWithInt:33]];
    Nsstring *pic2 = [[NSBundle mainBundle] pathForResource:@"xiaoyu" ofType:nil];
    NSData *pic2_data = [NSData dataWithContentsOfFile:pic2];
    [rowData_2 addobject:pic2_data];
    [rowData_2 addobject:[NSNumber numberWithFloat:3.3]];

    NSMutableArray *rowData_3 = [[NSMutableArray alloc] init];
    [rowData_3 addobject:@"xiaoxiaoxiao"];
    [rowData_3 addobject:@"9990"];
    [rowData_3 addobject:@"beijing"];
    [rowData_3 addobject:[NSNumber numberWithInt:32]];
    [rowData_3 addobject:[NSNull null]];                                //二进制位空
    [rowData_3 addobject:[NSNumber numberWithFloat:5.4]];

    //数据值的初始化
    NSArray *tableArr = [[NSArray alloc] initWithObjects:rowData_1,rowData_2,rowData_3,nil];
    //数据类型的初始化
    NSArray *dataType = [[NSArray alloc] initWithObjects:[NSNumber numberWithInt:DTTEXT],[NSNumber numberWithInt:DTTEXT],[NSNumber numberWithInt:DTINT],[NSNumber numberWithInt:DTBLOB],[NSNumber numberWithInt:DTREAL],nil];
    Nsstring *insertsql = @"insert into test_table_1 values(null,?,?)";

    NSLog(@"insert res:%ld",[_dbcon sqlInsert:insertsql data:tableArr datatype:dataType]);

2.数据查询

- (void) searchClicked:(id)sender
{
    Nsstring *sql = @"select * from test_table_1";
    NSArray *dataType = [[NSArray alloc] initWithObjects:[NSNumber numberWithBool:DTINT],nil];

    NSArray<NSArray *> *searchRes;
    searchRes = [_dbcon sqlQuery:sql dataType:dataType];
    NSInteger rows = [searchRes count];
    NSLog(@"search rows:%ld",rows);
    for (int i=0; i<rows; i++)
    {
        NSArray *rowData = searchRes[i];
        NSNumber *idnum = rowData[0];
        Nsstring *name = rowData[1];
        Nsstring *passed = rowData[2];
        Nsstring *address = rowData[3];
        NSNumber *age = rowData[4];
        //NSData *img = rowData[5];
        NSNumber *rank = rowData[6];
        NSLog(@"id:%d name:%@ passwd:%@ address:%@ age:%d photo not show rank:%.1f",idnum.intValue,name,passed,address,age.intValue,rank.floatValue);
    }
    _searchRes = searchRes;

5.源代码

文件sqliteInter.h

//
// sqliteInter.h
// sqlitePro
//
// Created by zp on 15/12/26.
// copyright © 2015年 ZP. All rights reserved.
//

//@brief: sqlite通用接口封装
//@attention: 1.本身并不提供线程安全,用户可以通过Serial dispatch Queue的方式,保证安全可靠访问
// 2.只是对通用的使用方式进行了封装,很多细节或者特殊的使用方式并未覆盖


#import <Foundation/Foundation.h>
#import <sqlite3.h>

//sqlite支持的5种数据类型
typedef NS_ENUM(NSInteger,//文本数据
    DTBLOB          //二进制数据
};

@interface sqliteInter : NSObject

//错误
@property (assign,nonatomic) NSInteger lastErrCode;

//@brief:打开数据库文件
//@param:dbFile 数据库文件路径
//@return: 0 成功 其它 失败的错误
- (NSInteger)openDB:(Nsstring *)dbFile;

//@brief:关闭数据库连接
//@return: YES 成功 NO 失败
- (NSInteger)closeDB;

//@breif: sql命令,返回执行状态
//@return: 0 成功
// 其它 错误
//@attention: 主要执行查询,状态获取
- (NSInteger)execsql:(Nsstring *)sql;

//@brief: 执行SQL查询语句
//@param: dataType 指定查询返回的数据类型(注意需为DataType的枚举值
//@return: 返回为双重数组,第一层为一行数据封装,第二层为列数据封装

- (NSArray<NSArray *> *)sqlQuery:(Nsstring *)sql
                                    dataType:(NSArray<NSNumber *> *)dataType;

//@brief: 数据插入
//@param: sql 插入的sql语句
// data 绑定的值,而为数组形式,先封装一行数据,然后再封装
// datatype 每一列数据的值
//@return: >=0 影响的行数
// -1 失败
//@attention: 内部不检测值和类型是否匹配,需用户自己校验
- (NSInteger)sqlInsert:(Nsstring*)sql data:(NSArray<NSArray *> *)data datatype:(NSArray *)datatype;

//@brief: 根据错误码,返回错误描述信息
- (Nsstring *)lastError:(NSInteger)errcode;

@end

实现文件
sqliteInter.m

//
// sqliteInter.m
// sqlitePro
//
// Created by zp on 15/12/26.
// copyright © 2015年 ZP. All rights reserved.
//

/**@brief:sqlite数据接口封装,方便复用 * * */

#import "sqliteInter.h"

@interface sqliteInter ()

//注意:sqlite3 为struct类型,不能用strong属性
@property (assign,nonatomic) sqlite3 *database;

@property (assign,nonatomic) sqlite3_stmt *stmt;

@end


@implementation sqliteInter

- (NSInteger)openDB:(Nsstring *)dbFile
{

    //如果数据库已经打开,则先关闭
    if (_database)
    {
        _lastErrCode = [self closeDB];
        if (_lastErrCode != sqlITE_OK)
        {
            _lastErrCode = 0;
            return 0;
        }
    }

    _lastErrCode = sqlite3_open([dbFile UTF8String],&_database);
    return _lastErrCode;
}

- (NSInteger)closeDB
{
    if (_database)
    {
        NSInteger num = 0;
        //会关闭2次,2次失败,则失败
        while (num < 2)
        {
            _lastErrCode = sqlite3_close(_database);
            //关闭成功
            if (sqlITE_OK == _lastErrCode)
            {
                _database = nil;
                break;
            }
            sqlite3_finalize(_stmt);
            num++;
        }
    }
    return _lastErrCode;
}

- (NSInteger)execsql:(Nsstring *)sql
{
    //这个地方并不校验 _database == nil,errorcode 会有描述

    _lastErrCode = sqlite3_exec(_database,[sql UTF8String],NULL,NULL);
    //返回错误
    return _lastErrCode;
}

- (NSArray<NSArray *> *)sqlQuery:(Nsstring *)sql
                                    dataType:(NSArray<NSNumber *> *)dataType
{
    NSMutableArray *dataSet = [[NSMutableArray alloc] init];
    NSInteger preRes = sqlite3_prepare_v2(_database,-1,&_stmt,nil);
    if (preRes == sqlITE_OK)
    {
        while (sqlite3_step(_stmt) == sqlITE_ROW)
        {
            NSMutableArray *dataArr = [[NSMutableArray alloc] init];
            int colNum = sqlite3_data_count(_stmt);
            //获取列的数量
            for (int i=0; i<colNum; i++)
            {
                [dataArr addobject:[self get_col_data:dataType[i].intValue statement:_stmt col:i]];
            }
            [dataSet addobject:dataArr];
        }
    }
    sqlite3_finalize(_stmt);
    return dataSet;
}

- (id) get_col_data:(DataType)dbtype statement:(sqlite3_stmt *)stmt col:(NSInteger)col
{
    switch (dbtype) {
        case DTNULL:
            return [NSNull null];
            break;
        case DTINT:{
            //(int)col 强制转化,避免警告
            NSNumber *number = [NSNumber numberWithInt:sqlite3_column_int(stmt,(int)col)];
            return number;
            break;
            }
        case DTREAL:{
            NSNumber *number = [NSNumber numberWithFloat:sqlite3_column_double(stmt,(int)col)];
            return number;
            }
        case DTTEXT:{
            Nsstring *cellData;
            char* str = (char*)(char*)sqlite3_column_text(stmt,(int)col);
            if (str != NULL)
            {
                cellData = [Nsstring stringWithFormat:@"%s",str];
            }
            else
            {
                //当为空的时候,为一个空对象
                cellData = @"";
            }
            return cellData;
        }
        //二进制的处理
        case DTBLOB:{
            NSInteger len = sqlite3_column_bytes(stmt,(int)col);
            NSData *cellData = [[NSData alloc] initWithBytes:sqlite3_column_blob(stmt,(int)col) length:len];
            return cellData;
        }
        default:
            break;
    }
    return  [NSNull null];
}

- (NSInteger)sqlInsert:(Nsstring*)sql data:(NSArray<NSArray *> *)data datatype:(NSArray *)datatype
{
    NSInteger effectNum = 0;
    int preStatus = sqlite3_prepare_v2(_database,NULL);
    if (preStatus == sqlITE_OK)
    {
        for (int i=0; i<data.count; i++)
        {
            NSArray *rowData = data[i];
            for (int col=0; col<rowData.count; coL++)
            {
                NSNumber *type = datatype[col];
                switch (type.intValue) {
                    case DTNULL:
                        sqlite3_bind_null(_stmt,col+1);
                        break;
                    case DTINT:{
                        NSNumber *number = rowData[col];
                        sqlite3_bind_int(_stmt,col+1,number.intValue);
                        break;
                    }
                    case DTREAL:{
                        NSNumber *real = rowData[col];
                        sqlite3_bind_double(_stmt,real.floatValue);
                        break;
                    }
                    case DTTEXT:{
                        Nsstring *str;
                        if (rowData[col] == [NSNull null])
                        {
                            str = @"";
                        }
                        else
                        {
                            str = rowData[col];
                        }
                        sqlite3_bind_text(_stmt,[str UTF8String],NULL);
                        break;
                    }
                    case DTBLOB:{
                        NSData *msg;
                        if (rowData[col] == [NSNull null])
                        {
                            msg = [[NSData alloc] initWithBytes:@"" length:1];
                        }
                        else
                        {
                            msg = rowData[col];
                        }
                        sqlite3_bind_blob(_stmt,[msg bytes],(int)[msg length],NULL);
                        break;
                    }
                    default:
                        break;
                } /*switch */
            } //for
            if (sqlite3_step(_stmt) == sqlITE_DONE)
            {
                effectNum++;
            }
            //需要重置statement
            sqlite3_reset(_stmt);
        } /*for*/
    } /*if*/

    sqlite3_finalize(_stmt);
    return effectNum;
    //这种用法不对
    //return sqlite3_changes(_database);
}

- (Nsstring *)lastError:(NSInteger)errcode
{
    return [Nsstring stringWithUTF8String:sqlite3_errstr((int)errcode)];
}
@end

原文地址:https://www.jb51.cc/sqlite/199137.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐