Android数据库代码优化(2) - 从SQLite说起
从SQLite说起
如果没有SQLite的基础,我们只是从Android封装的SQLite API去学习的话,难免思路会受到限制。所以,我们还是需要老老实实从头开始学习SQLite.
当我们有一身的SQLite武功之后,再去看Android的封装,就能更清楚如何发挥SQLite的特长。
SQLite的核心只有一个c文件,访问的db也存在一个文件当中。所以,我们完全可以把它嵌入到另外一个程序中。
在mac上,可以通过Homebrew来安装。安装之后,我们就可以用sqlite3的API来写代码了。
先来个能编过的sqlite3调用例子吧
我们找个网上找到的最简单的打开关闭SQLite数据库的例子:
#include <stdio.h>
#include <sqlite3.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
sqlite3 *db;
char *zErrMsg = 0;
int rc;
rc = sqlite3_open("contacts.db", &db);
if (rc)
{
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
exit(0);
}
else
{
fprintf(stderr, "Opened database successfully\n");
}
sqlite3_close(db);
}
我们先不管它是什么意思,先编译一下试试:
gcc -o test_sqlite test.c -lsqlite3
然后运行一下吧,需要本地有个叫contacts.db的数据库。
./test_sqlite
输出为:
Opened database successfully
从上面的例子,我们可以学习到两个容易理解的API: sqlite3_open和sqlite3_close.
SQLite3是一个基于VDBE的数据库引擎
有了能运行的环境之后,我们就来看看SQLite数据库引擎的结构吧:
从这张官方图上,我们可以看到,除了工具和测试代码之外,SQLite的核心部分分为三部分:核心,编译器和后端。
核心部分就是对SQL命令的处理的部分,它通过编译器来编译成VDBE(Virtual Database Engine)能执行的代码。
后端是真正对数据库进行操作的部分,包括B-树的查找结构等。
喜欢划重点的同学注意啦,重点来了:调用SQLite3数据库的代码优化的第一个点就是将编译好的字节码保存起来,下次用的时候直接调用。
这么重要的功能,SQLite3 API中当然有提供,这就是后面我们会大量学习使用的sqlite3_prepare和sqlite3_prepare_v2函数。
Android对此也有同样的封装,提供了SQLiteStatement来实现预编译代码的保存。
有同学问了,我的SQL语句并不是一成不变的,语句中的参数经常改变,这样的话,编译出来的代码就没有用了啊?
这在SQLite3的设计中当然是有考虑到的,编译好的语句,是可以支持参数的。我们首先使用sqlite3_prepare_v2编译,然后再通过sqlite3_bind_*函数来绑定参数。下次如果换了参数,先调用sqlite3_reset清除掉绑定信息,然后再重新用sqlite3_bind_*来做绑定新参数,就可以了。
一个调用sqlite3实现数据库操作的功能可以用下面的步骤来套用:
1. 根据业务需求,构造sql语句
2. 调用sqlite3_prepare_v2函数来编译sql语句
3. 如果有参数,调用sqlite3_bind_*函数来绑定参数
4. 调用sqlite3_step函数来执行一次sql操作,直至所有操作都完成
5. 下次再使用第2步编译出来的语句时,调用sqlite3_reset函数清理参数。然后重复第3步的操作
6. 最后,调用sqlite3_finalize来销毁预编译语句
下面我们直接开始实操,首先先举个select的例子。
我们以Android中联系人数据库为例,取其中的calls表的简化版:
CREATE TABLE calls (
_id INTEGER PRIMARY KEY AUTOINCREMENT,
sourceid TEXT,
number TEXT
...
);
虽然字段很多,我们就关注id和号码就好。
如何写查询语句
我们先来一半,我们选_id和number这两列,然后看看返回的数据中是不是两列:
核心代码如下:
rc = sqlite3_prepare_v2(db, sql_select_caller, -1, &stmt, &tail);
rc = sqlite3_step(stmt);
int ncols = sqlite3_column_count(stmt);
printf("The column counts of calls is:%d\n", ncols);
sqlite3_finalize(stmt);
完整版的代码,便于大家实验:
#include <stdio.h>
#include <sqlite3.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
sqlite3 *db;
char *zErrMsg = 0;
int rc;
const char *sql_select_caller = "select _id, number from calls";
sqlite3_stmt *stmt;
const char *tail;
rc = sqlite3_open("contacts.db", &db);
if (rc)
{
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
exit(0);
}
else
{
fprintf(stderr, "Opened database successfully\n");
}
//select _id, number from calls
rc = sqlite3_prepare_v2(db, sql_select_caller, -1, &stmt, &tail);
rc = sqlite3_step(stmt);
int ncols = sqlite3_column_count(stmt);
printf("The column counts of calls is:%d\n", ncols);
sqlite3_finalize(stmt);
sqlite3_close(db);
}
下面我们直接调用sqlite3_step去读每一条记录,增加下面一段:
while(rc == SQLITE_ROW){
printf("calls ID=%d,\t",sqlite3_column_int(stmt,0));
printf("number=%s\n",sqlite3_column_text(stmt,1));
rc = sqlite3_step(stmt);
}
如果sqlite3_step返回的结果是SQLITE_ROW,说明这一次执行取到了一条符合条件的记录。每次取一条记录。
完整代码如下:
#include <stdio.h>
#include <sqlite3.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
sqlite3 *db;
char *zErrMsg = 0;
int rc;
const char *sql_select_caller = "select _id, number from calls";
sqlite3_stmt *stmt;
const char *tail;
rc = sqlite3_open("contacts.db", &db);
if (rc)
{
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
exit(0);
}
else
{
fprintf(stderr, "Opened database successfully\n");
}
//select _id, number from calls
rc = sqlite3_prepare_v2(db, sql_select_caller, -1, &stmt, &tail);
rc = sqlite3_step(stmt);
int ncols = sqlite3_column_count(stmt);
printf("The column counts of calls is:%d\n", ncols);
while (rc == SQLITE_ROW)
{
printf("calls ID=%d,\t", sqlite3_column_int(stmt, 0));
printf("number=%s\n", sqlite3_column_text(stmt, 1));
rc = sqlite3_step(stmt);
}
sqlite3_finalize(stmt);
sqlite3_close(db);
}
输出如下例:
The column counts of calls is:2
calls ID=1, number=18600009876
calls ID=2, number=18600019876
calls ID=3, number=18600029876
calls ID=4, number=18600039876
calls ID=5, number=18600049876
calls ID=6, number=18600059876
calls ID=7, number=18600069876
calls ID=8, number=18600079876
calls ID=9, number=18600089876
calls ID=10, number=18600099876
如何写非查询语句
上面的例子是针对查询语句的,我们再举个非查询语句的例子。比如我们试个插入的例子。
void insert_item(sqlite3 *db)
{
const char *sql_insert_sample = "insert or ignore into calls (_id,number) values (?1,?2);";
sqlite3_stmt *stmt = NULL;
const char *tail = NULL;
int rc = sqlite3_prepare_v2(db, sql_insert_sample, -1, &stmt, &tail);
sqlite3_bind_int(stmt, 1, 1000);
sqlite3_bind_text(stmt, 2, "01084993677", 11, NULL);
rc = sqlite3_step(stmt);
if (rc == SQLITE_DONE)
{
printf("Last inserted row id=%ld\n", (long)sqlite3_last_insert_rowid(db));
}
else
{
printf("Insert failed!");
}
sqlite3_finalize(stmt);
}
输出如下:
Last inserted row id=0
小结
上面,我们就查询和非查询两种情况,学习了如何使用SQLite3的API。
剩下的工作主要就是构造SQL语句以及处理返回结果了。
Android数据库代码优化(2) - 从SQLite说起的更多相关文章
- Android数据库高手秘籍(一)——SQLite命令
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/38461239 要想熟练地操作不论什么一个数据库.最最主要的要求就是要懂SQL语言, ...
- Android数据库高手秘籍:SQLite命令
要想熟练地操作任何一个数据库,最最基本的要求就是要懂SQL语言,这也是每个程序员都应该掌握的技能.虽说SQL博大精深,要想精通确实很难,但最基本的一些建表命令,增删改查,大家还是必须要学会的. SQL ...
- Android数据库代码优化(1) - 从Google的数据库guide说起
假如我们没有任何在Android上使用SQLite的经验,现在要开始在工作中用SQLite存储一些数据.OK, 我们去看google的官方培训文档吧,http://developer.android. ...
- Android数据库高手秘籍(零)——前言
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/38083103 在我刚開始接触Android的时候甚至都不敢相信.Android系统 ...
- Android数据库高手秘籍(二):创建表和LitePal的基本用法
原文:http://blog.jobbole.com/77157/ 上一篇文章中我们学习了一些Android数据库相关的基础知识,和几个颇为有用的SQLite命令,都是直接在命令行操作的.但是我们都知 ...
- 深入解析Sqlite的完美替代者,android数据库新王者——Realm
写在前面: 又到一年一度七夕虐狗节,看着大家忍受着各种朋友圈和QQ空间还有现实生活中的轮番轰炸,我实在不忍心再在这里给大家补刀,所以我觉得今天不虐狗,继续给大家分享有用的. 如果你比较关心androi ...
- Android内部自带的SQLite数据库操作dos命令
1:什么叫做SQLite数据库 Android系统内核是Linux系统,Android系统很特殊,他自带了一个SQLite数据库,轻量型的一款嵌入式的数据库 它占用资源非常的低,在嵌入式设备中,可能只 ...
- Android数据库之SQLite数据库
Android数据库之SQLite数据库 导出查看数据库文件 在android中,为某个应用程序创建的数据库,只有它可以访问,其它应用程序是不能访问的,数据库位于Android设备/data/data ...
- Android数据库框架——GreenDao轻量级的对象关系映射框架,永久告别sqlite
Android数据库框架--GreenDao轻量级的对象关系映射框架,永久告别sqlite 前不久,我在写了ORMLite这个框架的博文 Android数据库框架--ORMLite轻量级的对象关系映射 ...
随机推荐
- 前端基础之jQuery(Day55)
阅读目录 一 jQuery是什么? 二 什么是jQuery对象? 三 寻找元素(选择器和筛选器) 四 操作元素(属性,css,文档处理) 扩展方法 (插件机制) 一. jQuery是什么? [1] ...
- JVM内存杂记1
大多数 JVM 将内存区域划分为 Method Area(Non-Heap)(方法区) ,Heap(堆) , Program Counter Register(程序计数器) , VM Stack( ...
- 对 java 设计模式的一些了解 (正在学习整理中)
A .设计模式的作用 从书上摘话给你们看看 帮助我们将应用组织成容易了解,容易维护,具有弹性的架构,建立可维护的OO系统,要诀在于随时想到系统以后可能需要的变化以及应付变化的原则. 这么复杂的解释肯定 ...
- Sybase:循环调用存储过程
Sybase:循环调用存储过程 一.日期循环 declare @c_count int declare @rq int --获取两个日期之间的天数 ,getdate()) begin ,),),),) ...
- Python3.x:pyodbc调用sybase的存储过程
Python3.x:pyodbc调用sybase的存储过程 示例代码 # python3 # author lizm # datetime 2018-03-02 17:00:00 # -*- codi ...
- wyx20162314实验报告二
北京电子科技学院BESTI实验报告 课程:程序设计与数据结构 班级: 1623 姓名: 王译潇 学号:20162310 指导教师:娄佳鹏老师.王志强老师 实验日期:2017年3月26号 实验密级: 非 ...
- shell-一些有趣的使用
1. 对字符串进行MD5加密 echo test |md5sum|awk '{print $1}' 字符串数量很多时可以这样做: echo test |md5sum|awk '{print $1}' ...
- 使用Kali Linux 破解无线网
用到的工具 airmon-ngairodump-ngaireplay-ngaircrack-ng 过程 123456789101112131415161718192021222324 root@lm: ...
- sed 案例
sed:Stream Editor文本流编辑,sed是一个“非交互式的”面向字符流的编辑器.能同时处理多个文件多行的内容,可以不对原文件改动,把整个文件输入到屏幕,可以把只匹配到模式的内容输入到屏幕上 ...
- LeetCode——Detect Capital
LeetCode--Detect Capital Question Given a word, you need to judge whether the usage of capitals in i ...