Cocos2d-x开发系列 lua sqlite集成 LSQLite3
2016-06-12 15:59
1736 查看
项目中经常会使用到sqlite来存储数据,例如聊天,以及一些游戏中的配置。
Cocos2d-x引擎中是有一个storage文件夹,仔细看LocalStorage.h文件,里面说明了,值专门针对JS Bindings使用。另外没有sqlite.c文件。引擎中也没有SQLite的sqlite.c实现文件。所以我们需要到官网去下载:
luaSqlite的源代码http://lua.sqlite.org/index.cgi/index
下载sqlite的源代码 http://sqlite.org/
引擎版本:3.6
一、集成到项目中
在上面的两个网址下载文件后等到如下文件:
lsqlite3.c (lua的绑定实行已经做好了)
shell.c
sqlite3.c
sqlite3.h
sqlite3ext.h
1、在Class里面新建文件夹Sqlite3,将上述文件放在里面。编译
2、lua-bindings中的auto目录下新建lsqlite3.h文件,内容如下
3、注册SQLite相关函数
在L状态中调用lsqlite.h文件中的 luaopen_lsqlite3注册到lua虚拟机环境中。
跟其它的自定义类,或者引擎相关的注册函数调用出调用。这里我们在LuaSupportFactory::registerCustomLuaModule()中添加注册代码
4、测试验证
在lua中调用如下
二、关于包体大小
集成的时候,发现,几个文件加起来达到6.78M。主要是sqlite3.c文件很大。不过其实编译后就很小了。
win32下面文件变为2.16M了,但是看看其他的cpp文件编译后大小比这大多了。
新建一个Cocos2d-x lua项目
分别打出不包含、包含lsqlite3的两个项目包
文件差不多大。所以sqlite.c文件很大,但是因为是C文件,在打包后会压缩到很小。不必担心集成包大小
三、使用API
1、引用LuaSqlite
四、碰到的问题
1、error loading module ‘sqlite3’
在一次更新代码的时候将sqlite注册到Lua的代码冲掉了,一直报这个错误,后来检查代码才发现是没有注册过去。
2、iOS平台下,出现shell.c报错
需要将这个文件去掉,这个文件是控制台数据库操作用的,不应该加搞项目中。
五、实例
Cocos2d-x引擎中是有一个storage文件夹,仔细看LocalStorage.h文件,里面说明了,值专门针对JS Bindings使用。另外没有sqlite.c文件。引擎中也没有SQLite的sqlite.c实现文件。所以我们需要到官网去下载:
luaSqlite的源代码http://lua.sqlite.org/index.cgi/index
下载sqlite的源代码 http://sqlite.org/
引擎版本:3.6
一、集成到项目中
在上面的两个网址下载文件后等到如下文件:
lsqlite3.c (lua的绑定实行已经做好了)
shell.c
sqlite3.c
sqlite3.h
sqlite3ext.h
1、在Class里面新建文件夹Sqlite3,将上述文件放在里面。编译
2、lua-bindings中的auto目录下新建lsqlite3.h文件,内容如下
#ifndef __LSQLITE3_H__ #define __LSQLITE3_H__ #ifdef __cplusplus extern "C" { #endif #include "tolua++.h" #ifdef __cplusplus } #endif extern "C" int luaopen_lsqlite3(lua_State* L); //lsqlite3.c 中的C函数,这里注册C函数 #endif
3、注册SQLite相关函数
在L状态中调用lsqlite.h文件中的 luaopen_lsqlite3注册到lua虚拟机环境中。
跟其它的自定义类,或者引擎相关的注册函数调用出调用。这里我们在LuaSupportFactory::registerCustomLuaModule()中添加注册代码
void LuaSupportFactory::registerCustomLuaModule() { //TODO 注册自定义的Lua API lua_State* L = LuaEngine::getInstance()->getLuaStack()->getLuaState(); register_all_ww_net(L); register_all_ww_gui(L); register_all_ww_data(L); luaopen_lsqlite3(L); //注册LSQLite3相关内容。 }
4、测试验证
在lua中调用如下
local sqlite3 = require("sqlite3") cclog("sqlite3 version"..sqlite3.version())
二、关于包体大小
集成的时候,发现,几个文件加起来达到6.78M。主要是sqlite3.c文件很大。不过其实编译后就很小了。
win32下面文件变为2.16M了,但是看看其他的cpp文件编译后大小比这大多了。
新建一个Cocos2d-x lua项目
分别打出不包含、包含lsqlite3的两个项目包
文件差不多大。所以sqlite.c文件很大,但是因为是C文件,在打包后会压缩到很小。不必担心集成包大小
三、使用API
1、引用LuaSqlite
local sqlite3 = require("sqlite3") --打开数据库文件 local db = sqlite3.open('test.db') --打开内存数据库 local db = sqlite3.open_memory()
四、碰到的问题
1、error loading module ‘sqlite3’
在一次更新代码的时候将sqlite注册到Lua的代码冲掉了,一直报这个错误,后来检查代码才发现是没有注册过去。
2、iOS平台下,出现shell.c报错
需要将这个文件去掉,这个文件是控制台数据库操作用的,不应该加搞项目中。
五、实例
------------------------------------------------------------------------- -- Desc: sqlite3test.lua -- Author: sqlite3测试 -- Copyright (c) wawagame Entertainment All right reserved. -- local sqlite3 = require("app.dataorm.sqlite3test") -- sqlite3:getDBVersion() -- sqlite3:openDB() -- sqlite3:insert('numbers', {10086, 10086,"diyal"}) -- sqlite3:test() -- sqlite3:test2() -- sqlite3:test3() -- sqlite3:aggregate() -- sqlite3:crudTest() -- sqlite3:statement() -- sqlite3:tracing() -- sqlite3:batchsql() -- sqlite3:updateHook() ------------------------------------------------------------------------- local sqlite3 = require("sqlite3") local sqlite3test = class('sqlite3test') local _db, _vm --数据库句柄, 数据库状态 --[[获取版本号]] function sqlite3test:getDBVersion() cclog("[SQLite] DB version : "..sqlite3.version()) end function sqlite3test:openDB() local dbFilePath = device.writablePath..'test.db' local isExist = cc.FileUtils:getInstance():isFileExist(dbFilePath) _db = sqlite3.open(dbFilePath) if isExist then cclog('[SQLite] DB File is exist') else cclog('[SQLite] DB File is not exist, created it') --初始化 4000 表结构 self:initDB() end end function sqlite3test:initDB() -- Demo表DDL语句 local t_demo_sql= [=[ CREATE TABLE numbers(num1,num2,str); INSERT INTO numbers VALUES(1,11,"ABC"); INSERT INTO numbers VALUES(2,22,"DEF"); INSERT INTO numbers VALUES(3,33,"UVW"); INSERT INTO numbers VALUES(4,44,"XYZ"); SELECT * FROM numbers; ]=] local showrow = function(udata,cols,values,names) assert(udata == 't_demo_create') -- for i=1,cols do -- cclog('%s |-> %s',names[i],values[i]) -- end cclog('[SQLite] %s rows %s', udata,table.concat( values, "-")) return 0 end _db:exec(t_demo_sql, showrow, 't_demo_create') end function sqlite3test:insert( tableName, tableParas) local t_demo_sql= [=[ INSERT INTO tableName VALUES(tableParas); SELECT * FROM numbers; ]=] local showrow = function(udata,cols,values,names) assert(udata == 't_demo_create') -- for i=1,cols do -- cclog('%s |-> %s',names[i],values[i]) -- end cclog('[SQLite] %s rows %s', udata,table.concat( values, "-")) return 0 end local ret = _db:exec(t_demo_sql, showrow, 't_demo_create') if ret ~= sqlite3.OK then cclog('error') end end --[[test]] function sqlite3test:test() local sqlite3 = require('sqlite3') local width = 78 local function line(pref, suff) --格式化函数 pref = pref or '' suff = suff or '' local len = width - 2 - string.len(pref) - string.len(suff) cclog(pref .. string.rep('_', len) .. suff) end local db, vm local assert_, assert = assert, function (test) if (not test) then error(db:errmsg(), 2) end end -- os.remove('test.db') db = sqlite3.open('test.db') line(nil, 'db:exec') db:exec('CREATE TABLE t(a, b)') line(nil, 'prepare') vm = db:prepare('insert into t values(?, :bork)') assert(vm, db:errmsg()) assert(vm:bind_parameter_count() == 2) assert(vm:bind_values(2, 4) == sqlite3.OK) assert(vm:step() == sqlite3.DONE) assert(vm:reset() == sqlite3.OK) assert(vm:bind_names{ 'pork', bork = 'nono' } == sqlite3.OK) assert(vm:step() == sqlite3.DONE) assert(vm:reset() == sqlite3.OK) assert(vm:bind_names{ bork = 'sisi' } == sqlite3.OK) assert(vm:step() == sqlite3.DONE) assert(vm:reset() == sqlite3.OK) assert(vm:bind_names{ 1 } == sqlite3.OK) assert(vm:step() == sqlite3.DONE) assert(vm:finalize() == sqlite3.OK) line("select * from t", 'db:exec') -- assert(db:exec('select * from t', function (ud, ncols, values, names) -- cclog(table.unpack(values)) -- return sqlite3.OK -- end) == sqlite3.OK) db:exec('select * from t', function (ud, ncols, values, names) cclog( table.concat( { unpack(values)} ) ) return sqlite3.OK end) line("select * from t", 'db:prepare') vm = db:prepare('select * from t') assert(vm, db:errmsg()) cclog(vm:get_unames()) while (vm:step() == sqlite3.ROW) do cclog(vm:get_uvalues()) end assert(vm:finalize() == sqlite3.OK) line('udf', 'scalar') local function do_query(sql) local r local vm = db:prepare(sql) assert(vm, db:errmsg()) cclog('====================================') cclog(vm:get_unames()) cclog('------------------------------------') r = vm:step() while (r == sqlite3.ROW) do cclog(vm:get_uvalues()) r = vm:step() end assert(r == sqlite3.DONE) assert(vm:finalize() == sqlite3.OK) cclog('====================================') end local function udf1_scalar(ctx, v) local ud = ctx:user_data() ud.r = (ud.r or '') .. tostring(v) ctx:result_text(ud.r) end db:create_function('udf1', 1, udf1_scalar, { }) do_query('select udf1(a) from t') line('udf', 'aggregate') local function udf2_aggregate(ctx, ...) local ud = ctx:get_aggregate_data() if (not ud) then ud = {} ctx:set_aggregate_data(ud) end ud.r = (ud.r or 0) + 2 end local function udf2_aggregate_finalize(ctx, v) local ud = ctx:get_aggregate_data() ctx:result_number(ud and ud.r or 0) end db:create_aggregate('udf2', 1, udf2_aggregate, udf2_aggregate_finalize, { }) do_query('select udf2(a) from t') -- if (true) then -- line(nil, '100 insert exec') -- db:exec('delete from t') -- local t = os.time() -- for i = 1, 100 do -- db:exec('insert into t values('..i..', '..(i * 2 * -1^i)..')') -- end -- print('elapsed: '..(os.time() - t)) -- do_query('select count(*) from t') -- line(nil, '100000 insert exec T') -- db:exec('delete from t') -- local t = os.time() -- db:exec('begin') -- for i = 1, 100000 do -- db:exec('insert into t values('..i..', '..(i * 2 * -1^i)..')') -- end -- db:exec('commit') -- print('elapsed: '..(os.time() - t)) -- do_query('select count(*) from t') -- line(nil, '100000 insert prepare/bind T') -- db:exec('delete from t') -- local t = os.time() -- local vm = db:prepare('insert into t values(?, ?)') -- db:exec('begin') -- for i = 1, 100000 do -- vm:bind_values(i, i * 2 * -1^i) -- vm:step() -- vm:reset() -- end -- vm:finalize() -- db:exec('commit') -- print('elapsed: '..(os.time() - t)) -- do_query('select count(*) from t') -- end line(nil, "db:close") local filePath = cc.FileUtils:getInstance():fullPathForFilename('test.db') cclog('path: '..filePath) assert(db:close() == sqlite3.OK) end function sqlite3test:test2() _db = sqlite3.open('test.db') cclog('[SQLite] db:exec') _db:exec('CREATE TABLE t(a, b)') cclog('[SQLite] prepare') _vm = _db:prepare('insert into t values(?, :bork)') assert(_vm, _db:errmsg()) assert(_vm:bind_parameter_count() == 2) assert(_vm:bind_values(2, 4) == sqlite3.OK) assert(_vm:step() == sqlite3.DONE) assert(_vm:reset() == sqlite3.OK) assert(_vm:bind_names{ 'pork', bork = 'nono' } == sqlite3.OK) assert(_vm:step() == sqlite3.DONE) assert(_vm:reset() == sqlite3.OK) assert(_vm:bind_names{ bork = 'sisi' } == sqlite3.OK) assert(_vm:step() == sqlite3.DONE) assert(_vm:reset() == sqlite3.OK) assert(_vm:bind_names{ 1 } == sqlite3.OK) assert(_vm:step() == sqlite3.DONE) assert(_vm:finalize() == sqlite3.OK) cclog("[SQLite] select * from t") -- assert(_db:exec('select * from t', -- function (ud, ncols, values, names) -- cclog(table.unpack(values)) -- return sqlite3.OK -- end) == sqlite3.OK -- ) local ret = _db:exec('select * from t', function (ud, ncols, values, names) cclog('[SQLite] ' .. table.unpack(values)) return sqlite3.OK end) end --[[test 3]] function sqlite3test:test3() end --[[聚合函数]] function sqlite3test:aggregate() assert( _db:exec "CREATE TABLE test (col1, col2)" ) assert( _db:exec "INSERT INTO test VALUES (1, 2)" ) assert( _db:exec "INSERT INTO test VALUES (2, 4)" ) assert( _db:exec "INSERT INTO test VALUES (3, 6)" ) assert( _db:exec "INSERT INTO test VALUES (4, 8)" ) assert( _db:exec "INSERT INTO test VALUES (5, 10)" ) do local square_error_sum = 0 local function step(ctx, a, b) local error = a - b local square_error = error * error square_error_sum = square_error_sum + square_error end local function final(ctx) ctx:result_number( square_error_sum / ctx:aggregate_count() ) end assert( _db:create_aggregate("my_stats", 2, step, final) ) end for my_stats in _db:urows("SELECT my_stats(col1, col2) FROM test") do cclog("my_stats:%d", my_stats) end end --[[CRUD]] function sqlite3test:crudTest() local sqlite3 = require("sqlite3") --加载模块 local db = sqlite3.open_memory() --开辟内存数据库 db:exec[[ CREATE TABLE test (id INTEGER PRIMARY KEY, content) ]] --执行DDL语句 local stmt = db:prepare[[ INSERT INTO test VALUES (:key, :value) ]] --前导声明 stmt:bind_names({ key = 1, value = "Hello World" }) --参数绑定 -- step() -- This is the top-level implementation of sqlite3_step(). Call -- sqlite3Step() to do most of the work. If a schema error occurs, -- call sqlite3Reprepare() and try again. stmt:step() --执行 stmt:reset() --重置 stmt:bind_names({ key = 2, value = "Hello Lua" } ) stmt:step() stmt:reset() stmt:bind_names({ key = 3, value = "Hello Sqlite3" }) stmt:step() stmt:finalize() for row in db:nrows("SELECT * FROM test") do cclog("%d, %s", row.id, row.content) end end --[[statement]] function sqlite3test:statement() local sqlite3 = require("sqlite3") local db = sqlite3.open_memory() db:exec[[ CREATE TABLE test ( id INTEGER PRIMARY KEY, content VARCHAR ); ]] local insert_stmt = assert( db:prepare("INSERT INTO test VALUES (NULL, ?)") ) local function insert(data) --封装一个insert函数 insert_stmt:bind_values(data) insert_stmt:step() insert_stmt:reset() end local select_stmt = assert( db:prepare("SELECT * FROM test") ) local function select() --封装一个查询函数 for row in select_stmt:nrows() do cclog("%d, %s",row.id, row.content) end end insert("Hello World") cclog("First:") select() insert("Hello Lua") cclog("Second:") select() insert("Hello Sqlite3") cclog("Third:") select() end --[[tracing]] function sqlite3test:tracing() local sqlite3 = require("sqlite3") local db = sqlite3.open_memory() db:trace( function(ud, sql) cclog("[Sqlite Trace]: %s", sql) end ) db:exec[=[ CREATE TABLE test ( id INTEGER PRIMARY KEY, content VARCHAR ); INSERT INTO test VALUES (NULL, 'Hello World'); INSERT INTO test VALUES (NULL, 'Hello Lua'); INSERT INTO test VALUES (NULL, 'Hello Sqlite3'); ]=] for row in db:rows("SELECT * FROM test") do cclog(row.content) end end --[[batch sql str]] --批处理 function sqlite3test:batchsql() local sqlite3 = require("sqlite3") local db = sqlite3.open_memory() local sql=[=[ CREATE TABLE numbers(num1,num2,str); INSERT INTO numbers VALUES(1,11,"ABC"); INSERT INTO numbers VALUES(2,22,"DEF"); INSERT INTO numbers VALUES(3,33,"UVW"); INSERT INTO numbers VALUES(4,44,"XYZ"); SELECT * FROM numbers; ]=] local showrow = function(udata,cols,values,names) assert(udata=='test_udata') for i=1,cols do cclog('%s |-> %s',names[i],values[i]) end return 0 end db:exec(sql,showrow,'test_udata') end --[[update hook]] --表事件监听 eg:有在一张表插入数据,则读取更新数据 function sqlite3test:updateHook() local sqlite3 = require("sqlite3") local db = sqlite3.open_memory() local optbl = { [sqlite3.UPDATE] = "UPDATE"; [sqlite3.INSERT] = "INSERT"; [sqlite3.DELETE] = "DELETE" } setmetatable(optbl, { __index=function(t,n) return string.format("Unknown op %d",n) end }) local udtbl = {0, 0, 0} db:update_hook( function(ud, op, dname, tname, rowid) cclog("Sqlite Update Hook: %s,%s,%s,%d", optbl[op], dname, tname, rowid) end, udtbl) db:exec[[ CREATE TABLE test ( id INTEGER PRIMARY KEY, content VARCHAR ); INSERT INTO test VALUES (NULL, 'Hello World'); INSERT INTO test VALUES (NULL, 'Hello Lua'); INSERT INTO test VALUES (NULL, 'Hello Sqlite3'); UPDATE test SET content = 'Hello Again World' WHERE id = 1; DELETE FROM test WHERE id = 2; ]] for row in db:nrows("SELECT * FROM test") do cclog('%d %s', row.id, row.content) end end return sqlite3tes
相关文章推荐
- [原创]java局域网聊天系统
- SQLite教程(十一):临时文件
- SQLite中重置自动编号列的方法
- 保护你的Sqlite数据库(SQLite数据库安全秘籍)
- SQLite教程(十):内存数据库和临时数据库
- SQLite 入门教程二 SQLite的创建、修改、删除表
- 详解SQLite中的数据类型
- 详解SQLite中的查询规划器
- C#封装的Sqlite访问类实例
- SQLite中的B-Tree实现细节分析
- SQLite 中文指南之FAQ第1/6页
- Android Sqlite命令详解(基本命令)
- Cocos2d-x中背景音乐和音效使用实例
- Cocos2d-x学习笔记之CCScene、CCLayer、CCSprite的默认坐标和默认锚点实验
- Cocos2d-x UI开发之CCControlPotentiometer控件类使用实例
- Cocos2d-x UI开发之文本类使用实例
- Cocos2d-x保存用户游戏数据之XML文件是否存在问题判断方法
- Cocos2d-x UI开发之菜单类使用实例
- SQLite 内存数据库学习手册
- SQLite中的WAL机制详细介绍