skynet框架应用——mongodb

在skynet中使用mongodb,在
在配置文件config.mongodb中看到启动的是main_mongodb.lua
main_mongodb.lua文件内容

local skynet = require "skynet"

skynet.start(function()
	print("Main Server start")
	local console = skynet.newservice(
		"testmongodb", "127.0.0.1", 27017, "testdb", "test", "test"
	)
	
	print("Main Server exit")
	skynet.exit()
end)

testmongodb.lua文件在官方的示例中有,大家可以自己去看,我们这里不展开。
接下来要说的是,在skynet中,我们怎么更方便地使用mongodb。
我们考虑的是将mongodb单独成一个服务,
在使用时候,用skynet.call去调用它,示例:

local mongodb = skynet.newservice("mongodb")
skynet.call(mongodb, "lua", "connect", {
       host = "127.0.0.1",
       port = 27017
})

第一个文件:
mongodb.lua

local skynet = require "skynet"
require "skynet.manager"
local dbLogic = require "dbLogic"

skynet.start(function()
	skynet.dispatch("lua", function(session, address, cmd, ...)
		local f = dbLogic[cmd]
		if f then
			skynet.ret(skynet.pack(f(...)))
		else
			error(string.format("Unknown command %s", tostring(cmd)))
		end
	end)

	skynet.register ".mongodb"
end)

我们把对mongodb的增、删、查、改都放到了dbLogic.lua文件中:

local skynet = require "skynet"
require "skynet.manager"
local mongo = require "skynet.db.mongo"

local client

local _M = {}

function _M.connect(args)
	client = mongo.client(
		{
			host = args.host, 
            port = tonumber(args.port)
		}
	)

    if client then
        return true
    end
    return false
end

function _M.disconnect()
    client:disconnect()
end

function _M.insert(args)
    local db = client:getDB(args.database)
    local c = db:getCollection(args.collection)
    c:insert(args.doc)
end

function _M.insertBatch(args)
	local db = client:getDB(args.database)
	local c = db:getCollection(args.collection)
	c:batch_insert(args.docs)
end

function _M.delete(args)
	local db = client:getDB(args.database)
	local c = db:getCollection(args.collection)
	c:delete(args.selector, args.single)
end

function _M.drop(args)
	local db = client:getDB(args.database)
	local r = db:runCommand("drop", args.collection)
	return r
end

function _M.findOne(args)
	local db = client:getDB(args.database)
	local c = db:getCollection(args.collection)
    local result = c:findOne(args.query, args.selector)
	return result
end

function _M.findAll(args)
	local db = client:getDB(args.database)
	local c = db:getCollection(args.collection)
	local result = {}
	local cursor = c:find(args.query, args.selector)
	if args.skip ~= nil then
		cursor:skip(args.skip)
	end
	if args.limit ~= nil then
		cursor:limit(args.limit)
	end
	while cursor:hasNext() do
		local document = cursor:next()
		table.insert(result, document)
	end	
    cursor:close()

    if #result > 0 then
        return result
    end
end

function _M.update(args)
	local db = client:getDB(args.database)
	local c = db:getCollection(args.collection)
	c:update(args.selector, args.update, args.upsert, args.multi)
end

function _M.createIndex(args)
	local db = client:getDB(args.database)
	local c = db:getCollection(args.collection)
	local result = c:createIndex(args.keys, args.option)
	return result
end

function _M.runCommand(args)
	local db = client:getDB(args.database)
	local result = db:runCommand(args)
	return result
end

return _M

为了方便查看table中的数据,我们将util.lua拷贝过来,放到和main.lua同一个文件下。
具体内容查看这篇博客:https://blog.csdn.net/hp_cpp/article/details/104882400

现在我们开始对dbLogic.lua的接口进行测试和说明:

一、连接数据库

local skynet = require "skynet"
local util = require "util"

skynet.start(function()
	print("Main Server start")
	local mongodb = skynet.newservice("mongodb")
	
    local ret = skynet.call(mongodb, "lua", "connect", {
        host = "127.0.0.1",
        port = 27017
    })
    print("connect ret:", ret)
	--以下测试均在此处添加代码
	
	skynet.exit()
end)

打印出true,表示连接成功。
我们现在用的mongo数据库在默认端口,没有用户名和密码的,而连接数据库也很简单,只需要提供两个参数host和port:

client = mongo.client({host = args.host, 
					   port = tonumber(args.port)})

