skynet框架应用 (十六) mysql

16 mysql

​ skynet封装了mysql的驱动,主要文件为 lualib/skynet/db/mysql.lua。

先在ubuntu下安装mysql


sudo apt-get install mysql-server

设置mysql的用户密码为root 123456,并且创建一个skynet数据库。

16.1 连接mysql

连接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

16.2 执行SQL语句

​ 执行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

16.3 db:query的调度情况

​ 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返回。

你可能感兴趣的:(skynet)