前言:

之前学习了数据存储的NSUserDefaults,归档和解档,沙盒文件存储,但是对于数据量比较大,需要频繁查询,删除,更新等操作的时候无论从效率上还是性能上,上述三种明显不能满足我们的日常开发需要了。这个时候我们必须借助数据库,做为Android开发的都知道采用的是一种轻量级数据库Sqlite。其实它广泛用于包括浏览器、IOS,Android以及一些便携需求的小型web应用系统。它具备占用资源低,处理速度快等优点。接下来我们具体认识一下。

我们在项目开发中需要引入libsqlite3.dylib,那么sqllite有哪些具体方法呢?

sqlite3  *db, 数据库句柄,跟文件句柄FILE很类似
sqlite3_stmt *stmt, 这个相当于ODBC的Command对象,用于保存编译好的SQL语句
sqlite3_open(), 打开数据库,没有数据库时创建。
sqlite3_exec(), 执行非查询的sql语句
Sqlite3_step(), 在调用sqlite3_prepare后,使用这个函数在记录集中移动。
Sqlite3_close(), 关闭数据库文件还有一系列的函数,用于从记录集字段中获取数据,如
sqlite3_column_text(), 取text类型的数据。
sqlite3_column_blob(),取blob类型的数据
sqlite3_column_int(), 取int类型的数据

为了系统而且方面的学习sqlite 整理一个sqlite管理类DBManager,实现功能具体涵盖了:数据库的创建,打开,关闭,升级,数据的增删改查,以及事务的开启和开启事务的好处。

DBManager.h

#import <Foundation/Foundation.h>

@interface DBManager : NSObject<NSCopying>

//创建数据库管理者单例
+(instancetype)shareManager; //打开数据库
-(void)openDb; //关闭数据库
-(void)closeDb; //执行sql语句
-(void)execSql:(NSString *)sql; //创建数据库表
-(void)creatTable; //删除表结构
-(void)dropTable; //插入数据
-(void)insertData:(NSString*)tempName; //插入数据未开启事务
-(void)insertDataByNomarl:(NSArray*)tempNames; //插入数据开启事务
-(void)insertDataByTransaction:(NSArray*)tempNames; //删除数据
-(void)deleteData:(NSString*)tempName; //删除数据
-(void)deleteData; //修改数据
-(void)updateData:(NSString*)tempName; //查询数据
-(void)queryData; @end

DBManager.m

