最新文章
Cocos2d-x游戏开发实例详解7:对象释放时机
03-25 13:59
Cocos2d-x游戏开发实例详解6:自动释放池
03-25 13:55
Cocos2d-x游戏开发实例详解5:神奇的自动释放
03-25 13:49
Cocos2d-x游戏开发实例详解4:游戏主循环
03-25 13:44
Cocos2d-x游戏开发实例详解3:无限滚动地图
03-25 13:37
Cocos2d-x游戏开发实例详解2:开始菜单续
03-25 13:32
Cocos2d-x数据模块教程06:SQLite3数据库基础用法
在Cocos2d-x中,简单数据存储可以使用UserDefault。但如果要存储大量、不规则的数据,该如何解决呢?在Cocos2d-x里,我们可以使用SQLite数据库来存储数据。
SQLite是一种应用广泛的嵌入式数据库,具有小巧、高效、跨平台、开源免费且易于操作等特点。因此,它被大量应用于手机、PDA、MP3播放器以及机顶盒设备等。SQLite数据库使用C语言编写,所以在Cocos2d-x中使用SQLite也十分便捷。
本文将介绍SQLite3数据库的基础用法,即增删改查操作。
另外,关于SQLite的可视化管理工具,本人使用的是SQLiteStudio,你可以自行了解。
1、准备工作
Cocos引擎的external文件夹里的sqlite3好像只有两个.h文件,没有sqlite3.c文件,导致编译时一直无法通过。后来从sqlite官网下载了源文件,才成功编译。
(1)下载sqlite3源文件
你可以从以下地址下载sqlite3的源文件:http://www.sqlite.org/download.html
(2)拷贝并导入源文件
将sqlite3的三个源文件拷贝到项目的Classes文件夹中,并导入到项目里。
如果是Android平台,还需要修改Android.mk文件。
2、SQLite3的基础API
这里仅介绍SQLite3最基本的API,这些API可以帮助你完成数据库的增删改查功能。
注意:SQLite3数据库使用的编码格式为UTF - 8。如果出现乱码,需将其转为UTF - 8格式。
2.1、关键数据结构:sqlite3*
在SQLite中,最常用的类型是sqlite3*。从数据库打开开始,SQLite就需要为这个类型分配内存,直到数据库关闭,整个过程都要用到该类型。当数据库打开时,这个类型的变量就代表了你要操作的数据库,下面将详细介绍。
2.2、打开数据库:sqlite3_open
int sqlite3_open(const char *filename, sqlite3 **ppDb)
这个函数用于打开数据库,各参数说明如下:
filename:数据库文件名,例如"/Users/apple/Documents/data.db"。文件名不一定要存在,如果文件不存在,sqlite会自动创建;如果文件存在,则尝试将其作为数据库文件打开。ppDb:即前面提到的关键数据结构,无需关注其底层细节。- 返回值:如果返回
SQLITE_OK,则表示成功打开数据库。
2.3、关闭数据库:sqlite3_close
int sqlite3_close(sqlite3 *)
该函数用于关闭数据库。当不再使用数据库时,必须关闭数据库以释放内存资源。
sqlite3*:即前面提到的关键数据结构。- 返回值:如果返回
SQLITE_OK,则表示成功关闭数据库。
2.4、执行sql语句:sqlite3_exec
int sqlite3_exec(sqlite3*, const char *sql, int (*callback)(void*,int,char**,char**), void*, char **errmsg)
这个函数用于执行SQL语句,实现对数据库的增删改查操作。
sqlite3*:即前面提到的关键数据结构。sql:SQL语句(增删改查)。(*callback):执行exec时,每查到一条记录,就会调用这个回调函数(具体在2.5节介绍)。void*:传递数据,可以是任意值,会传递到回调函数callback,作为其第一个参数传入。errmsg:错误信息。
注意:后面三个参数若不需要,可以填NULL。
2.5、sqlite3_exec的回调函数callback
int (*sqlite3_callback)(void* para, int col_num, char** col_value, char** col_name)
该函数作为sqlite3_exec的第三个参数,执行exec时,每查询到一条记录,就会调用一次。
para:即exec的第四个参数传递来的数据。col_num:一条记录的字段数量(即列数)。col_value:查询出来的数据,是一个一维数组,每个元素都是一个字符串char *值,表示一个字段的内容。col_name:每个字段的名称(即列名),与col_value对应。
2.6、不使用回调查询数据库:sqlite3_get_table
sqlite3_get_table(sqlite3*db,const char*sql,char***result,int*row,int*col,char**errmsg)
这个函数用于查询数据库。
db:即前面提到的关键数据结构。sql:SQL查询语句。result:查询结果,是一个一维数组。其内存布局为:第一行是字段名称,后面紧接着是每个字段的值。例如,0~col - 1是字段名称,col~2*col - 1是第一行记录,2*col~3*col - 1是第二行记录,以此类推。row:行数。col:列数。errmsg:错误信息。
注意:使用完该函数的result后,需要使用sqlite3_free_table(result)释放资源。
3、使用方法
3.1、引入头文件
添加从SQLite官网下载的源代码sqlite3.h头文件。
#include "sqlite3.h"
3.2、创建数据库
创建数据库时,若文件不存在,SQLite会自动建立;若文件存在,则尝试将其作为数据库文件打开。
// 数据库路径
std::string path = "/soft/cocos2d-x-3.4/projects/Demo34/Resources/data.db";
std::string sql; // sql语句
int ret; // 执行结果,SQLITE_OK表示成功执行
// 创建sqlite数据库:sqlite3*
sqlite3* pdb = nullptr;
// 打开sqlite数据库:sqlite3_open
ret = sqlite3_open(path.c_str(), &pdb);
// 当sqllite数据库打开失败时
if (ret != SQLITE_OK) {
// 获得sqltite数据库打开错误的信息
const char* errmsg = sqlite3_errmsg(pdb);
CCLOG("sqlite open error: %s", errmsg);
sqlite3_close(pdb);
return false;
}
3.3、创建表
创建一张名为student的表,包含三个字段:ID、name、sex,其中ID为主键自增。
创建表时,不需要回调函数,sqlite3_exec的后面三个参数都填NULL。
// 创建表的sql语句:create table
sql = "create table student(ID integer primary key autoincrement, name text, sex text)";
// 执行sql语句:sqlite3_exec
ret = sqlite3_exec(pdb, sql.c_str(), nullptr, nullptr, nullptr);
if(ret != SQLITE_OK) {
CCLOG("create table failed");
}
3.4、插入数据(增)
插入三条数据,插入数据时不需要回调函数,sqlite3_exec的后面三个参数都填NULL。
// (1 , 'student1' , 'male')
sql = "insert into student values(1, 'student1', 'male')";
ret = sqlite3_exec(pdb, sql.c_str(), nullptr, nullptr, nullptr);
if(ret != SQLITE_OK) {
CCLOG("insert data failed!");
}
// (2 , 'student3' , 'female')
sql = "insert into student values(2, 'student2', 'female')";
ret = sqlite3_exec(pdb, sql.c_str(), nullptr, nullptr, nullptr);
if(ret != SQLITE_OK) {
CCLOG("insert data failed!");
}
// (3 , 'student3' , 'male')
sql = "insert into student values(3, 'student3', 'male')";
ret = sqlite3_exec(pdb, sql.c_str(), nullptr, nullptr, nullptr);
if(ret != SQLITE_OK) {
CCLOG("insert data failed!");
}
3.5、查询数据,使用sqlite3_exec(查)
使用sqlite3_exec来查询数据。
// 查询语句
sql = "select * from student";
ret = sqlite3_exec(pdb, sql.c_str(), &callback, (void*)"para", nullptr);
// 回调函数
int callback(void* para, int col_num, char** col_value, char** col_name)
{
CCLOG("%s : 总共有 %d 个字段", (char *)para , col_num);
for (int i = 0; i < col_num; i++) {
CCLOG("%s = %s", col_name[i], col_value[i]);
}
CCLOG("------------------------------"); // 分隔符
return 0;
}
控制台输出结果:(此处可根据实际运行结果补充)
3.6、删除数据(删)
删除第一条记录。
// 删除第一条记录
sql = "delete from student where ID = 1";
ret = sqlite3_exec(pdb, sql.c_str(), nullptr, nullptr, nullptr);
if(ret != SQLITE_OK) {
CCLOG("delete data failed!");
}
3.7、修改数据(改)
修改第三条记录的name字段。
// 修改第三条记录的 name 字段
sql = "update student set name = 'hello' where ID = 3";
ret = sqlite3_exec(pdb, sql.c_str(), nullptr, nullptr, nullptr);
if(ret != SQLITE_OK) {
CCLOG("update data failed!");
}
3.8、查询数据,使用sqlite3_get_table(查)
使用sqlite3_get_table来查询数据,查询完后,不使用回调函数,而是直接保存查询结果。
char** table; // 查询结果
int r, c; // 行数、列数
sql = "select * from student";
sqlite3_get_table(pdb, sql.c_str(), &table, &r, &c, nullptr);
CCLOG("行数 is %d , 列数 is %d", r, c);
// 第0行(0 ~ c-1),为字段名
// 第1行(c ~ 2*c-1),第一条记录
// ......
for(int i = 0; i <= r; i++) {
for(int j = 0; j < c; j++) {
CCLOG("%s", table[i * c + j]);
}
CCLOG("------------------------------");
}
// 记得释放查询表
sqlite3_free_table(table);
控制台输出结果:可以看到ID = 1的数据已经被删除,并且ID = 3的数据name被改为了"hello"。
3.9、关闭数据库
最后,记得关闭数据库,否则会造成内存泄露。
sqlite3_close(pdb);