数据持久化(二)-----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 类型的数据


@Sqlite3主要步骤如下:

1 首先获取iPhone上Sqlite 3的数据库文件的地址
2 打开Sqlite 3的数据库文件
3 定义SQL文
4 邦定执行SQL所需要的参数
5 执行SQL文,并获取结果
6 释放资源
7 关闭Sqlite 3数据库。


@导入库

在工程中的Frameworks中导入相应的libsqlite3.dylib文件,也许在相应的目录下存在多个以libsqlite3开头的文件,务必选择libsqlite3.dylib,它始终指向最新版的SQLite3库的别名。


@SQLite数据库执行SQL语句的过程

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


#import "HMTSqlDBManager.h"
#import <sqlite3.h>          //--------记得导入libsqlite3.0.dylib库



@implementation HMTSqlDBManager

static  HMTSqlDBManager * _dbManager = nil;

+ (HMTSqlDBManager *)shareInstance{

    @synchronized(self){
        if (!_dbManager) {
            
            _dbManager = [[HMTSqlDBManager alloc]init];
        }
    }
    
    return _dbManager;
}

#pragma mark - 获取沙盒下Documents路径
- (NSString *)documentsPath{
    
    return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES)lastObject];
    
}

#pragma mark - 先声明一个数据库类型的变量
static sqlite3 * dbSqlite = nil;

#pragma mark - 打开数据库操作
- (void)openDB{

    // (3)如果数据库存在并且已经打开,直接返回
    if (dbSqlite) {
        return;
    }
    
    // 拼接出数据库全路径
    NSString * filePath = [[self documentsPath] stringByAppendingPathComponent:@"Lanou.sqlite"];
    
    // 创建一个文件管理器
    NSFileManager * fileManager = [NSFileManager defaultManager];
    
    // (1)判断是否存在数据库文件
    if (![fileManager fileExistsAtPath:filePath]) {
        
        // 打开数据库(这里已经会创建data.sqlite数据库了,但是,里面为空)
        int result = sqlite3_open([filePath UTF8String],&dbSqlite);
        if (result == SQLITE_OK) {
            
            // 设置创建表语句CREATE
            NSString * sql = @"CREATE TABLE Student (number INTEGER PRIMARY KEY  AUTOINCREMENT  NOT NULL,name TEXT DEFAULT 18,age INTEGER NOT NULL  DEFAULT 18,sex TEXT DEFAULT 不男不女,icon BLOB);";
            
            // 执行
            sqlite3_exec(dbSqlite,[sql UTF8String],NULL,NULL);
        }
    }
    
    // (2)打开数据库
    sqlite3_open([filePath UTF8String],&dbSqlite);
    
}

#pragma mark - 关闭数据库操作
- (void)closeDB{

    int result = sqlite3_close(dbSqlite);
    if (result == SQLITE_OK) {
        dbSqlite = nil;
    }
    
}

#pragma mark - **********增-----删-----改-----查 数据,最好封装成对象,直接对对象进行操作**********

#pragma mark - 插入数据操作
- (void)insertDataWithNumber:(int)number Name:(NSString *)name Sex:(NSString *)sex Age:(int)age Image:(UIImage *)image{

    // 1.打开数据库
    [self openDB];
    
    // 2.跟随指针,记录数据库的每步操作
    sqlite3_stmt * stmt = nil;
    
    // 3.绑定数据,执行sql语句(插入列表,用"?"占位符表示)
    NSString * sql = @"INSERT INTO Student(number,name,sex,age,icon) VALUES(?,?,?)";
    
    // 4.编译,验证SQL语句是否正确
    int result = sqlite3_prepare_v2(dbSqlite,-1,&stmt,NULL);
    if (result == SQLITE_OK) {
        
        // 5.绑定sql语句中得值(替换"?")----图像存入数据库,自断类型为blob,将图像转为二进制数据NSData存入
        sqlite3_bind_int(stmt,1,number);
        sqlite3_bind_text(stmt,2,[name UTF8String],NULL);
        sqlite3_bind_text(stmt,3,[sex UTF8String],NULL);
        sqlite3_bind_int(stmt,4,age);
        sqlite3_bind_blob(stmt,5,[UIImagePNGRepresentation(image) bytes],(int)[UIImagePNGRepresentation(image) length],NULL);
    }

    // 6.执行
    sqlite3_step(stmt);
    
    // 7.释放
    sqlite3_finalize(stmt);

    // 8.关闭数据库
    [self closeDB];
}

