local skynet = require "skynet" local oo = require "Class" local log = require "Log" local DBData = oo.class() --检查下是不是有新增的字段 function DBData:CheckNewFields( newTable , initTable) for key, value in pairs( initTable ) do if "table" ~= type( value[2] ) then --非表,如果未给值就必须初始化 if nil == newTable[ value[1] ] then newTable[value[1] ] = value[2] end else --是表,如果未给值必须初始化 if nil == newTable[ value[1] ] then newTable[ value[1] ] = {} end --遍历子结点 self:CheckNewFields( newTable[ value[1] ] , value[2] ) end end end --遍历用户数据 function DBData:Traversal(newData , oldData) for key, value in pairs(oldData) do if "table" ~= type(value[2]) then newData[value[1]] = value[2] else newData[value[1]] = {} newData[value[1]] = self:Parse( newData[value[1]] , value[1] ,value[2] ) end end end --解析字段 function DBData:Parse( newTable , t1 ,v2 ) if "table" ~= type(v2) then newTable[t1] =v2 else for key, value in pairs(v2) do if "table" ~= type(value[2]) then newTable[ value[1] ] = value[2] else newTable[ value[1] ]= {} newTable[ value[1] ] = self:Parse(newTable[value[1]] , value[1] , value[2]) end end end return newTable end --[[ --需要在这里增加更新玩家字段 function DBData:CheckUserVision( log ) --[[ 新增字段事例 table.insert(updateData , {"test1",0 }) test1为不存在的字段名,默认类型为0 table.insert(updateData , {"test2",{} }) test2为不存在的字段名,默认类型为{} table.insert(updateData , {"test3",{ a = 1 ,b = 2} }) test3为存在的字段名,test3是表,在test3新增a,b字段 --这里添加每个更新版本的玩家字段 local updateData = {} local sql = "" self:UpdateDBData( updateData , log ) end --更新新字段到数据库 function DBData:UpdateDBData(updateData ,log) log.info("开始更新新字段到数据库") local newData = {} local t1 = skynet.GetTime() self:Traversal(newData , updateData) --得到数据库中所有玩家数量 local sql = string.format("select count(1) from player" ) local queryData = skynet.server.db:Query(sql) local id = nil local userInfo = nil local jsonInfo = nil local modifyCount = 0 if #queryData > 0 then --一次取出太多的数据在内存中,底层会警告,为了更稳固,所以分批读取用户数据进行处理 local curUserCount = tonumber(queryData[1]["count(1)"]) local queryMaxUser = 1000 --每次从数据库中取出玩家数据的数量 local startId = 100000 --帐号的起始ID local endId = startId + curUserCount --帐号的结束ID local startPos = 0 local endPos = 0 log.info("数据库总共玩家数量", curUserCount) for pos = startId, endId , queryMaxUser do startPos = pos endPos = startPos + (queryMaxUser - 1) if endPos > endId then --如果大于结束ID,就获取最终的结束ID endPos = (startPos + ( endId - startPos)) - 1 end --根据ID获取用户信息 sql = string.format("select id,data from player where id >= %d and id <= %d",startPos ,endPos ) queryData = skynet.server.db:Query(sql) log.info(string.format("当前起始ID %d 结束ID %d 的范围 取出数量 %d ",startPos ,endPos , #queryData)) for i = 1, #queryData do id = tonumber(queryData[i]["id"]) userInfo = queryData[i]["data"] if userInfo then jsonInfo = JSON:decode(userInfo) for key, value in pairs(newData) do if jsonInfo[ key ] then for k, v in pairs(value) do jsonInfo[ key ][ k ] = v end else jsonInfo[ key ] = value end end sql = string.format("update player set data = '%s' where id = %d", JSON:encode(jsonInfo), id) skynet.server.db:Query(sql) modifyCount = modifyCount + 1 end end end end log.info("更新完所有用户需要的时间",skynet.GetTime() - t1, "秒") log.info("成功修改玩家数量",modifyCount) log.info("结束更新新字段到数据库") end ]] skynet.server.dbData = DBData return DBData