openresty開發系列28--openresty中操作mysql


openresty開發系列28--openresty中操作mysql

Mysql客戶端
   應用中最常使用的就是數據庫了,尤其mysql數據庫,那openresty lua如何操作mysql呢?
   默認安裝OpenResty時已經自帶了該模塊。


案例,mysql數據庫的常用操作,編輯testmysql.lua

# centos7中安裝mariadb
# yum install -y mariadb-server mariadb
# systemctl start mariadb-server
# 設置root密碼為'root'
# update mysql.user set password=PASSWORD('root') where user='root' and host='localhost';

# 創建測試的數據庫openresty
create database openresty charset='utf8mb4';

# 測試nginx配置
# nginx.conf
location /testmysql {
        content_by_lua_file /usr/local/lua/testmysql.lua;
    }

# vim /usr/local/lua/testmysql.lua

local function close_db(db)
    if not db then
        return
    end
    db:close()
end

-- 引入mysql實例
local mysql = require("resty.mysql")
--創建實例
local db, err = mysql:new()
if not db then
    ngx.say("new mysql error : ", err)
    return
end

--設置超時時間(毫秒)
db:set_timeout(10000)

--定義連接屬性
local props = {
    host = "127.0.0.1",
    port = 3306,
    database = 'openresty',
    user = 'root',
    password = 'root',
    charset = 'utf8'
}


local res,err,errno,sqlstate = db:connect(props)
if not res then
    ngx.say("connect to mysql error:", err,", errno:", errno,", sqlstate:", sqlstate)
    return close_db(db)
end

--我們對數據庫進行crud,統一的操作方法 query
--不同於其他語言 insert update delete select

ngx.say("----------刪除表user----------------","<br/>")

--刪除表
local drop_table_sql = "drop table if exists user"
res, err, errno, sqlstate = db:query(drop_table_sql)
if not res then
    ngx.say("drop table error :", err,", errno", errno, ", sqlstate : ",sqlstate)
    return close_db(db)
end

ngx.say("----------創建表user----------------","<br/>")

local create_table_sql = "create table user(id int primary key auto_increment,username varchar(100))"
res, err, errno, sqlstate = db:query(create_table_sql)
if not res then
    ngx.say("create table error :", err,", errno", errno, ", sqlstate : ",sqlstate)
    return close_db(db)
end

ngx.say("----------插入數據user----------------","<br/>")
local insert_table_sql = "insert into user(username) values('jack'),('lucy'),('tom'),('lily')"
res, err, errno, sqlstate = db:query(insert_table_sql)
if not res then
    ngx.say("insert table error :", err,", errno", errno, ", sqlstate : ",sqlstate)
    return close_db(db)
end

res, err, errno, sqlstate = db:query(insert_table_sql)

ngx.say("insert rows :", res.affected_rows,", id", res.insert_id, "<br/>")


ngx.say("----------更新表user----------------","<br/>")

local update_sql = "update user set username = 'lucy' where id = " .. res.insert_id
res, err, errno, sqlstate = db:query(update_sql)
if not res then
    ngx.say("update table error :", err,", errno", errno, ", sqlstate : ",sqlstate)
    return close_db(db)
end

ngx.say("update rows :",res.affected_rows, "<br/>")

ngx.say("----------查詢表user----------------","<br/>")

--查詢
local select_sql = "select id,username from user"
res, err, errno, sqlstate = db:query(select_sql)
if not res then
    ngx.say("select table error :", err,", errno", errno, ", sqlstate : ",sqlstate)
    return close_db(db)
end

for i, row in ipairs(res) do
    for username,value in pairs(row) do
        ngx.say("select row", i," : ", username, " = ", value, "<br/>")
    end
end

ngx.say("----------刪除user----------------","<br/>")