#import "DBManager.h"
#import <sqlite3.h> #define DBNAME @"myDb" //数据库名字
#define TBNAME @"persons" //表名
#define DBVERSION 1 //数据库版本
#define DBVERSIONKEY @"dbversion_key" //存储数据库版本key static DBManager *instance=nil; @implementation DBManager
{
//创建数据库实例
sqlite3 *db;
} -(instancetype)init
{
self=[super init];
if (self) {
[self creatTable];
[self upgrade];
}
return self;
} //创建数据库管理者单例
+(instancetype)shareManager
{
if(instance==nil){
@synchronized(self){
if(instance==nil){
instance =[[[self class]alloc]init];
}
}
}
return instance;
} -(id)copyWithZone:(NSZone *)zone
{ return instance;
} +(id)allocWithZone:(struct _NSZone *)zone
{
if(instance==nil){
instance =[super allocWithZone:zone];
}
return instance;
} //打开数据库
-(void)openDb
{ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documents = [paths objectAtIndex:];
NSString *database_path = [documents stringByAppendingPathComponent:DBNAME]; if (sqlite3_open([database_path UTF8String], &db) == SQLITE_OK) {
NSLog(@"数据库打开成功");
}else{
[self closeDb];
NSLog(@"数据库打开失败");
} } //关闭数据库
-(void)closeDb
{
sqlite3_close(db);
} //检查数据库是否需要升级
- (void)upgrade {
//获取存储好的原版本号
NSInteger oldVersionNum = [[NSUserDefaults standardUserDefaults] integerForKey:DBVERSIONKEY];
if (DBVERSION <= oldVersionNum || oldVersionNum == ) {
return;
} //升级
[self upgrade:oldVersionNum]; // 保存新的版本号到库中 -这里大家可以使用NSUserDefault存储
[[NSUserDefaults standardUserDefaults]setInteger:DBVERSION forKey:DBVERSIONKEY];
} //根据不同版本执行不同的升级逻辑
- (void)upgrade:(NSInteger)oldVersion {
if (oldVersion >= DBVERSION) {
return;
}
switch (oldVersion) {
case :
//执行相应的升级操作
break;
case :
//执行相应的升级操作
break;
case :
//执行相应的升级操作
break;
default:
break;
}
oldVersion ++;
// 递归判断是否需要升级
[self upgrade:oldVersion];
} //执行sql语句
-(void)execSql:(NSString *)sql
{
[self openDb];
char *err;
if (sqlite3_exec(db, [sql UTF8String], NULL, NULL, &err) == SQLITE_OK) {
NSLog(@"数据库操作数据成功!");
}else{
sqlite3_free(err);
NSLog(@"数据库操作数据失败!");
}
sqlite3_close(db);
} //创建数据库表
-(void)creatTable
{
NSString *creatTableSql=[NSString stringWithFormat:@"create table if not exists %@(person_id integer primary key,name text)",TBNAME];
[self execSql:creatTableSql];
} //删除数据库表
-(void)dropTable
{
NSString *dropTableSql=[NSString stringWithFormat:@"drop table %@",TBNAME];
[self execSql:dropTableSql];
} //插入数据
-(void)insertData:(NSString*)tempName
{
NSString *insertSql = [NSString stringWithFormat:@"insert into %@ (name) values ('%@')",TBNAME,tempName];
[self execSql:insertSql];
} //插入数据未开启事务
-(void)insertDataByNomarl:(NSArray*)tempNames
{
[self openDb];
for(NSString *name in tempNames){
NSString *sql = [NSString stringWithFormat:@"insert into %@ (name) values ('%@')",TBNAME,name];
char *err;
if (sqlite3_exec(db, [sql UTF8String], NULL, NULL, &err) == SQLITE_OK) {
NSLog(@"数据库操作数据成功!");
}else{
sqlite3_free(err);
NSLog(@"数据库操作数据失败!");
}
}
[self closeDb];
} //插入数据开启事务
-(void)insertDataByTransaction:(NSArray*)tempNames
{
@try{
char *errorMsg;
[self openDb];
if (sqlite3_exec(db, "BEGIN", NULL, NULL, &errorMsg)==SQLITE_OK) { NSLog(@"启动事务成功"); sqlite3_free(errorMsg); //执行真正的操作
for(NSString *name in tempNames){
NSString *sql = [NSString stringWithFormat:@"insert into %@ (name) values ('%@')",TBNAME,name];
char *err;
if (sqlite3_exec(db, [sql UTF8String], NULL, NULL, &err) == SQLITE_OK) {
NSLog(@"数据库操作数据成功!");
}else{
sqlite3_free(err);
NSLog(@"数据库操作数据失败!");
}
} if (sqlite3_exec(db, "COMMIT", NULL, NULL, &errorMsg)==SQLITE_OK) { NSLog(@"提交事务成功");
} sqlite3_free(errorMsg); }else{
sqlite3_free(errorMsg);
} } @catch(NSException *e){ char *errorMsg;
if (sqlite3_exec(db, "ROLLBACK", NULL, NULL, &errorMsg)==SQLITE_OK) {
NSLog(@"回滚事务成功");
}
sqlite3_free(errorMsg); }
[self closeDb];
} //删除数据
-(void)deleteData:(NSString*)tempName
{
NSString *deleteSql=[NSString stringWithFormat:@"delete from %@ where name = '%@'",TBNAME,tempName];
[self execSql:deleteSql]; } //删除数据
-(void)deleteData
{
NSString *deleteSql=[NSString stringWithFormat:@"delete from %@ ",TBNAME];
[self execSql:deleteSql];
} //修改数据
-(void)updateData:(NSString*)tempName
{
NSString *updateSql=[NSString stringWithFormat:@"update %@ set name ='test' where name = '%@'",TBNAME,tempName];
[self execSql:updateSql]; } //查询数据
-(void)queryData
{
[self openDb];
NSString *querySql =[NSString stringWithFormat:@"select * from %@",TBNAME];
sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(db, [querySql UTF8String], -, &stmt, nil) == SQLITE_OK) { while (sqlite3_step(stmt)==SQLITE_ROW) { char *name = (char *)sqlite3_column_text(stmt, );
NSString *nameString = [[NSString alloc] initWithUTF8String:name];
NSLog(@"nameString---->%@",nameString); } sqlite3_finalize(stmt);
}
[self closeDb]; }
@end

