sqllite相关总结
一,sqlite 简介
前面写了一篇博文讲如何在 C# 中使用 ADO 访问各种数据库,在移动开发和嵌入式领域也有一个轻量级的开源关系型数据库-sqlite。它的特点是零配置(无需服务器),单磁盘文件存储数据(就像fopen一样),平台无关性,使用起来简单又高效。这些特点让其非常适合移动开发和嵌入式领域。当然,sqlite 也因其力求简单高效,也就限制了它对并发,海量数据的处理。下面,我就再接再厉,来讲讲如何在 iOS 中使用 sqlite 库和第三方封装库 FMDB,以及介绍一个 MAC 下开源的可视化 sqlite 浏览器。
本文源码:https://github.com/kesalin/iOSSnippet/tree/master/SQLiteDemo
二,在 iOS 中的使用
在 iOS 中 sqlite3 库是一套纯 C 的接口,因此很方便地就可以在 obj-c 源码中无痕使用它,而且其使用方式与用 ADO 方式操作数据库大同小异-少了创建数据库链接一环而已(因为 sqlite 没有服务器的概念也就无需链接了)。
- 首先,需要引入 libsqlite3.0.dylib:

然后包含头文件:
#import "/usr/include/sqlite3.h"
- 打开或创建数据库
SQLITE_API int sqlite3_open(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
使用示例:(dbPath 为 NSString *)

// open database
//
int state = sqlite3_open([dbPath UTF8String], &database);
if (state == SQLITE_OK) {
DLOG(@" >> Succeed to open database. %@", dbPath);
}
else {
DLOG(@" >> Failed to open database. %@", dbPath);
}

- 关闭数据库
SQLITE_API int sqlite3_close(sqlite3 *);
上面这个接口将关闭数据库,如果当前还有事务没有提交,会先执行 rollback 操作,然后再关闭数据库。
- 执行 sql 语句

SQLITE_API int sqlite3_exec(
sqlite3*, /* An open database */
const char *sql, /* SQL to be evaluated */
int (*callback)(void*,int,char**,char**), /* Callback function */
void *, /* 1st argument to callback */
char **errmsg /* Error msg written here */
);

这个接口是最常用到的,几乎除了查询之外的 sql 命令都可以用它来操作,比如创建表,插入/更新/删除记录,创建/提交/回滚事务等。注意:如果 errmsg 不为 null,那么当错误发生时, sqlite 就会为错误消息分配内存,返回给调用者,调用者有责任调用 sqlite3_free 来释放这部分内存。为了方便使用,我封装了一个简单的 obj-c 方法:

- (BOOL)excuteSQLWithCString:(const char *)sqlCmd
{
char * errorMsg;
int state = sqlite3_exec(database, sqlCmd, NULL, NULL, &errorMsg);
if (state == SQLITE_OK) {
DLOG(@" >> Succeed to %@",
[NSString stringWithCString:sqlCmd encoding:NSUTF8StringEncoding]);
}
else {
DLOG(@" >> Failed to %@. Error: %@",
[NSString stringWithCString:sqlCmd encoding:NSUTF8StringEncoding],
[NSString stringWithCString:errorMsg encoding:NSUTF8StringEncoding]); sqlite3_free(errorMsg);
} return (state == SQLITE_OK);
}

下面是创建表以及事务操作的使用示例:

- (void)createTable
{
if (database == NULL) {
DLOG(@" >> Database does not open yet.");
return;
} const char * sqlCmd = "create table if not exists customer (id integer primary key autoincrement, name text not null, address text, age integer)"; [self excuteSQLWithCString:sqlCmd];
} - (BOOL)beginTransaction
{
return [self excuteSQLWithCString:"BEGIN EXCLUSIVE TRANSACTION;"];
} - (BOOL)commit
{
return [self excuteSQLWithCString:"COMMIT TRANSACTION;"];
} - (BOOL)rollback
{
return [self excuteSQLWithCString:"ROLLBACK TRANSACTION;"];
}

很简单,不是么?至于插入,更新,删除示例,请参考如下 sqlCmd:

// insert
NSString * sqlCmd = [NSString stringWithFormat:@"insert into customer (name, address, age) values ('%@', '%@', %d)",
customer.name, customer.address, customer.age]; // update
NSString * sqlCmd = [NSString stringWithFormat:@"update customer set address='%@',age=%d where name='%@'",
newValue.address, newValue.age, oldValue.name]; // delete
NSString * sqlCmd = [NSString stringWithFormat:@"delete from customer where name='%@'",
customer.name];

- 查询操作
查询操作稍微负责一点,需要创建查询描述(sqlite3_stmt),然后调用如下接口编译成字节程序:

SQLITE_API int sqlite3_prepare_v2(
sqlite3 *db, /* Database handle */
const char *zSql, /* SQL statement, UTF-8 encoded */
int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const char **pzTail /* OUT: Pointer to unused portion of zSql */
);

注意:这里使用的是 v2 - version 2,这是 sqlite 推荐使用的版本,version 1 仅仅是为了向后兼容而保留着。
然后使用如下接口来评估的查询结果:
SQLITE_API int sqlite3_step(sqlite3_stmt*);
如果该接口返回 SQLITE_ROW,表面查询到了一行记录,我们就可以以下接口从查询描述中获取我们想要的值:

SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol);
SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol);
SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol);
SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);

