文章目录
  1. 1. lua 模块
    1. 1.1. require函数
    2. 1.2. 加载机制
  2. 2. openresty 实践
    1. 2.1. 设置module路径
    2. 2.2. 设计module
    3. 2.3. yield问题
    4. 2.4. 使用
  3. 3. 参考
    1. 3.1. 参考1:设置环境变量的方式:
    2. 3.2. 坑:再次打开终端环境变量失效

最近用openresty写接口,每个接口都要要链接数据库,写一个通用的模块来实现,顺便学习下lua module的相关知识。

lua 模块

Lua中的一个模块就是一个table,table元素包括变量,函数等。“因此创建一个模块很简单,就是创建一个 table,然后把需要导出的常量、函数放入其中,最后返回这个 table”。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
-- 文件名为 module.lua
-- 定义一个名为 module 的模块
module = {}

-- 定义一个常量
module.constant = "这是一个常量"

-- 定义一个函数
function module.func1()
io.write("这是一个公有函数!\n")
end

local function func2()
print("这是一个私有函数!")
end

function module.func3()
func2()
end

return module

require函数

require函数用来加载模块。

1
2
3
require("<模块名>")
-- 或
require"<模块名>"

也可以给模块一个别名,方便调用

1
2
3
local m = require("module")

m.func1

加载机制

对于我们自定义的模块,并不是放在那个目录都行,require有一套自己的文件加载机制。

require 用于搜索 Lua 文件的路径是存放在全局变量 package.path 中,当 Lua 启动后,会以环境变量 LUA_PATH 的值来初始这个环境变量。如果没有找到该环境变量,则使用一个编译时定义的默认路径来初始化。

如果我们设置LUA_PATH环境变量(参考1)

1
2
#LUA_PATH
export LUA_PATH="~/lua/?.lua"

那么调用 require(“module”) 时就会尝试打开以下文件目录去搜索目标。

1
2
3
4
5
6
/Users/dengjoe/lua/module.lua;
./module.lua
/usr/local/share/lua/5.1/module.lua
/usr/local/share/lua/5.1/module/init.lua
/usr/local/lib/lua/5.1/module.lua
/usr/local/lib/lua/5.1/module/init.lua

openresty 实践

写一个链接数据库的module

设置module路径

在openresty中设置module路径的方式:

1
lua_package_path 'lua/?.lua;/Users/zhangpan/Project/XinanServer/XinanServer/lua/module/?.lua;;';

其中lua/?.lua; 代表的绝对路径是 ~/lua/?.lua;;后面一个是绝对路径。

设计module

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
xinandb = {}

-- 创建数据库链接实例
local mysql = require "resty.mysql"

xinandb.db = mysql:new()

-- 连接数据库
function xinandb.connect()
if not xinandb.db then
return false
end

local ok, err, errno, sqlstate = (xinandb.db):connect {
host = "127.0.0.1",
port = 3306,
database = "xinan",
user = "***",
password = "***",
max_packet_size = 1024 * 1024 }
return ok
end

return xinandb

yield问题

这里遇到的一个问题:开始想创建db时就直接链接

1
2
3
4
5
6
7
8
9
xinandb.db = mysql:new()

local ok, err, errno, sqlstate = (xinandb.db):connect {
host = "127.0.0.1",
port = 3306,
database = "xinan",
user = "***",
password = "***",
max_packet_size = 1024 * 1024 }

这样就会报一个错误

[error] 7091#0: *291 lua entry thread aborted: runtime error: attempt to yield across C-call boundary

最终参考文章关于在config.lua中加入resolver包,出现跨界问题解决。

解决方式:把连接数据库操作封装在一个函数中供调用。

使用

使用就比较简单了,和其他一样

1
2
3
4
5
6
7
8
-- 连接DB
local xinandb = require("xinandb")
local res = xinandb:connect()
if not res then
ngx.say("{\"errorCode\" : 1003, \"errorMessage\" : \"连接数据库错误\"}")
return
end
local db = xinandb.db;

参考

参考1:设置环境变量的方式:

如果没有 LUA_PATH 这个环境变量,也可以自定义设置,在当前用户根目录下打开 .profile文件(没有则创建,打开 .bashrc 文件也可以),例如把 “~/lua/“ 路径加入 LUA_PATH 环境变量里;

然后执行

1
source ~/.profile

坑:再次打开终端环境变量失效

用的是Mac系统,shell是zsh。按照上面的方式设置了环境变量后,关闭终端,再次打开后环境变量就失效了。

解决方式:将LUA_PATH添加到.zshrc 执行

1
source ~/.zshrc