lua table怎么检查数据变了

为了缓解数据库压力,数据会缓存在lua table,满足频繁读写需求,再定时检查,发现数据变了则落地。

问题来了,lua table怎么检查数据变了?

table检查数据变了

答案很简单,使用 metatable,这里贴一个简单的例子。

-- db数据
db = {openid="openid_123", token="token_123"}

-- 缓存
cache = {}

setmetatable(cache, {
	__index = function(t, k)
		return db[k]
	end,
	__newindex = function(t, k, v)
		if k ~= "__dirty" then
			db.__dirty = true
		end
		db[k] = v
	end,
	__pairs = function(t, k)
		return next, db, k
	end,
})


for k, v in pairs(cache) do
	print(k, v)
end

cache.__dirty = nil
print("cache.__dirty", cache.__dirty)

cache.token = "token_456"
print("cache.__dirty", cache.__dirty)


执行结果如下:

> dofile("test.lua")
token   token_123
openid  openid_123
cache.__dirty      nil
cache.__dirty      true

问题到这里就结束了。

接下来,我们再提出一个问题,lua table如何检查子项为table的数据变了?

table检查子项为table的数据变了

先说思路,要遍历 table,找到所有子项的table,都设置 metatable
注意处理好两个问题:
1、值为table,table之间可能相互引用,就可能存在m对n的引用关系
2、子table下可能又有table,所有子table修改都要更新根table状态

为此,实现如下(非完整版本):

local function dirty_check(root)
	local dummy = {}
	local g_set = {}
	local function check_table(t)
		if type(t) ~= "table" then
			return
		end
		local mt = getmetatable(t)
		local tv = g_set[t]
		if not tv then
			local tv = {}
			for k, v in pairs(t) do
				check_table(v)
				tv[k] = v
				rawset(t, k, nil) -- 强制使 table 触发 newindex
			end
			g_set[t] = tv
		end
		if not mt then
			setmetatable(t, dummy)
		end
	end
	dummy.__newindex = function(t, k, v)
		if k ~= "__dirty" then
			g_set[root]["__dirty"] = true
			check_table(v)
		end
		g_set[t][k] = v -- 存在内存泄漏,v 为 table 需要清理 g_set
		
	end
	dummy.__index = function(t, k)
		return g_set[t][k]
	end
	dummy.__pairs = function(t, k)
		return next, g_set[t], k
	end
	dummy.__len = function(t)
		return #g_set[t]
	end
	check_table(root)
end

-- 例子
local tb = {1,2,3, {}}
dirty_check(tb)
for k,v in pairs(tb) do
	print(k,v)
end

print("table dirty 1", tb.__dirty)
tb[3]=1
print("table dirty 2", tb.__dirty)

tb.__dirty = nil
tb[3]=2
print("table dirty 3", tb.__dirty)

tb.__dirty = nil
local t={{},{},{},{},{}}
tb[4] = t
print("table dirty 4", tb.__dirty)


tb.__dirty = nil
t[3][1] = 1
print("table dirty 5", tb.__dirty)


tb.__dirty = nil
t[3][1] = 2
print("table dirty 6", tb.__dirty)


tb.__dirty = nil
t[3][2] = {}
print("table dirty 7", tb.__dirty)

执行结果如下:

> dofile("test.lua")
1       1
2       2
3       3
4       table: 0x7c6a20
table dirty 1   nil
table dirty 2   true
table dirty 3   true
table dirty 4   true
table dirty 5   true
table dirty 6   true
table dirty 7   true
 
 

文章最后,贴下完整版本,包含了内存泄漏的处理,有兴趣看看,有问题撩我 https://github.com/chenweiqi/lua_util

《lua table怎么检查数据变了》上有4条评论

      1. 大佬有空方便技术交流下嘛(联系方式,取取经),看了大佬大部分csdn的博客,感觉大佬的理解对于新人很有启发

发表评论

邮箱地址不会被公开。 必填项已用*标注