最后,需要通过如下接口释放先前创建的查询描述。通常,为了提高查询效率,可以把常用的查询描述缓存起来。
SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);
下面就来看一个具体的使用示例:

- (NSArray *)queryAllCustomers
{
NSMutableArray * array = [[NSMutableArray alloc] init]; const char * sqlCmd = "select name, address, age from customer";
sqlite3_stmt * statement;
int state = sqlite3_prepare_v2(database, sqlCmd, -1, &statement, nil);
if (state == SQLITE_OK) {
DLOG(@" >> Succeed to prepare statement. %@",
[NSString stringWithCString:sqlCmd encoding:NSUTF8StringEncoding]);
} NSInteger index = 0;
while (sqlite3_step(statement) == SQLITE_ROW) {
// get raw data from statement
//
char * cstrName = (char *)sqlite3_column_text(statement, 0);
char * cstrAddress = (char *)sqlite3_column_text(statement, 1);
int age = sqlite3_column_int(statement, 2); NSString * name = [NSString stringWithCString:cstrName encoding:NSUTF8StringEncoding];
NSString * address = [NSString stringWithCString:cstrAddress encoding:NSUTF8StringEncoding];
KSCustomer * customer = [[KSCustomer alloc]
initWith:name
address:address
age:age];
[array addObject:customer]; DLOG(@" >> Record %d : %@ %@ %d", index++, name, address, age);
} sqlite3_finalize(statement); DLOG(@" >> Query %d records.", [array count]);
return array;
}

三,MAC 下查看 sqlite db 文件的工具
MAC 下有一款不错的开源可视化 sqlite db 浏览器:SQLite Database Browser,你可以从以下链接获取:
http://sourceforge.net/projects/sqlitebrowser/
该软件运行界面如下:

