skynet封装了mysql的驱动,主要文件为 lualib/skynet/db/mysql.lua。
先在ubuntu下安装mysql
sudo apt-get install mysql-server
设置mysql的用户密码为root 123456,并且创建一个skynet数据库。
连接mysql的API
local skynet = require "skynet" local mysql = require "skynet.db.mysql" --引入模块 --连接成功db返回非nil local db=mysql.connect({ host="127.0.0.1", port=3306, database="skynet", user="root", password="123456", max_packet_size = 1024 * 1024, --数据包最大字节数 on_connect = on_connect --连接成功的回调函数 }) --关闭连接 db:disconnect()
示例代码connectmysql.lua:
local skynet = require "skynet" local mysql = require "skynet.db.mysql" skynet.start(function() local function on_connect(db) skynet.error("on_connect") end local db=mysql.connect({ host="127.0.0.1", port=3306, database="skynet", user="root", password="123456", max_packet_size = 1024 * 1024, on_connect = on_connect }) if not db then skynet.error("failed to connect") else skynet.error("success to connect to mysql server") end db:disconnect() --关闭连接 end)
在mysql中先创建一个skynet数据库然后再运行:
connectmysql [:0100000a] LAUNCH snlua connectmysql [:0100000a] on_connect [:0100000a] success to connect to mysql server
执行SQL语句可以使用db:query(sql),参数sql可以填任何你想要执行的SQL语句。
示例代码querymysql.lua
local skynet = require "skynet" local mysql = require "skynet.db.mysql" local function dump(res, tab) tab = tab or 0 if(tab == 0) then skynet.error("............dump...........") end if type(res) == "table" then skynet.error(string.rep("\t", tab).."{") for k,v in pairs(res) do if type(v) == "table" then dump(v, tab + 1) else skynet.error(string.rep("\t", tab), k, "=", v, ",") end end skynet.error(string.rep("\t", tab).."}") else skynet.error(string.rep("\t", tab) , res) end end skynet.start(function() local function on_connect(db) skynet.error("on_connect") end local db=mysql.connect({ host="127.0.0.1", port=3306, database="skynet", user="root", password="123456", max_packet_size = 1024 * 1024, on_connect = on_connect }) if not db then skynet.error("failed to connect") skynet.exit() else skynet.error("success to connect to mysql server") end --设置utf8字符集 local res = db:query("set charset utf8"); dump(res) --删除数据表 res = db:query("drop table if exists dogs") dump(res) --创建数据表 res = db:query("create table dogs (id int primary key,name varchar(10))") dump(res) --插入数据 res = db:query("insert into dogs values (1, \'black\'), (2, \'red\')") dump(res) --查询数据 res = db:query("select * from dogs") dump(res) --多条语句查询 res = db:query("select * from dogs; select * from dogs") dump(res) --查询错误 res = db:query("select * from noexist;") dump(res) db:disconnect() --关闭连接 skynet.exit() end)
运行结果:
querymysql [:0100000a] LAUNCH snlua querymysql [:0100000a] on_connect [:0100000a] success to connect to mysql server [:0100000a] ............dump........... [:0100000a] { [:0100000a] server_status = 2 , #状态2表示成功 [:0100000a] warning_count = 0 , [:0100000a] affected_rows = 0 , [:0100000a] insert_id = 0 , [:0100000a] } [:0100000a] ............dump........... [:0100000a] { [:0100000a] server_status = 2 , [:0100000a] warning_count = 0 , [:0100000a] affected_rows = 0 , [:0100000a] insert_id = 0 , [:0100000a] } [:0100000a] ............dump........... [:0100000a] { [:0100000a] server_status = 2 , [:0100000a] warning_count = 0 , [:0100000a] affected_rows = 0 , [:0100000a] insert_id = 0 , [:0100000a] } [:0100000a] ............dump........... [:0100000a] { [:0100000a] message = &Records: 2 Duplicates: 0 Warnings: 0 , [:0100000a] warning_count = 0 , [:0100000a] server_status = 2 , [:0100000a] affected_rows = 2 , [:0100000a] insert_id = 0 , [:0100000a] } [:0100000a] ............dump........... [:0100000a] { #查询数据,返回一张表 [:0100000a] { [:0100000a] id = 1 , [:0100000a] name = black , [:0100000a] } [:0100000a] { [:0100000a] id = 2 , [:0100000a] name = red , [:0100000a] } [:0100000a] } [:0100000a] ............dump........... [:0100000a] { [:0100000a] { [:0100000a] { [:0100000a] id = 1 , [:0100000a] name = black , [:0100000a] } [:0100000a] { [:0100000a] id = 2 , [:0100000a] name = red , [:0100000a] } [:0100000a] } [:0100000a] { [:0100000a] { [:0100000a] id = 1 , [:0100000a] name = black , [:0100000a] } [:0100000a] { [:0100000a] id = 2 , [:0100000a] name = red , [:0100000a] } [:0100000a] } [:0100000a] mulitresultset = true , #多条sql语句执行结果中mulitresultset为true [:0100000a] } [:0100000a] ............dump........... [:0100000a] { [:0100000a] errno = 1146 , [:0100000a] badresult = true , [:0100000a] sqlstate = 42S02 , [:0100000a] err = Table 'skynet.noexist' doesn't exist , [:0100000a] } [:0100000a] KILL self
db:query通过给mysql服务端发送sql语句,并且阻塞等待mysql服务端返回结果,这个过程当中,db.query
会自动让出当前协程的执行权,等待skynet的下次调度。
来看一个例子:
testquerymysql.lua
local skynet = require "skynet" local mysql = require "skynet.db.mysql" local function test( db , name) local i=1 while true do local res = db:query("select * from dogs") --每个协程十秒查询两遍 skynet.error(name, "loop times=", i, res) res = db:query("select * from dogs") skynet.error(name, "loop times=",i, res) skynet.sleep(1000) i=i+1 end end skynet.start(function() local function on_connect(db) skynet.error("on_connect") end local db=mysql.connect({ host="127.0.0.1", port=3306, database="skynet", user="root", password="123456", max_packet_size = 1024 * 1024, on_connect = on_connect }) if not db then skynet.error("failed to connect") skynet.exit() else skynet.error("success to connect to mysql server") end skynet.fork(test, db, "test0") skynet.fork(test, db, "test1") skynet.fork(test, db, "test2") end)
运行结果:
$ ./skynet examples/config testqureymysql [:0100000a] LAUNCH snlua testqureymysql [:0100000a] on_connect [:0100000a] success to connect to mysql server [:0100000a] test0 loop times= 1 table: 0x7fc0e4a937c0 #协程test0的两次查询并没有都执行完,因为db.query会让出协程执行权限 [:0100000a] test1 loop times= 1 table: 0x7fc0e4a93a80 [:0100000a] test2 loop times= 1 table: 0x7fc0e4a93d40 [:0100000a] test0 loop times= 1 table: 0x7fc0e4b07040 [:0100000a] test1 loop times= 1 table: 0x7fc0e4b07300 [:0100000a] test2 loop times= 1 table: 0x7fc0e4b075c0 [:0100000a] test0 loop times= 2 table: 0x7fc0e4afd680 [:0100000a] test1 loop times= 2 table: 0x7fc0e4afd940 [:0100000a] test2 loop times= 2 table: 0x7fc0e4afdc00 [:0100000a] test0 loop times= 2 table: 0x7fc0e4afdec0 [:0100000a] test1 loop times= 2 table: 0x7fc0e4b081c0 [:0100000a] test2 loop times= 2 table: 0x7fc0e4b08480
上面开了三个协程每十秒分别调用两次db.query,但是test0协程并没有一次性把两次调用给执行完,而是调用完一次db.query阻塞让出执行权,然后test1调用阻塞让出执行权,test2调用也阻塞让出执行权,三个协程都在等待资源,这个时候资源到达是通过skynet框架来通知,再分别上test0、test1、test2从db.query返回。