#pragma mark - 修改数据操作
- (void)updateNumber:(int)number Name:(NSString *)name{

    // 1.
    [self openDB];
    
    // 2.
    sqlite3_stmt * stmt= nil;
    
    // 3.
    NSString * sql = @"UPDATE Student SET name = ? WHERE number = ?";
    
    // 4.
    int result = sqlite3_prepare_v2(dbSqlite,NULL);
    if (result == SQLITE_OK) {
        
        // 5.
        sqlite3_bind_text(stmt,number);
        
        // 6.
        sqlite3_step(stmt);
    }

    // 7.
    sqlite3_finalize(stmt);
    
    // 8.
    [self closeDB];
    
}

#pragma mark - 删除数据操作
- (void)deleteNumber:(int)number{

    // 1.
    [self openDB];
    
    // 2.stmt跟随指针(数据库句柄)
    sqlite3_stmt * stmt= nil;
    
    // 3.
    NSString * sql = @"DELETE FROM Student WHERE number = ?";
    
    // 4.
    int result = sqlite3_prepare_v2(dbSqlite,NULL);
    if (result == SQLITE_OK) {
        
        // 5.
        sqlite3_bind_int(stmt,number);
        
        // 6.
        sqlite3_step(stmt);
    }
    
    // 7.
    sqlite3_finalize(stmt);

    // 8.
    [self closeDB];
    
}

#pragma mark - 查询数据操作
- (NSArray *)selectAllData{
    
    NSMutableArray * allDataArray = [NSMutableArray array];

    // 1.
    dbSqlite = [self openDB];
    
    // 2.类似JAVA句柄?
    sqlite3_stmt * stmt = nil;
    
    // 3.设置查询数据语句SELECT
    NSString * sql = @"SELECT name FROM Student";
    
    // 4.编译
    int result = sqlite3_prepare_v2(dbSqlite,NULL);
    if (result == SQLITE_OK) {
        
        // 5.查询数据
        while (sqlite3_step(stmt) == SQLITE_ROW) {
            
            // 6.查询的索引下标从0开始(每一次循环后,下标+1)
            const unsigned char * name = sqlite3_column_text(stmt,0);
            //NSString * nameString = [NSString stringWithUTF8String:(const char *)name];
            NSString * nameString = [NSString stringWithCString:(const char *)name encoding:NSUTF8StringEncoding];
            [allDataArray addObject:nameString];
        }
        
        // 8.关闭数据库句柄
        sqlite3_finalize(stmt);
        
        // 9.
        [self closeDB];
        
        return allDataArray;
    }

    return nil;
}

- (NSMutableDictionary *)selectOneDataWithNumber:(int)number{
    
    sqlite3 * _dbSqlite = [self openDB];
    
    sqlite3_stmt * stmt = nil;
    
    NSString * sql = @"SELECT * FROM Student WHERE number = ?";
    
    int result = sqlite3_prepare_v2(_dbSqlite,NULL);
    
    if (result == SQLITE_OK) {
        
        sqlite3_bind_int(stmt,number);
        while (sqlite3_step(stmt) == SQLITE_ROW) {
          
            int number = sqlite3_column_int(stmt,0);
            NSString * name = [NSString stringWithUTF8String:(const char *)sqlite3_column_text(stmt,1)];
            int age = sqlite3_column_int(stmt,2);
            NSString * sex = [NSString stringWithUTF8String:(const char *)sqlite3_column_text(stmt,3)];
            UIImage * image = [UIImage imageWithData:[NSData dataWithBytes:sqlite3_column_blob(stmt,4) length:sqlite3_column_bytes(stmt,4)]];
            
            NSMutableDictionary * dic = [NSMutableDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:number],@"number",@"name",[NSNumber numberWithInt:age],@"age",@"sex",image,@"image",nil];
 
            // 关闭数据库句柄
            sqlite3_finalize(stmt);
            return dic;
        }
        
    }

    return nil;
}

@end