local ch_param = ngx.req.get_uri_args()["ch"] or ''
--local query_sql = "select id,username from user where username = " .. ngx.quote_sql_str(ch_param)
local query_sql = "select id,username from user where username = " .. ch_param
ngx.say(query_sql,"<br/>")
res, err, errno, sqlstate = db:query(query_sql)
if not res then
   ngx.say("select error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)
   return close_db(db)
end

for i,row in ipairs(res) do
    for username,value in pairs(row) do
        ngx.say("select row ",i," : ",username, " = ",value,"<br/>")
    end
end



ngx.say("=========關閉db===========", "<br/>")

close_db(db)

======================================

對於新增/修改/刪除會返回如下格式的響應:
{
    insert_id = 0,     ----insert_id是在使用自增序列時產生的id。
    server_status = 2,
    warning_count = 1,
    affected_rows = 32,   ----affected_rows表示操作影響的行數
    message = nil
}

對於查詢會返回如下格式的響應:
{
    { id= 1, ch= "hello"},
    { id= 2, ch= "hello2"}
}
null將返回ngx.null。

訪問請求http://10.11.0.215/testmysql
輸出結果
start connect
end connect mysql
----------刪除表user----------------
----------創建表user----------------
----------插入數據user----------------
insert rows :4, id5
----------更新表user----------------
update rows :1
----------查詢表user----------------
select row1 : username = jack
select row1 : id = 1
select row2 : username = lucy
select row2 : id = 2
select row3 : username = tom
select row3 : id = 3
select row4 : username = lily
select row4 : id = 4
select row5 : username = lucy
select row5 : id = 5
select row6 : username = lucy
select row6 : id = 6
select row7 : username = tom
select row7 : id = 7
select row8 : username = lily
select row8 : id = 8
----------刪除user----------------
=========關閉db===========



===========查詢user=根據ch參數=======
select row 1 : ch = hello
select row 1 : id = 1
===========刪除user========
delete rows : 2
===========關閉db========

注意:

客戶端目前還沒有提供預編譯SQL支持(即占位符替換位置變量),
這樣在入參時記得使用ngx.quote_sql_str進行字符串轉義,防止sql注入;


--防止sql注入

local ch_param = ngx.req.get_uri_args()["ch"] or ''
--local query_sql = "select id,username from user where username = " .. ngx.quote_sql_str(ch_param)
-- 不使用quote_sql_str防注入
local query_sql = "select id,username from user where username = " .. ch_param
ngx.say(query_sql,"<br/>")
res, err, errno, sqlstate = db:query(query_sql)
if not res then
   ngx.say("select error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)
   return close_db(db)
end

for i,row in ipairs(res) do
    for username,value in pairs(row) do
        ngx.say("select row ",i," : ",username, " = ",value,"<br/>")
    end
end

當我們沒有使用quote_sql_str時,使用如下查詢語句,會把數據表中的所有數據查詢出來

http://10.11.0.215/testmysql?ch='jack' or 1=1

select id,username from user where username = 'jack' or 1=1
select row 1 : username = jack
select row 1 : id = 1
select row 2 : username = lucy
select row 2 : id = 2
select row 3 : username = tom
select row 3 : id = 3
select row 4 : username = lily
select row 4 : id = 4
select row 5 : username = lucy
select row 5 : id = 5
select row 6 : username = lucy
select row 6 : id = 6
select row 7 : username = tom
select row 7 : id = 7
select row 8 : username = lily
select row 8 : id = 8
=========關閉db===========

==========================================

連接池和之前Redis客戶端完全一樣。
local function close_db(db)  
    if not db then  
        return  
    end  
    --釋放連接(連接池實現)  
    local pool_max_idle_time = 10000 --毫秒  
    local pool_size = 100 --連接池大小  
    local ok, err = db:set_keepalive(pool_max_idle_time, pool_size)  
    if not ok then  
        ngx.say("set keepalive error : ", err)  
    end  
end  


更多資料 https://github.com/openresty/lua-resty-mysql
sqlstate https://blog.csdn.net/tercel99/article/details/1520094

 

testmysql.lua

[root@node5 conf]# cat /usr/local/lua/testredis.lua 
-- --定義redis關閉連接的方法
local function close_redis(red)
    if not red then
        return
    end
    --釋放連接(連接池實現)
    local pool_max_idle_time = 1000 --毫秒
    local pool_size = 100 --連接池大小
    local ok,err = red:set_keepalive(pool_max_idle_time, pool_size)
    if not ok then
        ngx.say("set keepalive error: ",err)
    end
end
-- 引入redis模塊
local redis = require "resty.redis" 
-- 創建一個對象,注意是用冒號調用的
local red = redis:new()
-- 設置超時(毫秒)
red:set_timeout(1000)
--建立連接
local ip = "10.11.0.215"
local port = 6379
local ok, err = red:connect(ip, port)
if not ok then
    ngx.say("connect to redis error : ", err)
    return close_redis(red)
end

-- 如果使用連接池,不需要每次都使用密碼
local count, err = red:get_reused_times()
if 0 == count then
    ok, err = red:auth("redis123")
    if not ok then
        ngx.say("faied to auth:", err)
        return
    end
elseif err then
    ngx.say("failed to get reused times:",err)
    return
end


--調用API設置key
ok, err = red:set("msg", "hello world")

if not ok then
    ngx.say("set msg error :", err)
    return close_redis(red)
end

-- 調用API獲取key值
local resp, err = red:get("msg1")
if not resp then
    ngx.say("get msg error:",err)
    return close_redis(red)
end

if resp == ngx.null then
    resp = 'hello lua'
end

ngx.say("msg:",resp)
close_redis(red)
[root@node5 conf]# cat /usr/local/lua/testmy
cat: /usr/local/lua/testmy: No such file or directory
[root@node5 conf]# cat /usr/local/lua/testmy
testmyredis.lua  testmysql.lua    
[root@node5 conf]# cat /usr/local/lua/testmysql.lua 
local function close_db(db)  
    if not db then  
        return  
    end  
    --釋放連接(連接池實現)  
    local pool_max_idle_time = 10000 --毫秒  
    local pool_size = 100 --連接池大小  
    local ok, err = db:set_keepalive(pool_max_idle_time, pool_size)  
    if not ok then  
        ngx.say("set keepalive error : ", err)  
    end  
end

-- 引入mysql實例
local mysql = require("resty.mysql")
--創建實例
local db, err = mysql:new()
if not db then
    ngx.say("new mysql error : ", err)
    return
end

--設置超時時間
db:set_timeout(10000)

--定義連接屬性
local props = {
    host = "127.0.0.1",
    port = 3306,
    database = 'openresty',
    user = 'root',
    password = 'root',
    charset = 'utf8'
}

ngx.say("start connect","<br/>")
local res,err,errno,sqlstate = db:connect(props)
if not res then
    ngx.say("connect to mysql error:", err,", errno:", errno,", sqlstate:", sqlstate)
    return close_db(db)
end

ngx.say("end connect mysql","<br/>")

ngx.say("----------刪除表user----------------","<br/>")

--刪除表
local drop_table_sql = "drop table if exists user"
res, err, errno, sqlstate = db:query(drop_table_sql)
if not res then
    ngx.say("drop table error :", err,", errno", errno, ", sqlstate : ",sqlstate)
    return close_db(db)
end

ngx.say("----------創建表user----------------","<br/>")
local create_table_sql = "create table user(id int primary key auto_increment,username varchar(100))"
res, err, errno, sqlstate = db:query(create_table_sql)
if not res then
    ngx.say("create table error :", err,", errno", errno, ", sqlstate : ",sqlstate)
    return close_db(db)
end

ngx.say("----------插入數據user----------------","<br/>")
local insert_table_sql = "insert into user(username) values('jack'),('lucy'),('tom'),('lily')"
res, err, errno, sqlstate = db:query(insert_table_sql)
if not res then
    ngx.say("insert table error :", err,", errno", errno, ", sqlstate : ",sqlstate)
    return close_db(db)
end

res, err, errno, sqlstate = db:query(insert_table_sql)

ngx.say("insert rows :", res.affected_rows,", id", res.insert_id, "<br/>")


ngx.say("----------更新表user----------------","<br/>")

local update_sql = "update user set username = 'lucy' where id = " .. res.insert_id
res, err, errno, sqlstate = db:query(update_sql)
if not res then
    ngx.say("update table error :", err,", errno", errno, ", sqlstate : ",sqlstate)
    return close_db(db)
end

ngx.say("update rows :",res.affected_rows, "<br/>")

ngx.say("----------查詢表user----------------","<br/>")

--查詢
local select_sql = "select id,username from user"
res, err, errno, sqlstate = db:query(select_sql)
if not res then
    ngx.say("select table error :", err,", errno", errno, ", sqlstate : ",sqlstate)
    return close_db(db)
end

for i, row in ipairs(res) do
    for username,value in pairs(row) do
        ngx.say("select row", i," : ", username, " = ", value, "<br/>")
    end
end

ngx.say("----------刪除user----------------","<br/>")

local ch_param = ngx.req.get_uri_args()["ch"] or ''
--local query_sql = "select id,username from user where username = " .. ngx.quote_sql_str(ch_param)
local query_sql = "select id,username from user where username = " .. ch_param
ngx.say(query_sql,"<br/>")
res, err, errno, sqlstate = db:query(query_sql)
if not res then
   ngx.say("select error : ", err, " , errno : ", errno, " , sqlstate : ", sqlstate)
   return close_db(db)
end

for i,row in ipairs(res) do
    for username,value in pairs(row) do
        ngx.say("select row ",i," : ",username, " = ",value,"<br/>")
    end
end



ngx.say("=========關閉db===========", "<br/>")

close_db(db)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM