1:常用接口
个人比较喜欢sqlite, 使用最方便,唯一的准备工作是下载250K的源;而且作者很热心,有问必答。
以下演示一下使用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类型的数据
…
2: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 不做任何转换的数据列类型
实例代码如下,
附件工程可直接编译,例子使用了blob数据类型。
#include "sqlite3.h" //包含一个头文件就可以使用所以sqlite的接口了
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#pragma comment(lib, "sqlite.lib") //我把sqlite编译成了一个静态的lib文件。
void createdb();
void querydb();
int main()
{
createdb();
querydb();
return 0;
}
void createdb()
{
int ret;
sqlite3 *pdb = 0;
sqlite3_stmt *stmt = 0;
char *error = 0;
char *sql = "insert into table1 values('value11',:aaa)";
int index;
static void *value = "asdfadsfasdfjasdfjaksdfaskjdfakdsfaksfja";
ret = sqlite3_open("db1.sdb", &pdb); //打开数据库,跟打开文本文件一样
if( ret != SQLITE_OK )
return;
ret = sqlite3_exec(pdb, "create table table1(col1 char(20), col2 BLOB)", 0,0, &error );
if( ret != SQLITE_OK )
return;
ret = sqlite3_prepare(pdb, sql,strlen(sql), &stmt, &error);
if( ret != SQLITE_OK )
return;
index = sqlite3_bind_parameter_index(stmt, ":aaa");
ret = sqlite3_bind_blob(stmt, index, value, strlen(value), SQLITE_STATIC);
if( ret != SQLITE_OK )
return;
ret = sqlite3_step(stmt);
if( ret != SQLITE_DONE )
return;
sqlite3_close(pdb);
}
void querydb()
{
int ret;
sqlite3 *pdb = 0;
sqlite3_stmt *pstmt = 0;
char *error = 0;
char *sql = "select * from table1";
int len;
int i;
char *name;
void *value;
ret = sqlite3_open("db1.sdb", &pdb);
if( ret != SQLITE_OK )
return;
ret = sqlite3_prepare(pdb, sql, strlen(sql), &pstmt, &error);
if( ret != SQLITE_OK )
return;
while( 1 )
{
ret = sqlite3_step(pstmt);
if( ret != SQLITE_ROW )
break;
name = sqlite3_column_text(pstmt, 0);
value = sqlite3_column_blob(pstmt, 1);
len = sqlite3_column_bytes(pstmt,1 );
}
}
实例二:SQLite中如何用api操作blob类型的字段
在实际的编程开发当中我们经常要处理一些大容量二进制数据的存储,如图片或者音乐等等。对于这些二进制数据(blob字段)我们不能像处理普通的文本那样简单的插入或者查询,为此SQLite提供了一组函数来处理这种BLOB字段类型。下面的代码演示了如何使用这些API函数。
首先我们要建立一个数据库:
sqlite3_exec(db, "CREATE TABLE list (fliename varchar(128) UNIQUE, fzip blob);", 0, 0, &zErrMsg);
//由于mmmm.rar是一个二进制文件,所以要在使用insert语句时先用?号代替
sqlite3_prepare(db, "insert into list values ('mmmm.rar',?);", -1, &stat, 0);
FILE *fp;
long filesize = 0;
char * ffile;
fp = fopen("mmmm.rar", "rb");
if(fp != NULL)
{
//计算文件的大小
fseek(fp, 0, SEEK_END);
filesize = ftell(fp);
fseek(fp, 0, SEEK_SET);
//读取文件
ffile = new char[filesize+1];
size_t sz = fread(ffile, sizeof(char), filesize+1, fp);
fclose(fp);
}
//将文件数据绑定到insert语句中,替换“?”部分
sqlite3_bind_blob(stat, 1, ffile, filesize, NULL);
//执行绑定之后的SQL语句
sqlite3_step(stat);
这时数据库当中已经有了一条包含BLOB字段的数据。接下来我们要读取这条数据:
//选取该条数据
sqlite3_prepare(db, "select * from list;", -1, &stat, 0);
sqlite3_step(stat);
//得到纪录中的BLOB字段
const void * test = sqlite3_column_blob(stat, 1);
//得到字段中数据的长度
int size = sqlite3_column_bytes(stat, 1);
//拷贝该字段
sprintf(buffer2, "%s", test);
此时可以将buffer2写入到文件当中,至此BLOB数据处理完毕。
实例三:sqlite 中用blob存储图片和取出图片
#include<iostream>
#include<string>
#include<sqlite3.h>
using namespace std;
int main()
{
sqlite3 *db;
sqlite3_stmt *stat;
char *zErrMsg = 0;
char buffer2[1024]="0";
sqlite3_open("./MetaInfo.db", &db);
int result;
if(result)
{
cout<<"Open the database sqlite.db failed"<<endl;
}
else
cout<<"Open the database sqlite.db sucessfully"<<endl;
sqlite3_exec(db, "CREATE TABLE list (fliename varchar(128) UNIQUE, fzip blob);", 0, 0, &zErrMsg);
sqlite3_prepare(db, "insert into list values ('./data/2.bmp',?);", -1, &stat, 0);
FILE *fp;
long filesize = 0;
char * ffile;
fp = fopen("./data/2.bmp", "rb");
if(fp != NULL)
{
fseek(fp, 0, SEEK_END);
filesize = ftell(fp);
fseek(fp, 0, SEEK_SET);
ffile = new char[filesize+1];
size_t sz = fread(ffile, sizeof(char), filesize+1, fp);
fclose(fp);
}
sqlite3_bind_blob(stat, 1, ffile, filesize, NULL);
sqlite3_step(stat);
sqlite3_prepare(db, "select * from list;", -1, &stat, 0);
sqlite3_step(stat);
const void * test = sqlite3_column_blob(stat, 1);
int size = sqlite3_column_bytes(stat, 1);
sprintf(buffer2, "%s", test);
FILE *fp2;
fp2 = fopen("outfile.png", "wb");
if(fp2 != NULL)
{
size_t ret = fwrite(test, sizeof(char), size, fp2);
fclose(fp2);
}
delete(ffile);
sqlite3_finalize(stat);
sqlite3_close(db);
return 0;
}
从sqlite数据库中检查某个表是否已经被创建
SQLite数据库的框架被保存在一个名叫"sqlite_master"的特殊的表中。你可以像查询其它表一样通过执行“SELECT”查询这个特殊的表。比如说我要查一个表是否已经在数据库中被创建:
//tableName 表的名字
- (BOOL) isNeedCreateTable:(NSString *)tableName db:(sqlite3*)db{
sqlite3_stmt *statement = nil;
NSString *sqlObjcStr = [NSString stringWithFormat:@"SELECT COUNT(*) FROM sqlite_master WHERE type='table' and name='%@'",
tableName
];
const char *sql = [sqlObjcStr UTF8String];
if (sqlite3_prepare_v2(db, sql, -1, &statement, NULL) != SQLITE_OK) {
NSLog(@"Error: failed to prepare statement with message:checkTable.");
return YES;
}
int iNumber = 0;
while (sqlite3_step(statement) == SQLITE_ROW) {
iNumber = (int)sqlite3_column_int(statement, 0);
}
sqlite3_finalize(statement);
if(iNumber == 0){
return YES;
}
return NO;
}