@SQLite支持哪些数据类型些?
NULL 值为NULL
INTEGER 值为带符号的整型,根据类别用1,2,3,4,6,8字节存储
REAL 值为浮点型,8字节存储
TEXT 值为text字符串,使用数据库编码(UTF-8,UTF-16BE or UTF-16-LE)存储
BLOB 值为二进制数据,具体看实际输入
---------但实际上,sqlite3也接受如下的数据类型:
smallint  16 位元的整数
interger  32 位元的整数
decimal(p,s)  p 精确值和 s 大小的十进位整数,精确值p是指全部有几个数(digits)大小值 ,s是指小数点後有几位数。如果没有特别指定,则系统会设为 p=5; s=0 。
float   32位元的实数。
double   64位元的实数。
char(n)   n 长度的字串,n不能超过 254。
varchar(n)  长度不固定且其最大长度为 n 的字串,n不能超过 4000。
graphic(n)  和 char(n) 一样,不过其单位是两个字元 double-bytes, n不能超过127。 这个形态是为了支援两个字元长度的字体,例如中文字。
vargraphic(n)  可变长度且其最大长度为 n 的双字元字串,n不能超过 2000。
date   包含了 年份、月份、日期。
time   包含了 小时、分钟、秒。
timestamp  包含了 年、月、日、时、分、秒、千分之一秒。

@如果将某个字段设置为INTEGER PRIMARY KEY属性,有什么特性?
如果将声明表的一列设置为 INTEGER PRIMARY KEY,则具有:
1.每当你在该列上插入一NULL值时, NULL自动被转换为一个比该列中最大值大1的一个整数;
2.如果表是空的, 将会是1;
---------注意该整数会比表中该列上的插入之前的最大值大1。 该键值在当前的表中是唯一的。但有可能与已从表中删除的值重叠。要
想建立在整个表的生命周期中唯一的键值,需要在 INTEGER PRIMARY KEY 上增加AUTOINCREMENT声明。那么,新的键值将会比该表中曾能存在过的最大值大1。

@字段声明中有AUTOINCREMENT属性,有什么与众不同的含义?
要想建立在整个表的生命周期中唯一的键值,需要在 INTEGER PRIMARY KEY 上增加AUTOINCREMENT声明。那么,新的键值将会比该表中曾能存在过的最大值大1。


@SQL常用命令使用方法:

(1) 数据记录筛选:

sql="select * from 数据表 where 字段名=字段值 order by 字段名 [desc]"

sql="select * from 数据表 where 字段名 like %字段值% order by 字段名 [desc]"

sql="select top 10 * from 数据表 where 字段名 order by 字段名 [desc]"

sql="select * from 数据表 where 字段名 in (值1,值2,值3)"

sql="select * from 数据表 where 字段名 between 值1 and 值2"

(2) 更新数据记录:

sql="update 数据表 set 字段名=字段值 where 条件表达式"

sql="update 数据表 set 字段1=值1,字段2=值2 …… 字段n=值n where 条件表达式"

(3) 删除数据记录:

sql="delete from 数据表 where 条件表达式"

sql="delete from 数据表" (将数据表所有记录删除)

(4) 添加数据记录:

sql="insert into 数据表 (字段1,字段2,字段3 …) valuess (值1,值3 …)"

sql="insert into 目标数据表 select * from 源数据表" (把源数据表的记录添加到目标数据表)

(5) 数据记录统计函数:

AVG(字段名) 得出一个表格栏平均值
COUNT(*|字段名) 对数据行数的统计或对某一栏有值的数据行数统计
MAX(字段名) 取得一个表格栏最大的值
MIN(字段名) 取得一个表格栏最小的值
SUM(字段名) 把数据栏的值相加

引用以上函数的方法:

sql="select sum(字段名) as 别名 from 数据表 where 条件表达式"
set rs=conn.excute(sql)

用 rs("别名") 获取统的计值,其它函数运用同上。

(6) 数据表的建立和删除:

CREATE TABLE 数据表名称(字段1 类型1(长度),字段2 类型2(长度) …… )

例:CREATE TABLE tab01(name varchar(50),datetime default now())

DROP TABLE 数据表名称 (永久性删除一个数据表)

@sqlite中用LIMIT返回前2行,语句如下: 
select * from aa order by ids desc LIMIT 2

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

相关推荐