具体使用方法:

#import "DBManager.h"
#import <sqlite3.h> #define DBNAME @"myDb" //数据库名字
#define TBNAME @"persons" //表名
#define DBVERSION 1 //数据库版本
#define DBVERSIONKEY @"dbversion_key" //存储数据库版本key static DBManager *shareManager=nil; @implementation DBManager
{
//创建数据库实例
sqlite3 *db;
} -(instancetype)init
{
self=[super init];
if (self) {
[self creatTable];
[self upgrade];
}
return self;
} //创建数据库管理者单例
+(instancetype)shareManager
{
if(shareManager==nil){
@synchronized(self){
if(shareManager==nil){
shareManager =[[[self class]alloc]init];
}
}
}
return shareManager;
} -(id)copyWithZone:(NSZone *)zone
{ return shareManager;
} +(id)allocWithZone:(struct _NSZone *)zone
{
if(shareManager==nil){
shareManager =[super allocWithZone:zone];
}
return shareManager;
} //打开数据库
-(void)openDb
{ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documents = [paths objectAtIndex:];
NSString *database_path = [documents stringByAppendingPathComponent:DBNAME]; if (sqlite3_open([database_path UTF8String], &db) == SQLITE_OK) {
NSLog(@"数据库打开成功");
}else{
[self closeDb];
NSLog(@"数据库打开失败");
} } //关闭数据库
-(void)closeDb
{
sqlite3_close(db);
} //删除数据库
-(void)dropDb
{ } //检查数据库是否需要升级
- (void)upgrade {
//获取存储好的原版本号
NSInteger oldVersionNum = [[NSUserDefaults standardUserDefaults] integerForKey:DBVERSIONKEY];
if (DBVERSION <= oldVersionNum || oldVersionNum == ) {
return;
} //升级
[self upgrade:oldVersionNum]; // 保存新的版本号到库中 -这里大家可以使用NSUserDefault存储
[[NSUserDefaults standardUserDefaults]setInteger:DBVERSION forKey:DBVERSIONKEY];
} //根据不同版本执行不同的升级逻辑
- (void)upgrade:(NSInteger)oldVersion {
//对比数据库版本
if (oldVersion >= DBVERSION) {
return;
}
switch (oldVersion) {
case :
//执行相应的升级操作
break;
case :
//执行相应的升级操作
break;
case :
//执行相应的升级操作
break;
default:
break;
}
oldVersion ++;
// 递归判断是否需要升级
[self upgrade:oldVersion];
} //执行sql语句
-(void)execSql:(NSString *)sql
{
[self openDb];
char *err;
if (sqlite3_exec(db, [sql UTF8String], NULL, NULL, &err) == SQLITE_OK) {
NSLog(@"数据库操作数据成功!");
}else{
sqlite3_free(err);
NSLog(@"数据库操作数据失败!");
}
sqlite3_close(db);
} //创建数据库表
-(void)creatTable
{
NSString *creatTableSql=[NSString stringWithFormat:@"create table if not exists %@(person_id integer primary key,name text)",TBNAME];
[self execSql:creatTableSql];
} //删除数据库表
-(void)dropTable
{
NSString *dropTableSql=[NSString stringWithFormat:@"drop table %@",TBNAME];
[self execSql:dropTableSql];
} //插入数据
-(void)insertData:(NSString*)tempName
{
NSString *insertSql = [NSString stringWithFormat:@"insert into %@ (name) values ('%@')",TBNAME,tempName];
[self execSql:insertSql];
} //插入数据未开启事务
-(void)insertDataByNomarl:(NSArray*)tempNames
{
[self openDb];
for(NSString *name in tempNames){
NSString *sql = [NSString stringWithFormat:@"insert into %@ (name) values ('%@')",TBNAME,name];
char *err;
if (sqlite3_exec(db, [sql UTF8String], NULL, NULL, &err) == SQLITE_OK) {
//NSLog(@"数据库操作数据成功!");
}else{
sqlite3_free(err);
//NSLog(@"数据库操作数据失败!");
}
}
[self closeDb];
} //插入数据开启事务
-(void)insertDataByTransaction:(NSArray*)tempNames
{
@try{
char *errorMsg;
[self openDb];
if (sqlite3_exec(db, "BEGIN", NULL, NULL, &errorMsg)==SQLITE_OK) { NSLog(@"启动事务成功"); sqlite3_free(errorMsg); //执行真正的操作
for(NSString *name in tempNames){
NSString *sql = [NSString stringWithFormat:@"insert into %@ (name) values ('%@')",TBNAME,name];
char *err;
if (sqlite3_exec(db, [sql UTF8String], NULL, NULL, &err) == SQLITE_OK) {
//NSLog(@"数据库操作数据成功!");
}else{
sqlite3_free(err);
// NSLog(@"数据库操作数据失败!");
}
} if (sqlite3_exec(db, "COMMIT", NULL, NULL, &errorMsg)==SQLITE_OK) { NSLog(@"提交事务成功");
} sqlite3_free(errorMsg); }else{
sqlite3_free(errorMsg);
} } @catch(NSException *e){ char *errorMsg;
if (sqlite3_exec(db, "ROLLBACK", NULL, NULL, &errorMsg)==SQLITE_OK) {
NSLog(@"回滚事务成功");
}
sqlite3_free(errorMsg); }
[self closeDb];
} //删除数据
-(void)deleteData:(NSString*)tempName
{
NSString *deleteSql=[NSString stringWithFormat:@"delete from %@ where name = '%@'",TBNAME,tempName];
[self execSql:deleteSql]; } //删除数据
-(void)deleteData
{
NSString *deleteSql=[NSString stringWithFormat:@"delete from %@ ",TBNAME];
[self execSql:deleteSql];
} //修改数据
-(void)updateData:(NSString*)tempName
{
NSString *updateSql=[NSString stringWithFormat:@"update %@ set name ='test' where name = '%@'",TBNAME,tempName];
[self execSql:updateSql]; } //查询数据
-(void)queryData
{
[self openDb];
NSString *querySql =[NSString stringWithFormat:@"select * from %@",TBNAME];
sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(db, [querySql UTF8String], -, &stmt, nil) == SQLITE_OK) { while (sqlite3_step(stmt)==SQLITE_ROW) { char *name = (char *)sqlite3_column_text(stmt, );
NSString *nameString = [[NSString alloc] initWithUTF8String:name];
NSLog(@"nameString---->%@",nameString); } sqlite3_finalize(stmt);
}
[self closeDb]; } @end

