
1. 把数据库分解成几个asset文件。
2. 当需要打开数据库时,如果数据库不存在,就把那几个asset文件重新合并成一个数据库文件。
3. 如果数据库的版本改变了,就在onUpgrade()方法中嫌颂把数据库文件删除掉。
下面是代码:
//数据库的纤燃缺省路径
private static finalString DB_PATH = "/data/data/com.mypackage.myapp/databases/"
private static finalString DB_NAME = "mydb.db"
private static finalint DB_VERSION = 2
private static finalString DB_SPLIT_NAME = "mydb.db.00"
private static finalint DB_SPLIT_COUNT = 3
private SQLiteDatabasem_database
private final Contextm_context
/**
* Constructor
*保存传进来的context参数以用来访问应用的asset和资源文件。
* @param context
*/
public MyDB(Contextcontext) {
super(context, DB_NAME, null, DB_VERSION)
this.m_context = context
}
public static MyDBopenDatabaseReadOnly(Context context) {
MyDB db = new MyDB(context)
try {
db.createDataBase()
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace()
}
db.openDataBase(SQLiteDatabase.OPEN_READONLY)
return db
}
public static MyDBopenDatabaseReadWrite(Context context) {
MyDB db = new MyDB(context)
try {
db.createDataBase()
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace()
}
db.openDataBase(SQLiteDatabase.OPEN_READWRITE)
return db
}
/**
*创建一个空数据库,用来存储你已有的数据库。
*/
public voidcreateDataBase() throws IOException{
boolean dbExist =checkDataBase()
if (dbExist) {
/*
**如果你的数据库的版本改变了,调用这个方法确保在onUpgrade()被调用时
**传进芹竖郑去的是可写的数据库。
*/
SQLiteDatabase db =this.getWritableDatabase()
if (db != null) {
db.close()
}
}
dbExist = checkDataBase()
if (!dbExist) {
try {
/*
** 调用这个方法以确保在缺省路径内产生一个空数据库,以便在其基础上复制我们已有的数据库。
*/
SQLiteDatabase db =this.getReadableDatabase()
if (db != null) {
db.close()
}
copyDataBase()
}
catch (IOException e) {
Log.e("DB", e.getMessage())
throw new Error("Error copyingdatabase")
}
}
}
/**
* 检查数据库是否已存在,以避免重复复制。
* @return true if it exists, false if itdoesn't
*/
private static booleancheckDataBase(){
SQLiteDatabase checkDB = null
try {
String path = DB_PATH + DB_NAME
checkDB =SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READONLY)
}
catch (SQLiteException e){
//database does't exist yet.
}
if (checkDB != null) {
checkDB.close()
}
return checkDB != null ? true : false
}
/**
* 把存在asset文件中的数据库复制的刚创建的空数据库中。
* */
private voidcopyDataBase() throws IOException {
// 刚创建的空数据库的路径
String outFileName = DB_PATH + DB_NAME
// 打开空数据库
OutputStream output = new FileOutputStream(outFileName)
byte[] buffer = new byte[1024*8]
AssetManager assetMgr =m_context.getAssets()
for (int i = 1i <= DB_SPLIT_COUNTi++){
// 打开分解的asset文件
String fn = DB_SPLIT_NAME +String.valueOf(i)
InputStream input = assetMgr.open(fn)
//Log.i("DB", "opened" + fn)
int length
while ((length = input.read(buffer)) >0) {
//Log.i("DB", "read" + String.valueOf(length))
output.write(buffer, 0, length)
//Log.i("DB", "write" + String.valueOf(length))
}
input.close()
}
//Close the streams
output.flush()
output.close()
}
/**
sqllite属于轻量级的数据库,因为它足够小,可以放在androidapp中使用。
使用它用来存储返稿数据和姿的,相比其他数据库,都唤世绝需要在pc上配置环境,没法移植到app程序中。SQLite3是目前最新的SQLite版本。可以从网站上下载SQLite3的源代码(本书使用的版本是sqlite-3.6.12.tar.gz)。解压缩后进入sqlite-3.6.12的根目录,首先命令“./configure”生成Makefile文件,接着运行命令“make”对源代码进行编译,最后运行命令“make install”安装SQLite3。安装完毕后,可以运行命令sqlite3查看SQLite3是否能正常运行,如下所示:
[root@localhost ~]# sqlite3
SQLite version 3.6.12
Enter ".help" for instructions
Enter SQL statements terminated with a ""
sqlite>
可以看到,SQLite3启动后会停留在提示符sqlite>处,等待用户输入SQL语句。
在使用SQLite3前需要先了解下SQLite3支持的数据类型。SQLite3支持的基本数据类型主要态裂有以下几类:
NULL
NUMERIC
INTEGER
REAL
TEXT
SQLite3会自动把其他数据类型转换成以上5类基本数据类型,转换规则如下所示:
char、clob、test、varchar—>TEXT
integer—>INTEGER
real、double、float—>REAL
blob—>NULL
其余数据类型都转变成NUMERIC
下面通过一个实例来演示SQLite3的使用方法。
新建一个数据库
新建数据库test.db(使用.db后缀是为了标识数据库文件)。在test.db中新建一个表test_table,该表具有name,、sex、age三列。SQLite3的具体 *** 作如下所示:
[root@localhost home]# sqlite3 test.db
SQLite version 3.6.12
Enter ".help" for instructions
Enter SQL statements terminated with a ""
sqlite>create table test_table(name, sex, age)
如果数据库test.db已经存在,则命令“sqlite3 test.db”会在当前目录下打开test.db。如果数据库test.db不存在,则命令“sqlite3 test.db”会在当前目录下新建数据库test.db。为了提高效率,SQLite3并不会马上创建test.db,而是等到第一个表创建完成后才会燃闭敬在物理上创建数据库。
由于SQLite3能根据插入数据的实际类型动态改变列的类型,所以在create语句中并不要求给出列的类型。
创建索引
皮慎 为了加快表的查询速度,往往在主键上添加索引。如下所示的是在name列上添加索引的过程。
sqlite>create index test_index on test_table(name)
*** 作数据
如下所示的是在test_table中进行数据的插入、更新、删除 *** 作:
sqlite>insert into test_table values ('xiaoming', 'male', 20)
sqlite>insert into test_table values ('xiaohong', 'female', 18)
sqlite>select * from test_table
xiaoming|male|20
xiaohong|female|18
sqlite>update test_table set age=19 where name = 'xiaohong'
sqlite>select * from test_table
xiaoming|male|20
xiaohong|female|19
sqlite>delete from test_table where name = 'xiaoming'
sqlite>select * from test_table
xiaohong|female|19
批量 *** 作数据库
如下所示的是在test_table中连续插入两条记录:
sqlite>begin
sqlite>insert into test_table values ('xiaoxue', 'female', 18)
sqlite>insert into test_table values ('xiaoliu', 'male', 20)
sqlite>commit
sqlite>select * from test_table
xiaohong|female|19
xiaoxue|male|18
xiaoliu|male|20
运行命令commit后,才会把插入的数据写入数据库中。
数据库的导入导出
如下所示的是把test.db导出到sql文件中:
[root@localhost home]# sqlite3 test.db ".dump" >test.sql
test.sql文件的内容如下所示:
BEGIN TRANSACTION
CREATE TABLE test_table(name, sex, age)
INSERT INTO "test_table" VALUES('xiaohong','female',19)
CREATE INDEX test_index on test_table(name)
COMMIT
如下所示的是导入test.sql文件(导入前删除原有的test.db):
[root@localhost home]# sqlite3 test.db <test.sql
通过对test.sql文件的导入导出,可以实现数据库文件的备份。
11.2.2 SQLite3的C接口
以上介绍的是SQLite3数据库的命令 *** 作方式。在实际使用中,一般都是应用程序需要对数据库进行访问。为此,SQLite3提供了各种编程语言的使用接口(本书介绍C语言接口)。SQLite3具有几十个C接口,下面介绍一些常用的C接口。
sqlite_open
作用:打开SQLite3数据库
原型:int sqlite3_open(const char *dbname, sqlite3 **db)
参数:
dbname:数据库的名称;
db:数据库的句柄;
sqlite_colse
作用:关闭SQLite3数据库
原型:int sqlite_close(sqlite3 *db)
例如:
test.c:
#include <stdio.h>
#include <sqlite3.h>
static sqlite3 *db=NULL
int main()
{
int rc
rc= sqlite3_open("test.db", &db)
if(rc)
{
printf("can't open database!\n")
}
else
{
printf("open database success!\n")
}
sqlite3_close(db)
return 0
}
运行命令“gcc –o test test.c –lsqlite3”进行编译,运行test的结果如下所示:
[root@localhost home]# open database success!
sqlite_exec
作用:执行SQL语句
原型:int sqlite3_exec(sqlite3 *db, const char *sql, int (*callback)(void*,int,char**,char**), void *, char **errmsg)
参数:
db:数据库;
sql:SQL语句;
callback:回滚;
errmsg:错误信息
例如:
test.c:
#include <stdio.h>
#include <sqlite3.h>
static sqlite3 *db=NULL
static char *errmsg=NULL
int main()
{
int rc
rc = sqlite3_open("test.db", &db)
rc = sqlite3_exec(db,"insert into test_table values('daobao', 'male', 24)", 0, 0, &errmsg)
if(rc)
{
printf("exec fail!\n")
}
else
{
printf("exec success!\n")
}
sqlite3_close(db)
return 0
}
编译完成后,运行test的结果如下所示:
[root@localhost home]# ./test
exec success!
[root@localhost home]# sqlite3 test.db
SQLite version 3.6.11
Enter ".help" for instructions
Enter SQL statements terminated with a ""
sqlite>select * from test_table
daobao|male|24
sqlite3_get_table
作用:执行SQL查询
原型:int sqlite3_get_table(sqlite3 *db, const char *zSql, char ***pazResult, int *pnRow, int *pnColumn, char **pzErrmsg)
参数:
db:数据库;
zSql:SQL语句;
pazResult:查询结果集;
pnRow:结果集的行数;
pnColumn:结果集的列数;
errmsg:错误信息;
sqlite3_free_table
作用:注销结果集
原型:void sqlite3_free_table(char **result)
参数:
result:结果集;
例如:
test.c:
#include <stdio.h>
#include <sqlite3.h>
static sqlite3 *db=NULL
static char **Result=NULL
static char *errmsg=NULL
int main()
{
int rc, i, j
int nrow
int ncolumn
rc= sqlite3_open("test.db", &db)
rc= sqlite3_get_table(db, "select * from test_table", &Result, &nrow, &ncolumn,
&errmsg)
if(rc)
{
printf("query fail!\n")
}
else
{
printf("query success!\n")
for(i = 1i <= nrowi++)
{
for(j = 0j <ncolumnj++)
{
printf("%s | ", Result[i * ncolumn + j])
}
printf("\n")
}
}
sqlite3_free_table(Result)
sqlite3_close(db)
return 0
}
编译完成后,运行test的结果如下所示:
[root@localhost home]# ./test
query success!
xiaohong | female | 19 |
xiaoxue | female | 18 |
xiaoliu | male | 20 |
daobao | male | 24 |
sqlite3_prepare
作用:把SQL语句编译成字节码,由后面的执行函数去执行
原型:int sqlite3_prepare(sqlite3 *db, const char *zSql, int nByte, sqlite3_stmt **stmt, const char **pTail)
参数:
db:数据库;
zSql:SQL语句;
nByte:SQL语句的最大字节数;
stmt:Statement句柄;
pTail:SQL语句无用部分的指针;
sqlite3_step
作用:步步执行SQL语句字节码
原型:int sqlite3_step (sqlite3_stmt *)
例如:
test.c:
#include <stdio.h>
#include <sqlite3.h>
static sqlite3 *db=NULL
static sqlite3_stmt *stmt=NULL
int main()
{
int rc, i, j
int ncolumn
rc= sqlite3_open("test.db", &db)
rc=sqlite3_prepare(db,"select * from test_table",-1,&stmt,0)
if(rc)
{
printf("query fail!\n")
}
else
{
printf("query success!\n")
rc=sqlite3_step(stmt)
ncolumn=sqlite3_column_count(stmt)
while(rc==SQLITE_ROW)
{
for(i=0i<2i++)
{
printf("%s | ", sqlite3_column_text(stmt,i))
}
printf("\n")
rc=sqlite3_step(stmt)
}
}
sqlite3_finalize(stmt)
sqlite3_close(db)
return 0
}
编译完成后,运行test的结果如下所示:
[root@localhost home]# ./test
query success!
xiaohong | female | 19 |
xiaoxue | female | 18 |
xiaoliu | male | 20 |
daobao | male | 24 |
在程序中访问SQLite3数据库时,要注意C API的接口定义和数据类型是否正确,否则会得到错误的访问结果。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)