SQLite架构简单,又有Json计算能力,有时会承担Json文件/RESTful的计算功能,但SQLite不能直接解析Json文件/RESTful,需要用Java代码硬写,或借助第三方类库,最后再拼成insert语句插入数据表,代码非常繁琐,这里就不展示了。参考前面的代码可知,入库的过程比较麻烦,不能只用SQL,还要借助Java或命令行。SPL是现代的数据计算语言,属于简化的面向对象的语言风格,有对象的概念,可以用点号访问属性并进行多步骤计算,但没有继承重载这些内容,不算彻底的面向对象语言。...
使用Python操作内置数据库SQLite以及MySQL数据库。
破解微信数据库密码,用python导出微信聊天记录
(Unity)SQLite 是一个软件库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。SQLite 是在世界上最广泛部署的 SQL 数据库引擎。SQLite 源代码不受版权限制。本教程将告诉您如何使用 SQLite 编程,并让你迅速上手。.................................
安卓开发,利用SQLite实现登陆注册功能
相比大多数数据库而言,具有等优势,广泛应用于、等领域。
有时候,一个项目只有一个数据库,比如只有SQLite,或者MySQL数据库,那么我们只需要使用一个固定的数据库即可。但是一个项目如果写好了,有多个用户使用,但是多个用户使用不同的数据库,这个时候,我们就需要把软件设计成可以连接多个数据库的模式,用什么数据库,就配置什么数据库即可。4.Users实体类,这个实体类要和数据库一样的,形成一一对应的关系。11.Sqlite数据库,需要在代码里面创建数据库,建立表,再建立数据。8.我们开启MySQL数据库,然后进行调试,看程序的结果。2.安装SqlSugar。
基于Android的背单词软件,功能强大完整。
SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统。说白了就是使用起来轻便简单,
Android的简单购物车案例
SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。它是D.RichardHipp建立的公有领域项目。它的设计目标是嵌入式的,而且已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。它能够支持Windows/Linux/Unix等等主流的操作系统,同时能够跟很多程序语言相结合,比如 Tcl、C#、PHP、Java等,还有ODBC接口,同样比起Mysql、PostgreSQL这两款开源的世界著名数据库...
Qt设计较为美观好看的登录注册界面(包含SQLite数据库以及TCP通信的应用)
SQLite是用C语言开发的跨平台小型数据库,可嵌入其他开发语言,也可在单机执行。SPL是用Java开发的跨平台的数据计算语言,可嵌入Java,可在单机执行,可以数据计算服务的形式被远程调用。两者的代码都是解释执行的。...
新建库.openDATA_BASE;新建表createtableLIST_NAME(DATA);语法:NAME关键字...<用逗号分割>删除表droptableNAME;查看表.schema查看表信息新建数据insertintoLIST_NAMEvalues();语法:CLASS,PARAMETER...,CLASS是类别,PARAMETER是参数<用逗号分割新建的
importsqlite3classDemo01:def__init__(self):self.conn=sqlite3.connect("sql_demo_001.db")self.cursor1=self.conn.cursor()self.cursor1.execute("select*fromtable_001wherename=?andid=?",('ssss&#0
 在客户端配置文件<configuration>节点下,添加:<connectionStrings>      <add name="localdb" connectionString="Data Source=config/local.db;Version=3;UseUTF16Encoding=True;" providerName="System.Data.SQLite.SQLiteFactory"/&g
提到锁就不得不说到死锁的问题,而SQLite也可能出现死锁。下面举个例子:连接1:BEGIN(UNLOCKED)连接1:SELECT...(SHARED)连接1:INSERT...(RESERVED)连接2:BEGIN(UNLOCKED)连接2:SELECT...(SHARED)连接1:COMMIT(PENDING,尝试获取EXCLUSIVE锁,但还有SHARED锁未释放,返回SQLITE_BUSY)连接2:INSERT...
SQLite是一种嵌入式数据库,它的数据库就是一个文件。由于SQLite本身是C写的,而且体积很小,所以,经常被集成到各种应用程序中,甚至在iOS和Android的App中都可以集成。Python就内置了SQLite3,所以,在Python中使用SQLite,不需要安装任何东西,直接使用。在使用SQLite前,我们先要搞清楚几个概念:表
设计思想————首先要确定有几个页面、和每个页面的大致布局由于是入门,我也是学习了不是很长的时间,所以项目比较low。。。。第一个页面,也就是打开APP的首页面:今天这个博客,先实现添加功能!:首先对主界面进行布局:其中activity_main.xml的代码为<?xmlversion="1.0"encoding="