重点来了,曾经做个IM即时通讯方面,聊天信息相对来说还是比较庞大一点,动不动就是成千上万条聊天信息,有时候执行一个消息已读状态的更新都要耗时很长,那时候偶还没有学习IOS开发,在Android平台上我已经领略过开启事务对效率的提升所带来的喜悦了,那么ios上面是怎么开启事务的呢?效率怎么样呢?让我们一探究竟:

开启事务:

//插入数据开启事务
-(void)insertDataByTransaction:(NSArray*)tempNames
{
@try{
char *errorMsg;
[self openDb];
if (sqlite3_exec(db, "BEGIN", NULL, NULL, &errorMsg)==SQLITE_OK) { NSLog(@"启动事务成功"); sqlite3_free(errorMsg); //执行真正的操作
for(NSString *name in tempNames){
NSString *sql = [NSString stringWithFormat:@"insert into %@ (name) values ('%@')",TBNAME,name];
char *err;
if (sqlite3_exec(db, [sql UTF8String], NULL, NULL, &err) == SQLITE_OK) {
NSLog(@"数据库操作数据成功!");
}else{
sqlite3_free(err);
NSLog(@"数据库操作数据失败!");
}
} if (sqlite3_exec(db, "COMMIT", NULL, NULL, &errorMsg)==SQLITE_OK) { NSLog(@"提交事务成功");
} sqlite3_free(errorMsg); }else{
sqlite3_free(errorMsg);
}
} @catch(NSException *e){ char *errorMsg;
if (sqlite3_exec(db, "ROLLBACK", NULL, NULL, &errorMsg)==SQLITE_OK) {
NSLog(@"回滚事务成功");
}
sqlite3_free(errorMsg);
}
[self closeDb];
}

