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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章