四,封装 sqlite 的第三方库 FMDB
在 iOS 中直接使用 sqlite 原生 C 接口还是不那么方便,因此催生了第三方的 iOS 版封装库,其中使用比较广泛又轻量级的就是 FMDB(https://github.com/ccgus/fmdb),目前该库只有六个文件,不超过2000行代码。
使用也是非常简单,在工程中包含这六个文件:

然后包含头文件:
#import "FMDatabase.h"
#import "FMResultSet.h"
#import "FMDatabaseAdditions.h"
就可以使用该库了:

// Create database
//
NSString * path = [UIHUtilities configPathFor:kDatabaseFile];
FMDatabase db = [[FMDatabase databaseWithPath:path] retain]; if (![db open])
{
DLog(@" >> Error: Failed to open database at %@", path);
} #if DEBUG
db.traceExecution = TRUE;
#endif // Create tables
//
[db executeUpdate:@"CREATE TABLE Image (studyUid text, patientId text, seriesUid text, SOPUid text, contentDate text, modality text, patientPosition text, filepath text, thumbnailPath text)"]; // insert
//
BOOL retValue = [db executeUpdate:@"INSERT INTO Image (studyUid, patientId, seriesUid, SOPUid, contentDate, patientPosition, modality, filepath, thumbnailPath) VALUES (?,?,?,?,?,?,?,?,?)", image.studyUid, image.patientId, image.seriesUid, image.SOPUid, image.contentDate, image.patientPosition, image.modality, image.filepath, image.thumbnailPath]; if (!retValue)
DLog(@" >> Error: Database failed to insert image %@", image); // query
//
FMResultSet *rs = [db executeQuery:@"SELECT * FROM Image WHERE SOPUid = ?", SOPUid];
if ([rs next])
{
....
} // query count
//
NSInteger count = 0;
FMResultSet *rs = [db executeQuery:@"SELECT COUNT(*) FROM Image WHERE seriesUid = ?", seriesUid];
if ([rs next]) {
count = [rs intForColumnIndex:0];
} // delete
//
retValue = [db executeUpdate:@"DELETE FROM Image WHERE seriesUid = ?", seriesUid];
if (!retValue)
DLog(@" >> Error: Database failed to delete image by seriesUid %@", seriesUid); // release database
//
[db release];

sqllite相关总结的更多相关文章
- ELMAH入门
简介 ELMAH(Error Logging Modules and Handlers)错误日志记录模块和处理程序,是一种应用广泛的错误日志工具是完全可插拔.它可以动态添加到一个正在运行的ASP.NE ...
- sqlite3 解决并发读写冲突的问题
#include "stdafx.h" #include "sqlite3.h" #include <iostream> #include < ...
- 嵌入式单片机STM32应用技术(课本)
目录SAIU R20 1 6 第1页第1 章. 初识STM32..................................................................... ...
- 使用C#访问SQLLite
1.SQLLite如何集成在C#中 2.相关C#与SQLLite资源,及说明 3.简单示例
- 站点发布到 IIS 后,System.Data.SqlLite.dll 末找到
近来在部署一个站点到客户的服务器 IIS 上时,打开后却出现一个错误的页面,系统提示System.Data.SqlLite.dll 末找到,在站点部署到客户的服务器之前时,在本地测试,却没有发现什么异 ...
- QT 读写sqllite数据库
QT 读写sqllite数据库 分类: 技术资料2014-04-10 10:39 84人阅读 评论(0) 收藏 举报 #include <QtGui/QApplication> #incl ...
- SQLLite 简介
[1] SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内 ...
- SQL Server数据库读取数据的DateReader类及其相关类
之前学了几天的SQL Server,现在用C#代码连接数据库了. 需要使用C#代码连接数据库,读取数据. 涉及的类有: ConfigurationManage SqlConnection SqlCom ...
- MySql的相关资操作
01-MySql的前戏 MySql的前戏 在学习Mysql之前,我们先来想一下一开始做的登录注册案例,当时我们把用户的信息保存到一个文件中: #用户名 |密码root|123321 alex|12 ...
随机推荐
- python的partition() 方法
描述 partition() 方法用来根据指定的分隔符将字符串进行分割. 如果字符串包含指定的分隔符,则返回一个3元的元组,第一个为分隔符左边的子串,第二个为分隔符本身,第三个为分隔符右边的子串. p ...
- 07_传智播客iOS视频教程_#import指令
mac切换中英文输入法默认是Ctrl+空格键. 预处理指令的执行时机是在编译之前.在编译之前执行预处理指令. #import指令是包含文件,将指定的文件的内容在预编译的时候拷贝到写指令的地方. #im ...
- WordPress xmlrpc.php flaw exploited to install a WSO 2.1 Web Shell by oRb
WordPress xmlrpc.php flaw exploited to install a “WSO 2.1 Web Shell by oRb” Below you can see in the ...
- TransposonPSI——转座子分析的入门自学
最近需要做转座子分析,查找发现可以使用 TransposonPSI 来进行分析.但是登陆官网,该软件 update 时间为 2013 年,但是因为时间紧迫,暂时还没有进行其他方法的调研,所以先选用该软 ...
- bzoj 4071: [Apio2015]巴邻旁之桥【splay】
用权值线段树会容易一些并快一些,但是想复健一下splay所以打了splay 然后果然不会打了. 解题思路: 首先把家和办公室在同一侧的提出来直接加进答案里: 对于k=1,直接选所有办公室和家的中位数即 ...
- poj 1061 青蛙约会(扩展欧几里德)
题目链接: http://poj.org/problem?id=1061 题目大意: 中文题目,题意一目了然,就是数据范围大的出奇. 解题思路: 假设两只青蛙都跳了T次,可以列出来不定方程:p*l + ...
- 题解报告:hdu 1114 Piggy-Bank(完全背包恰好装满)
Problem Description Before ACM can do anything, a budget must be prepared and the necessary financia ...
- Android推送服务(2)微信智能心跳方案
http://mp.weixin.qq.com/s?__biz=MzAwNDY1ODY2OQ==&mid=207243549&idx=1&sn=4ebe4beb8123f1b5 ...
- CoreText的绘制流程-转
来自:http://blog.sina.com.cn/s/blog_7c8dc2d50101lbb1.html 使用coreText进行文本绘制,需要在工程中添加CoreText.framework, ...
- CSS综合用法
div 居中 {position: absolute; top: 50%; left: 50%; margin-top: -180px; margin-left: -160px;}