在这里插入图片描述我们手动建一个testdb数据库,以下操作均在testdb数据中进行。

二、插入

(1)单条插入

	skynet.call(mongodb, "lua", "insert", {
		database = "testdb",
		collection = "role",
		doc = {test = "haha", num = 100}
	})

这个操作在dbLogic.lua文件没有定义返回值,所以我们去查看数据库,果然新增了一个role表和插入一条记录
在这里插入图片描述
(1)批量插入

    skynet.call(mongodb, "lua", "insertBatch", {
        database = "testdb",
        collection = "role",
        docs = {
            {test = "hi", num = 101},
            {test = "me to", num = 102}}
    })

此时role表中又多了几条记录。

三、删除

(1)删除记录

    skynet.call(mongodb, "lua", "delete", {
		database = "testdb",
        collection = "role",
        selector = {num=100},
        single = 1,
    })

这里删除了role表中所有num=100的记录,(single为整形,表示删除多少条记录,或者说是删除多少个doc),具体可以查看以下两个文件:
在skynet-master\lualib\skynet\db\mongo.lua文件中:

function mongo_collection:delete(selector, single)
	local sock = self.connection.__sock
	local pack = driver.delete(self.full_name, single, bson_encode(selector))
	sock:request(pack)
end

在去查skynet-master\lualib-src\lua-mongo.c文件:

/*
	1 string collection
	2 integer single remove
	3 document selector

	return string package
 */
static int
op_delete(lua_State *L) {
	document selector  = lua_touserdata(L,3);
	if (selector == NULL) {
		luaL_error(L, "Invalid param");
	}
	size_t sz = 0;
	const char * name = luaL_checklstring(L,1,&sz);

	luaL_Buffer b;
	luaL_buffinit(L,&b);

	struct buffer buf;
	buffer_create(&buf);
		int len = reserve_length(&buf);
		write_int32(&buf, 0);
		write_int32(&buf, 0);
		write_int32(&buf, OP_DELETE);
		write_int32(&buf, 0);
		write_string(&buf, name, sz);
		write_int32(&buf, lua_tointeger(L,2));

		int32_t selector_len = get_length(selector);
		int total = buf.size + selector_len;
		write_length(&buf, total, len);

		luaL_addlstring(&b, (const char *)buf.ptr, buf.size);
	buffer_destroy(&buf);

	luaL_addlstring(&b, (const char *)selector, selector_len);
	luaL_pushresult(&b);

	return 1;
}

(2)清空表

    ret = skynet.call(mongodb, "lua", "drop", {
		database = "testdb",
        collection = "role",
    })
    
    util.dump_table(ret)

输出结果:

    S:nIndexesWas -> N:1
    S:ok -> N:1.0
    S:ns -> S:testdb.role

此时看到
在这里插入图片描述
role中的记录全部删除
返回的是一个table,我们用util模块中的util.dump_table打印出来,看到有个ok = 1.0,通过比较这个ok是否等于1,我们可以知道该操作是否成功
如果我们再执行一遍清空表操作:
则运行结果:

    S:errmsg -> S:ns not found
    S:ok -> N:0.0
    S:code -> N:26
    S:codeName -> S:NamespaceNotFound

提示我们操作错误了。

四、查找

(1)查找单条记录

	ret = skynet.call(mongodb, "lua", "findOne", {
		database = "testdb",
		collection = "role",
		query = {num = 100},
		selector = {test=1}
    })
    
    util.dump_table(ret)

