IOS数据存储之Sqlite数据库
前言:
之前学习了数据存储的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数据库的更多相关文章
- Android数据存储之SQLite数据库
Android数据存储 之SQLite数据库简介 SQLite的相关知识,并结合Java实现对SQLite数据库的操作. SQLite是D.Richard Hipp用C语言编写的开源嵌入式数据库引擎. ...
- IOS数据存储之FMDB数据库
前言: 最近几天一直在折腾数据库存储,之前文章(http://www.cnblogs.com/whoislcj/p/5485959.html)介绍了Sqlite 数据库,SQLite是一种小型的轻量级 ...
- IOS 数据存储之 SQLite详解
在IOS开发中经常会需要存储数据,对于比较少量的数据可以采取文件的形式存储,比如使用plist文件.归档等,但是对于大量的数据,就需要使用数据库,在IOS开发中数据库存储可以直接通过SQL访问数据库, ...
- IOS 数据存储之 SQLite具体解释
在IOS开发中常常会须要存储数据,对于比較少量的数据能够採取文件的形式存储,比方使用plist文件.归档等,可是对于大量的数据,就须要使用数据库,在IOS开发中数据库存储能够直接通过SQL訪问数据库, ...
- Android 数据存储之 SQLite数据库存储
----------------------------------------SQLite数据库---------------------------------------------- SQLi ...
- 【Android 应用开发】Android 数据存储 之 SQLite数据库详解
. 作者 :万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/19028665 . SQLiteDataBase示例程序下 ...
- Android之ListView,AsyncTask,GridView,CardView,本地数据存储,SQLite数据库
版权声明:未经博主允许不得转载 补充 补充上一节,使用ListView是用来显示列表项的,使用ListView需要两个xml文件,一个是列表布局,一个是单个列表项的布局.如我们要在要显示系统所有app ...
- Andoid数据存储之SQLite数据库
SQLite是一个嵌入式的并且是一个轻量级的数据库: SQLite数据库支持大部分SQL语法, 允许使用SQL语句操作数据库, 其本质是一个文件, 不需要安装启动: SQLite数据库打开只是打开了一 ...
- Android 数据存储 之 SQLite数据库详解
. 作者 :万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/19028665 . SQLiteDataBase示例程序下 ...
随机推荐
- PHP多级联动的学习(一)
我尝试在ThinkCMF中实现多级联动,首先我开始看了dede的联动类别管理前后台的代码以及他的数据库,经过非常多次的尝试,我渐渐有了一点想法,并给予实施. 首先写出前台的界面.如图. 然后在数据库中 ...
- myeclipse中source not found问题解决办法
myeclipse中出现source not found是因为你所引用的JavaEE Generic Library没有关联源码,如下图: 下面给出该问题的解决办法: 步骤一:去下载apache-to ...
- Android -- PopupWindow(其中嵌套ListView 可以被点击)
1. 效果图
- jQuery最基础最全面的选择器大览
一.基本选择器 1.标签选择器 (element):根据给定的标签名匹配元素 eg:$("h2")选取所有h2元素 --- 返回元素集合 2.类选择器 (.class):根 ...
- SQL Server CONVERT() 截取日期
SELECT CONVERT(varchar(100), GETDATE(), 0): 05 16 2006 10:57AMSELECT CONVERT(varchar(100), GETDATE() ...
- C#时间戳转换
,,)).ToUniversalTime ().Ticks ) / ;//先取得当前的UTC时间,然后转换成计算用的周期数(简称计时周期数),每个周期为100纳钞(ns)=0.1微秒(us)=0.00 ...
- Android动画
[浅谈Android动画] 总共四种:Tween Animation变换动画.Frame Animation帧动画 Layout Animation布局动画.Property Animation 属性 ...
- International Conference for Smart Health 2015 Call for Papers
Advancing Informatics for healthcare and healthcare applications has become an international researc ...
- iOS开发点滴:iPhone屏幕适配
最近开始做iOS开发,遇到一些小问题和解决方法,记录下. 今天是iPhone屏幕适配 iPhone5出来之后屏幕就有iPhone就有了2种尺寸:3.5寸和4寸,xcode 5 的IB设计器里面界面 ...
- 跨平台移动开发UI语言 -XAML
Xamarin.Forms 把XAML (Extensible Application Markup Language, XAML) 带进了ios,android的界面开发,也就使得使用Xamarin ...