同时准备一个未开启事务的:

//插入数据未开启事务
-(void)insertDataByNomarl:(NSArray*)tempNames
{
[self openDb];
for(NSString *name in tempNames){
NSString *sql = [NSString stringWithFormat:@"insert into %@ (name) values ('%@')",TBNAME,name];
char *err;
if (sqlite3_exec(db, [sql UTF8String], NULL, NULL, &err) == SQLITE_OK) {
NSLog(@"数据库操作数据成功!");
}else{
sqlite3_free(err);
NSLog(@"数据库操作数据失败!");
}
}
[self closeDb];
}

测试程序:

        //测试事务
NSMutableArray *testArray =[[NSMutableArray alloc]init];
int testMaxCount =;
for(int i=;i<testMaxCount;i++){
NSString *string = [[NSString alloc] initWithFormat:@"%d",i];
[testArray addObject:string];
} //未开启事务插入
CFAbsoluteTime start = CFAbsoluteTimeGetCurrent(); [[DBManager shareManager]insertDataByNomarl:testArray];
CFAbsoluteTime end=CFAbsoluteTimeGetCurrent();
NSLog(@"普通插入 time cost: %0.3f", end - start); //删除数据
[[DBManager shareManager]deleteData]; //开启事务插入
start = CFAbsoluteTimeGetCurrent(); [[DBManager shareManager]insertDataByTransaction:testArray]; end=CFAbsoluteTimeGetCurrent();
NSLog(@"开启事务插入 time cost: %0.3f", end - start); //删除数据
[[DBManager shareManager]deleteData];

测试结果:测试数据10000条 单位(秒)

开启事务耗时:0.049

未开启事务耗时:5.614

看到上面的执行结果 是不是惊呆了。

关于数据库升级:由于项目业务发展,数据库有可能要考虑到升级,比如数据库新增表或者已有表结构变化,这时候我们就要考虑到数据升级来做版本兼容:

什么时候检查:

-(instancetype)init
{
self=[super init];
if (self) {
[self creatTable];
[self upgrade];
}
return self;
}

怎么实现版本升级:

//检查数据库是否需要升级
- (void)upgrade {
//获取存储好的原版本号
NSInteger oldVersionNum = [[NSUserDefaults standardUserDefaults] integerForKey:DBVERSIONKEY];
if (DBVERSION <= oldVersionNum || oldVersionNum == ) {
return;
} //升级
[self upgrade:oldVersionNum]; // 保存新的版本号到库中 -这里大家可以使用NSUserDefault存储
[[NSUserDefaults standardUserDefaults]setInteger:DBVERSION forKey:DBVERSIONKEY];
} //根据不同版本执行不同的升级逻辑
- (void)upgrade:(NSInteger)oldVersion {
//对比数据库版本
if (oldVersion >= DBVERSION) {
return;
}
switch (oldVersion) {
case :
//执行相应的升级操作
break;
case :
//执行相应的升级操作
break;
case :
//执行相应的升级操作
break;
default:
break;
}
oldVersion ++;
// 递归判断是否需要升级
[self upgrade:oldVersion];
}

至此原生的Sqlite基础使用就告一段落了,至于高级使用一般情况涉及到的多数是sql语句的使用,sql语句不善长的小伙伴可以去熟悉一下sql数据!这时就在想了IOS有没有像Android一样的第三方数据库框架呢?也让我等sql小白缓解一下压力?特意查询了一下,以下仅供参考:Sqlitepersistentobjects ,FMDB(这个在两年前使用过)。