当找到该文档时,输出:

    S:_id -> S:^n��(�G�g�
    S:test -> S:haha

没找到时,返回nil
这里的参数要说明一下:
query是查询条件,{num = 100},这里可以写多个条件。
selector是刷选器,也就是最后结果中需要的字段(除_id外,其余字段),比如我们这里只填入了一个test=1,这里的筛选的字段要作为key,如果是空表,则表示全部字段都要。

	ret = skynet.call(mongodb, "lua", "findOne", {
		database = "testdb",
		collection = "role",
		query = {num = 100},
		selector = {}
    })

运行结果:

    S:test -> S:haha
    S:num -> N:100
    S:_id -> S:^n��(��wf�

(1)查找全部

	ret = skynet.call(mongodb, "lua", "findAll", {
		database = "testdb",
		collection = "role",
		query = {num = 100},
		selector = {test=1}
	})
    util.dump_table(ret)

参数说明同上,只是这里的返回值略有不同,返回多条记录。(比如role表中有3条记录)

    N:1 -> 
        S:_id -> S:^n��(��wf�
        S:test -> S:haha
    N:2 -> 
        S:_id -> S:^n��(��7f�
        S:test -> S:haha
    N:3 -> 
        S:_id -> S:^nF�(���
        S:test -> S:haha

五、修改

    local updater = {}
    updater["$set"] = {test = "hello world1"}			
    
    local allResult = skynet.call(mongodb, "lua", "update", {
        database = "testdb",
        collection = "role",
        selector = {num=100},
        update = updater,
        upsert = false,
        multi = false
    })
    util.dump_table(ret)

参数说明:
updater用来设置更新字段和内容
这里updater["$set"]是固定格式,后面是一个表,记录需要修改的字段和内容。

updater["$set"] = {test = "hello world1"}	

upsert 布尔值,true表示不存在则新增一条新文档,false表示不存在则不做任何操作

multi 布尔值,true表表示多行更新,flase表示只会更新符合条件的一条记录

main.lua中的全部代码:

local skynet = require "skynet"
local util = require "util"

skynet.start(function()
	print("Main Server start")
	local mongodb = skynet.newservice("mongodb")

    local ret = skynet.call(mongodb, "lua", "connect", {
        host = "127.0.0.1",
        port = 27017
    })
    print("connect ret:", ret)
	
	skynet.call(mongodb, "lua", "insert", {
		database = "testdb",
		collection = "role",
		doc = {test = "haha", num = 100}
	})
    
    -- skynet.call(mongodb, "lua", "insertBatch", {
    --     database = "testdb",
    --     collection = "role",
    --     docs = {
    --         {test = "hi", num = 101},
    --         {test = "me to", num = 102}}
    -- })
    
    -- skynet.call(mongodb, "lua", "delete", {
	-- 	database = "testdb",
    --     collection = "role",
    --     selector = {num=100},
    --     single = 1,
    -- })

    -- ret = skynet.call(mongodb, "lua", "drop", {
	-- 	database = "testdb",
    --     collection = "role",
    -- })
    -- util.dump_table(ret)

	-- ret = skynet.call(mongodb, "lua", "findOne", {
	-- 	database = "testdb",
	-- 	collection = "role",
	-- 	query = {num = 100},
	-- 	selector = {}
    -- })
    -- util.dump_table(ret)
	
	-- ret = skynet.call(mongodb, "lua", "findAll", {
	-- 	database = "testdb",
	-- 	collection = "role",
	-- 	query = {num = 100},
	-- 	selector = {test=1}
	-- })
    -- util.dump_table(ret)

    -- local updater = {}
    -- updater["$set"] = {test = "hello world1"}			
    
    -- local allResult = skynet.call(mongodb, "lua", "update", {
    --     database = "testdb",
    --     collection = "role",
    --     selector = {num=100},
    --     update = updater,
    --     upsert = false,
    --     multi = false
    -- })
    -- util.dump_table(ret)

	skynet.exit()
end)

util.lua中的全部代码:


local util = {}

local function get_type_first_print( t )
    local str = type(t)
    return string.upper(string.sub(str, 1, 1))..":"
end

function util.dump_table(t, prefix, indent_input, print)
    local indent = indent_input
    if indent_input == nil then
        indent = 1
    end

    if print == nil then
        print = _G["print"]
    end

    local p = nil

    local formatting = string.rep("    ", indent)
    if prefix ~= nil then
        formatting = prefix .. formatting
    end

    if t == nil then
        print(formatting.." nil")
        return
    end

    if type(t) ~= "table" then
        print(formatting..get_type_first_print(t)..tostring(t))
        return
    end

    local output_count = 0
    for k,v in pairs(t) do
        local str_k = get_type_first_print(k)
        if type(v) == "table" then

            print(formatting..str_k..k.." -> ")

            util.dump_table(v, prefix, indent + 1,print)
        else
            print(formatting..str_k..k.." -> ".. get_type_first_print(v)..tostring(v))
        end
        output_count = output_count + 1
    end

    if output_count == 0 then
        print(formatting.." {}")
    end
end

return util

最后的最后:

通过传入不同参数,可以通过runCommand,可以扩展我们对mongodb的操作。

function _M.runCommand(args)
	local db = client:getDB(args.database)
	local result = db:runCommand(args)
	return result
end

参考:
lua打印table

Mongodb 更新操作update

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 《Skynet框架教程-非常详细.pdf》是一本关于Skynet框架的教程,它提供了关于Skynet框架的全面和详细的介绍。 该教程首先介绍了Skynet框架的背景和起源,以及它的特点和优势。Skynet是一个高度可扩展的分布式服务框架,具有高性能和低延迟的特点。它采用了基于actor模型的并发编程模型,并提供了丰富的工具和库来帮助开发者构建和管理分布式应用。 教程的下一部分介绍了Skynet框架的基本概念和架构。它解释了Skynet节点、服务和消息传递等核心概念,并提供了示例代码来说明这些概念的使用方法。读者可以通过这一部分了解Skynet框架的基本原理和用法。 接下来的章节详细介绍了Skynet框架的各个组件和功能。其中包括服务注册与发现、负载均衡、容错机制、监控和调试等方面。每个组件和功能都有详细的说明和示例代码,读者可以通过实践来学习和理解。 教程的最后一部分是一些实际应用案例的介绍。这些案例涵盖了不同领域和规模的应用,包括游戏服务器、在线教育平台、电子商务网站等。每个案例都详细介绍了Skynet框架在该应用中的具体应用和实现过程,对于读者来说是一个很好的参考和借鉴资料。 总之,《Skynet框架教程-非常详细.pdf》是一本很好的Skynet框架学习资料,它提供了全面而详细的内容,涵盖了Skynet框架的各个方面。无论是初学者还是有一定经验的开发者,都可以通过这本教程来学习和掌握Skynet框架的使用和开发技巧。 ### 回答2: 《Skynet框架教程-非常详细.pdf》是一本关于Skynet框架的详细教程文档,其中包含了关于Skynet框架的基本概念、核心功能、使用方法等内容。 Skynet框架是一个高性能、轻量级的分布式服务框架,适用于开发网络游戏、实时通信等高并发场景。该框架基于事件驱动模型,通过异步消息传递和多线程技术实现高并发处理能力。 在《Skynet框架教程-非常详细.pdf》中,首先介绍了Skynet框架的背景与发展历程,帮助读者了解该框架的起源和应用领域。接着详细介绍了Skynet框架的核心架构,包括节点管理、服务管理、消息传递等模块的设计与实现原理。 教程还详细介绍了Skynet框架的安装和配置,包括环境准备、编译与安装等步骤。然后,通过一系列实际案例演示了如何使用Skynet框架进行开发,包括创建节点、注册服务、消息处理、资源管理等方面的内容。 此外,教程还介绍了Skynet框架的调试和优化技巧,包括日志查看、性能测试工具的使用等方面的内容。最后,给出了一些常见问题的解答,帮助读者更好地解决在使用Skynet框架过程中遇到的困惑。 总的来说,《Skynet框架教程-非常详细.pdf》是一本适合初学者和有一定经验的开发人员的教程,通过阅读该教程可以深入了解Skynet框架的原理和使用方法,从而更好地应用于实际项目中。 ### 回答3: 《Skynet框架教程-非常详细.pdf》是一本非常详细的Skynet框架教程。Skynet框架是一个高性能、高可靠性的分布式服务框架,用于构建可扩展的游戏服务器、物联网平台等分布式应用。 这本教程从Skynet框架的基础知识讲起,介绍了Skynet框架的特点、架构和设计理念。然后详细介绍了Skynet框架的安装和配置,包括环境准备、编译安装和启动流程等。 接下来,教程深入讲解了Skynet框架的核心概念和基本用法,包括服务、消息、协议等。这些内容帮助读者理解Skynet框架的工作原理,并能够快速上手开发。 教程还介绍了Skynet框架的高级特性和扩展功能,如集群部署、负载均衡、动态扩容等。这些内容使读者能够在实际应用中解决复杂的问题,并提升系统的性能和可扩展性。 此外,教程还提供了大量的示例和实战案例,帮助读者将理论应用到实际项目中。通过这些实例,读者可以学习到如何使用Skynet框架构建真实的分布式应用,同时也能够了解到Skynet框架的一些最佳实践和常见错误。 综上所述,《Skynet框架教程-非常详细.pdf》是一本非常全面的Skynet框架教程,适合初学者和有一定经验的开发者阅读,对于了解Skynet框架的原理和使用方法都有很大帮助。无论是想要学习Skynet框架的基础知识,还是进一步提升Skynet框架应用技巧,这本教程都是一个不错的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值