• SQLite


    由于在iPhone3.0上已经支持了Core Data,是苹果一个新的API,并且是基于SQlite的。速度也是非常快吧。所以我们对SQLite仅需要懂一些即可,以下是一些基础信息


    一、:常用接口(2个重要结构体和5个主要函数)
    sqlite3               *pdb, 数据库句柄,跟文件句柄 FILE 很类似
    sqlite3_stmt      *stmt, 这个相当于 ODBC 的 Command 对象,用于保存编译好的 SQL 语句


    sqlite3_open(),   打开数据库
    sqlite3_exec(),   执行非查询的 sql 语句
    sqlite3_prepare(), 准备 sql 语句,执行 select 语句或者要使用 parameter bind 时,用这个函数(封装了 sqlite3_exec ) .
    Sqlite3_step(), 在调用 sqlite3_prepare 后,使用这个函数在记录集中移动。
    Sqlite3_close(), 关闭数据库文件
     
    还有一系列的函数,用于从记录集字段中获取数据,如
    sqlite3_column_text(), 取 text 类型的数据。
    sqlite3_column_blob (),取 blob 类型的数据
    sqlite3_column_int(), 取 int 类型的数据


    其他工具函数
    1. 得到结果总共的行数
    int sqlite3_data_count(sqlite3_stmt *pStmt);
    如果过程没有返回值,如update,将返回0
    2. 得到当前行中包含的数据个数
    int sqlite3_column_count(sqlite3_stmt *pStmt);
    如果sqlite3_step返回SQLITE_ROW,可以得到列数,否则为零。
    3. 得到数据行中某个列的数据
    sqlite3_column_xxx(sqlite3_stmt*, int iCol);
    在sqlite3_step返回SQLITE_ROW后,使用它得到第iCol列的数据。
    其中的xxx代表:
    blob:指向保存数据内存的指针
    bytes, bytes16: 得到该blob类型数据的大小,或者text转换为UTF8/UTF16的字符串长度。
    double, int, int64: 数值
    text,text16:字符串指针
    type:该列的数据类型(SQLITE_INTEGER,SQLITE_FLOAT,SQLITE_TEXT,SQLITE_BLOB,SQLITE_NULL)
    注意:如果对该列使用了不同与该列本身类型适合的数据读取方法,得到的数值将是转换过的结果。
    4. 得到数据行中某个列的数据的类型
    int sqlite3_column_type(sqlite3_stmt*, int iCol);
    返回值:SQLITE_INTEGER,SQLITE_FLOAT,SQLITE_TEXT,SQLITE_BLOB,SQLITE_NULL
    使用的方法和sqlite3_column_xxx()函数类似。


    二、:sqlite数据类型介绍
         在进行数据库Sql操作之前,首先有个问题需要说明,就是Sqlite的数据类型,和其他的数据库不同,Sqlite支持的数据类型有他自己的特色,这个特色有时会被认为是一个潜在的缺点,但是这个问题并不在我们的讨论范围之内。
    大多数的数据库在数据类型上都有严格的限制,在建立表的时候,每一列都必须制定一个数据类型,只有符合该数据类型的数据可以被保存在这一列当中。而在 Sqlite 2.X中,数据类型这个属性只属于数据本生,而不和数据被存在哪一列有关,也就是说数据的类型并不受数据列限制(有一个例外:INTEGER PRIMARY KEY,该列只能存整型数据)。
    但是当Sqlite进入到3.0版本的时候,这个问题似乎又有了新的答案,Sqlite的开发者开始限制这种无类型的使用,在3.0版本当中,每一列开始 拥有自己的类型,并且在数据存入该列的时候,数据库会试图把数据的类型向该类型转换,然后以转换之后的类型存储。当然,如果转换被认为是不可行 的,Sqlite仍然会存储这个数据,就像他的前任版本一样。
    举个例子,如果你企图向一个INTEGER类型的列中插入一个字符串,Sqlite会检查这个字符串是否有整型数据的特征, 如果有而且可以被数据库所识别,那么该字符串会被转换成整型再保存,如果不行,则还是作为整型存储。


    总的来说,所有存在Sqlite 3.0版本当中的数据都拥有以下之一的数据类型:
    空(NULL):该值为空
    整型(INTEGEER):有符号整数,按大小被存储成1,2,3,4,6或8字节。
    实数(REAL):浮点数,以8字节指数形式存储。
    文本(TEXT):字符串,以数据库编码方式存储(UTF-8, UTF-16BE 或者 UTF-16-LE)。
    BLOB:BLOB数据不做任何转换,以输入形式存储。


    ps: 在关系数据库中,CLOB和BLOB类型被用来存放大对象。BOLB表示二进制大对象,这种数据类型通过用来保存图片,图象,视频等。CLOB表示字符大对象,能够存放大量基于字符的数据。


    对应的,对于数据列,同样有以下的数据类型:
    TEXT
    NUMERIC
    INTEGER
    REAL
    NONE
    数据列的属性的作用是确定对插入的数据的转换方向:
    TEXT 将数据向文本进行转换,对应的数据类型为NULL,TEXT 或 BLOB
    NUMERIC 将数据向数字进行转换,对应的数据类型可能为所有的五类数据,当试图存入文本 时将执行向整型或浮点类型的转换(视具体的数值而定),转换若不可行,则保留文本类型存储,NULL或BLOB不做变化
    INTEGER 将数据向整型转换,类似于NUMERIC,不同的是没有浮点标志的浮点数将转换为整型保存
    REAL 将数据向浮点数类型转换,类似于NUMERIC,不同的是整数将转换为浮点数保存
    NULL 不做任何转换的数据列类型

    内部类型

    请求的类型

    转换

    NULL

    INTEGER

    结果是0

    NULL

    FLOAT

    结果是0.0

    NULL

    TEXT

    结果是NULL

    NULL

    BLOB

    结果是NULL

    INTEGER

    FLOAT

    从整形转换到浮点型

    INTEGER

    TEXT

    整形的ASCII码显示

    INTEGER

    BLOB

    同上

    FLOAT

    INTEGER

    浮点型转换到整形

    FLOAT

    TEXT

    浮点型的ASCII显示

    FLOAT

    BLOB

    同上

    TEXT

    INTEGER

    使用atoi()

    TEXT

    FLOAT

    使用atof()

    TEXT

    BLOB

    没有转换

    BLOB

    INTEGER

    先到TEXT,然后使用atoi

    BLOB

    FLOAT

    先到TEXT,然后使用atof

    BLOB

    TEXT

    如果需要的话添加0终止符



    在iPhone中使用Sqlite 3主要步骤如下:
    1 首先获取iPhone上Sqlite 3的数据库文件的地址
    2 打开Sqlite 3的数据库文件
    3 定义SQL文
    4 邦定执行SQL所需要的参数
    5 执行SQL文,并获取结果
    6 释放资源
    7 关闭Sqlite 3数据库。
    // 首先获取iPhone上Sqlite3的数据库文件的地址  


    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);  
    NSString *documentsDirectory = [paths objectAtIndex:0];  
    NSString *path = [documentsDirectory stringByAppendingPathComponent:@"database_name"];  
    // 打开Sqlite3的数据库文件  
    sqlite3 *database;  
    sqlite3_open([path UTF8String], &database);  
    // 定义SQL文  
    sqlite3_stmt *stmt;  
    const char *sql = "SELECT * FROM table_name WHERE pk=? and name=?";  
    sqlite3_prepare_v2(database, sql, -1, &stmt, NULL);  
    // 邦定第一个int参数  
    sqlite3_bind_int(stmt, 1, 1);  
    // 邦定第二个字符串参数  
    sqlite3_bind_text(stmt, 2, [title UTF8String], -1, SQLITE_TRANSIENT);  
    // 执行SQL文,并获取结果  
    sqlite3_step(stmt);  
    // 释放资源  
    sqlite3_finalize(stmt);  
    // 关闭Sqlite3数据库  
    sqlite3_close(database); 


    三、objective-c 与 Sqlite
    1、SQLite的开发包
    注意:要在工程中的Frameworks中导入相应的libsqlite3.dylib文件,也许在相应的目录下存在多个以libsqlite3开头的文件,务必选择libsqlite3.dylib,它始终指向最新版的SQLite3库的别名。 
    libsqlite3.0.dylib文件地址:
    /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk/usr/lib/libsqlite3.dylib
    2、创建数据库
    //数据库的位置
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];


    //打开数据库 如果没有则会创建一个新的数据库
    sqlite3 *sql;
    if(sqlite3_open([[documentsDirectory stringByAppendingPathComponent:@"data.sqlite3"] UTF8String],&sql)!=SQLITE_OK) //data.sqlite3为自己定义数据库名称  
    {
    NSLog(@"创建数据库失败!");
    return;
    }
    3、创建数据表
    //创建一个新表 如果没有则会创一个新表
    char *errorMsg;
    NSString *createSQL = @"CREATE TABLE IF NOT EXISTS FIELDS (ROW INTEGER PRIMARY KEY, FIELD_DATA TEXT);";
    if (sqlite3_exec (sql, [createSQL UTF8String],NULL, NULL, &errorMsg) != SQLITE_OK)
    {
    sqlite3_close(sql);
    NSLog(@"创建数据表失败:%s",errorMsg);
    }
    4、插入更改数据
    for (int i = 1; i <= 4; i++)
    {
    NSString *fieldName = [[NSString alloc] initWithFormat:@"field%d", i];
    char *errorMsg;
    char *update = "INSERT OR REPLACE INTO FIELDS (ROW, FIELD_DATA) VALUES (?, ?);";
    sqlite3_stmt *stmt;
    if (sqlite3_prepare_v2(sql, update, -1, &stmt, nil) == SQLITE_OK)
    {
    //列1 绑定数据
    sqlite3_bind_int(stmt, 1, i);
    //列2 绑定数据
    sqlite3_bind_text(stmt, 2, [fieldName UTF8String], -1, NULL);
    }
    if (sqlite3_step(stmt) != SQLITE_DONE)
    {
    NSAssert1(0, @"插入数据产生错误: %s", errorMsg);
    }
    sqlite3_finalize(stmt);
    }
    5、查询数据
    NSString *query = @"SELECT ROW, FIELD_DATA FROM FIELDS ORDER BY ROW";
    sqlite3_stmt *statement;
    if (sqlite3_prepare_v2( sql, [query UTF8String],-1, &statement, nil) == SQLITE_OK) {
    while (sqlite3_step(statement) == SQLITE_ROW)
    {
    //列1
    int row = sqlite3_column_int(statement, 0);
    //列2
    char *rowData = (char *)sqlite3_column_text(statement, 1);
    NSString *fieldName = [[NSString alloc]
    initWithFormat:@"%d", row];
    NSString *fieldValue = [[NSString alloc]
    initWithUTF8String:rowData];


    NSLog(@"Row:%@ Data:%@",fieldName,fieldValue);


    }
    sqlite3_finalize(statement);


    //关闭数据库
    sqlite3_close(sql);
    }
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    打开数据库 另外一种方法: 
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);


        NSString *documentsDirectory = [paths objectAtIndex:0];


        NSString *path = [documentsDirectory stringByAppendingPathComponent:@"database.sqlite"];//database.sqlite为自己定义数据库名称


        NSFileManager *fileManager = [NSFileManager defaultManager];


        databasePath_ = path;


        BOOL find = [fileManager fileExistsAtPath:path];


        if (!find) {


    NSString *rePath = getBundleFilePath(@"database", @"sqlite");


    NSData *dataFile = [NSData dataWithContentsOfFile:rePath];


    [dataFile writeToFile:databasePath_ atomically:YES];


    }
    NSLog(@"Database file have already existed.");


    if(sqlite3_open([path UTF8String], &database_) != SQLITE_OK) {


    sqlite3_close(database_);


    NSLog(@"Error: open database file.");
    }




    四、简要说明一下SQLite数据库执行SQL语句的过程 


    ** 调用sqlite3_prepare()将SQL语句编译为sqlite内部一个结构体(sqlite3_stmt).该结构体中包含了将要执行的的SQL语句的信息. 
    ** 如果需要传入参数,在SQL语句中用'?'作为占位符,再调用sqlite3_bind_XXX()函数将对应的参数传入.
    ** 调用sqlite3_step(),这时候SQL语句才真正执行.注意该函数的返回值,SQLITE_DONE和SQLITE_ROW都是表示执行成功, 不同的是SQLITE_DONE表示没有查询结果,象UPDATE,INSERT这些SQL语句都是返回SQLITE_DONE,SELECT查询语句在 查询结果不为空的时候返回SQLITE_ROW,在查询结果为空的时候返回SQLITE_DONE. 
    ** 每次调用sqlite3_step()的时候,只返回一行数据,使用sqlite3_column_XXX()函数来取出这些数据.要取出全部的数据需要 反复调用sqlite3_step(). (注意, 在bind参数的时候,参数列表的index从1开始,而取出数据的时候,列的index是从0开始). 
    ** 在SQL语句使用完了之后要调用sqlite3_finalize()来释放stmt占用的内存.该内存是在sqlite3_prepare()时分配的. 
           ** 如果SQL语句要重复使用,可以调用sqlite3_reset()来清楚已经绑定的参数


    五、构建一个SqliteHelper类及其方法(详细的类 见代码总结文件SQLiteHelper)


    写一个SQLite的Helper文件,方便我们在其他的代码中使用,头文件(SqliteHelper.h)如下。
      #import 
      #import “sqlite3.h“
      #define kFileName @”mydatabase.sql”
      @interface SqliteHelper : NSObject {
      sqlite3 *database;
      }
      //创建表
      - (BOOL)createTable;
      //插入数据
      - (BOOL)insertMainTable:(NSString*) username insertPassword:(NSString*) password;
      //查询表
      - (BOOL)checkIfHasUser;
      @end
      我们的代码文件如下。
      #import “SqliteHelper.h“
      @implementation SqliteHelper
      - (BOOL)createTable
      {
      NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
      NSString *paths = [[path objectAtIndex:0] stringByAppendingPathComponent:kFileName];
      NSFileManager *fileManager = [NSFileManager defaultManager];
      BOOL fileFinded = [fileManager fileExistsAtPath:paths];
      NSLog(@”Database file path is %@“,paths);
      if(fileFinded)
      {
      NSLog(@”Database file existed“);
      if(sqlite3_open([paths UTF8String],&database)!=SQLITE_OK)
      {
      sqlite3_close(database);
      NSLog(@”Open Failed“);
      return NO;
      }
      }
      else
      {
      NSLog(@”Database file is not existed“);
      if(sqlite3_open([paths UTF8String],&database)!=SQLITE_OK)
      {
      sqlite3_close(database);
      NSLog(@”Open Failed“);
      return NO;
      }
      }
      char *errorMsg;
      NSString *createSQL = @”create table if not exists fields (userid integer primary key,username text,password text)“;
      if(sqlite3_exec(database,[createSQL UTF8String],NULL,NULL,&errorMsg)!=SQLITE_OK)
      {
      sqlite3_close(database);
      NSLog(@”Open failed or init filed“);
      return NO;
      }
      return YES;
      }
      - (BOOL)insertMainTable:(NSString*) username insertPassword:(NSString*) password
      {
      char *errorMsg;
      NSString *createSQL = @”create table if not exists fields (userid integer primary key,username text,password text)“;
      if(sqlite3_exec(database,[createSQL UTF8String],NULL,NULL,&errorMsg)!=SQLITE_OK)
      {
      sqlite3_close(database);
      NSLog(@”Open failed or init filed“);
      return NO;
      }
      NSString *insertData = [[NSString alloc] initWithFormat:@”insert or replace into fields (userid,username,password) values (%d,’%@’,'%@’)“,0,username,password];
      if(sqlite3_exec(database,[insertData UTF8String],NULL,NULL,&errorMsg)!=SQLITE_OK)
      {
      sqlite3_close(database);
      NSLog(@”Open failed or failed to insert“);
      return NO;
      }
      return YES;
      }
      - (BOOL)checkIfHasUser
      {
      NSString *getUserCountSQL = @”select * from fields“;
      sqlite3_stmt *statement;
      NSLog(@”checkIfHasUser“);
      if(sqlite3_prepare_v2(database,[getUserCountSQL UTF8String],-1,&statement,nil)==SQLITE_OK)
      {
      //while(sqlite3_step(statement) == SQLITE_ROW)
      //{
      // int row = sqlite3_column_int(statement,0);
      // char* rowData = (char*)sqlite3_column_text(statement,2);
      // NSString *fieldName = [[NSString alloc] initWithFormat:@”show%d”,row];
      // NSString *fieldValue = [[NSString alloc] initWithUTF8String:rowData];
      //
      // NSLog(@”fieldName is :%@,fieldValue is :%@”,fieldName,fieldValue);
      // return [[NSString alloc] initWithFormat:@”fieldName is :%@,fieldValue is :%@”,fieldName,fieldValue];
      //
      // [fieldName release];
      // [fieldValue release];
      //}
      //sqlite3_finalize(statement);
      if(sqlite3_step(statement) == SQLITE_ROW)
      {
      NSLog(@”Have user“);
      return YES;
      }
      }
      NSLog(@”No user“);
      return NO;
      }
      @end
      其中checkIfHasUser是检查数据,这个方法中我注释的是得到数据,因为我们这里只是check,所以不需要得到数据,直接看是否存在数据即可
  • 相关阅读:
    Consul的反熵
    Swift:一个基于.NET Core的分布式批处理框架
    C03:架构,面向人的设计,面向业务的建模
    架构-W01-食堂就餐卡系统设计
    架构C02:商业模式与架构设计
    架构C01: 什么是架构?为什么做架构?架构师需要做什么?
    程序中的日志
    物联网这一次应该是认真的!
    移动端H5混合开发设置复盘与总结
    span 英文数字保持一行,中文自动换行
  • 原文地址:https://www.cnblogs.com/ejllen/p/3785338.html
Copyright © 2020-2023  润新知