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