Cocos2d-x数据模块教程06:SQLite3数据库基础用法

2015年03月24日 09:30 0 点赞 0 评论 更新于 2025-11-21 13:55

在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的表,包含三个字段:IDnamesex,其中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);