IOS数据存储之Sqlite数据库的更多相关文章

  1. Android数据存储之SQLite数据库

    Android数据存储 之SQLite数据库简介 SQLite的相关知识,并结合Java实现对SQLite数据库的操作. SQLite是D.Richard Hipp用C语言编写的开源嵌入式数据库引擎. ...

  2. IOS数据存储之FMDB数据库

    前言: 最近几天一直在折腾数据库存储,之前文章(http://www.cnblogs.com/whoislcj/p/5485959.html)介绍了Sqlite 数据库,SQLite是一种小型的轻量级 ...

  3. IOS 数据存储之 SQLite详解

    在IOS开发中经常会需要存储数据,对于比较少量的数据可以采取文件的形式存储,比如使用plist文件.归档等,但是对于大量的数据,就需要使用数据库,在IOS开发中数据库存储可以直接通过SQL访问数据库, ...

  4. IOS 数据存储之 SQLite具体解释

    在IOS开发中常常会须要存储数据,对于比較少量的数据能够採取文件的形式存储,比方使用plist文件.归档等,可是对于大量的数据,就须要使用数据库,在IOS开发中数据库存储能够直接通过SQL訪问数据库, ...

  5. Android 数据存储之 SQLite数据库存储

    ----------------------------------------SQLite数据库---------------------------------------------- SQLi ...

  6. 【Android 应用开发】Android 数据存储 之 SQLite数据库详解

    . 作者 :万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/19028665 . SQLiteDataBase示例程序下 ...

  7. Android之ListView,AsyncTask,GridView,CardView,本地数据存储,SQLite数据库

    版权声明:未经博主允许不得转载 补充 补充上一节,使用ListView是用来显示列表项的,使用ListView需要两个xml文件,一个是列表布局,一个是单个列表项的布局.如我们要在要显示系统所有app ...

  8. Andoid数据存储之SQLite数据库

    SQLite是一个嵌入式的并且是一个轻量级的数据库: SQLite数据库支持大部分SQL语法, 允许使用SQL语句操作数据库, 其本质是一个文件, 不需要安装启动: SQLite数据库打开只是打开了一 ...

  9. Android 数据存储 之 SQLite数据库详解

    . 作者 :万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/19028665 . SQLiteDataBase示例程序下 ...

随机推荐

  1. PHP多级联动的学习(一)

    我尝试在ThinkCMF中实现多级联动,首先我开始看了dede的联动类别管理前后台的代码以及他的数据库,经过非常多次的尝试,我渐渐有了一点想法,并给予实施. 首先写出前台的界面.如图. 然后在数据库中 ...

  2. myeclipse中source not found问题解决办法

    myeclipse中出现source not found是因为你所引用的JavaEE Generic Library没有关联源码,如下图: 下面给出该问题的解决办法: 步骤一:去下载apache-to ...

  3. Android -- PopupWindow(其中嵌套ListView 可以被点击)

    1. 效果图

  4. jQuery最基础最全面的选择器大览

    一.基本选择器     1.标签选择器 (element):根据给定的标签名匹配元素 eg:$("h2")选取所有h2元素 --- 返回元素集合 2.类选择器 (.class):根 ...

  5. SQL Server CONVERT() 截取日期

    SELECT CONVERT(varchar(100), GETDATE(), 0): 05 16 2006 10:57AMSELECT CONVERT(varchar(100), GETDATE() ...

  6. C#时间戳转换

    ,,)).ToUniversalTime ().Ticks ) / ;//先取得当前的UTC时间,然后转换成计算用的周期数(简称计时周期数),每个周期为100纳钞(ns)=0.1微秒(us)=0.00 ...

  7. Android动画

    [浅谈Android动画] 总共四种:Tween Animation变换动画.Frame Animation帧动画 Layout Animation布局动画.Property Animation 属性 ...

  8. International Conference for Smart Health 2015 Call for Papers

    Advancing Informatics for healthcare and healthcare applications has become an international researc ...

  9. iOS开发点滴:iPhone屏幕适配

    最近开始做iOS开发,遇到一些小问题和解决方法,记录下.   今天是iPhone屏幕适配 iPhone5出来之后屏幕就有iPhone就有了2种尺寸:3.5寸和4寸,xcode 5 的IB设计器里面界面 ...

  10. 跨平台移动开发UI语言 -XAML

    Xamarin.Forms 把XAML (Extensible Application Markup Language, XAML) 带进了ios,android的界面开发,也就使得使用Xamarin ...