From 0de8032172753afc3fc17487908f40b5c56d5c19 Mon Sep 17 00:00:00 2001 From: liuzujun <307836273@qq.com> Date: Fri, 26 Feb 2021 17:48:07 +0800 Subject: [PATCH] 创建游戏数据库,role对应mysql数据表,以及存储读取实现 --- src/actions/HttpAction.lua | 2 +- src/actions/RoleAction.lua | 14 +++++++------- src/agent.lua | 1 + src/main.lua | 7 +++++++ src/models/Role.lua | 17 +++++++++-------- src/services/dbseed.lua | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- src/services/mysqld.lua | 42 ++++++++++++++++++++++++++++++++++++++++++ src/shared/ModelBaseMysql.lua | 466 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/shared/mysqlproxy.lua | 34 ++++++++++++++++++++++++++++++++++ 9 files changed, 656 insertions(+), 23 deletions(-) create mode 100644 src/services/mysqld.lua create mode 100644 src/shared/ModelBaseMysql.lua create mode 100644 src/shared/mysqlproxy.lua diff --git a/src/actions/HttpAction.lua b/src/actions/HttpAction.lua index eff3d01..0475060 100644 --- a/src/actions/HttpAction.lua +++ b/src/actions/HttpAction.lua @@ -134,7 +134,7 @@ function _M.gm_action(query) return isOn end -- 离线操作 - local role = require("models.Role").new({key = string.format("role:%d", query.id)}) + local role = require("models.Role").new({key = string.format("%d", query.id)}) local ret = role:load() if not ret then return "角色不存在" diff --git a/src/actions/RoleAction.lua b/src/actions/RoleAction.lua index 392f485..5048c8e 100644 --- a/src/actions/RoleAction.lua +++ b/src/actions/RoleAction.lua @@ -84,12 +84,12 @@ function _M.loginRpc( agent, data ) local role = agent.role -- 2 if not role then - local roleKey = string_format("role:%d", roleId) - if not redisproxy:exists(roleKey) then - response.result = "DB_ERROR" - SendPacket(actionCodes.Role_loginRpc, MsgPack.pack(response)) - return true - end + local roleKey = string_format("%d", roleId) + --if not redisproxy:exists(roleKey) then + -- response.result = "DB_ERROR" + -- SendPacket(actionCodes.Role_loginRpc, MsgPack.pack(response)) + -- return true + --end -- 2a role = require("models.Role").new({key = roleKey}) role:load() @@ -333,7 +333,7 @@ function _M.createRpc(agent, data) end local roleName = setRoleName(msg.uid, roleId) local newRole = require("models.Role").new({ - key = string_format("role:%d", roleId), + key = string_format("%d", roleId), id = roleId, uid = tostring(msg.uid), sid = msg.subId or 0, diff --git a/src/agent.lua b/src/agent.lua index 2232513..1d7229e 100644 --- a/src/agent.lua +++ b/src/agent.lua @@ -12,6 +12,7 @@ local xxtea = require "xxtea" skynet = require "skynet" redisproxy = require "shared.redisproxy" +mysqlproxy = require "shared.mysqlproxy" datacenter = require "skynet.datacenter" mcast_util = require "services/mcast_util" csvdb = require "shared.csvdata" diff --git a/src/main.lua b/src/main.lua index 8938470..6cfc3a0 100644 --- a/src/main.lua +++ b/src/main.lua @@ -21,6 +21,13 @@ skynet.start(function() }) end + -- 启动mysql + for i = 1, work_count do + local redisd = skynet.newservice("services/mysqld", i) + skynet.call(redisd, "lua", "open", { + }) + end + --启动log if use_logd == 1 then for i = 1, work_count * 2 do diff --git a/src/models/Role.lua b/src/models/Role.lua index 6ad8695..c6bc2d9 100644 --- a/src/models/Role.lua +++ b/src/models/Role.lua @@ -1,4 +1,4 @@ -local Role = class("Role", require("shared.ModelBase")) +local Role = class("Role", require("shared.ModelBaseMysql")) local RoleLog = import(".RoleLog") --日志相关 local RolePlugin = import(".RolePlugin") --基础功能 @@ -40,11 +40,12 @@ function Role:ctor( properties ) self.sendMailFlag = false --发送邮件标识 end +-- type, default value, key type, length Role.schema = { - id = {"number"}, + id = {"number", 0, "pri"}, uid = {"string", ""}, name = {"string", ""}, - intro = {"string", ""}, + intro = {"string", "", "", 1024}, headId = {"number", globalCsv.defaultHead}, sid = {"number", 0}, device = {"string", ""}, @@ -61,11 +62,11 @@ Role.schema = { diamond = {"number", 0}, reDiamond = {"number", 0}, setting = {"table", {}}, --设置 - codeStr = {"string", ""}, --已经领过的礼包码 + codeStr = {"string", "", "blob"}, --已经领过的礼包码 -- roleInfo level = {"number", 1}, exp = {"number", 0}, - items = {"string", ""}, + items = {"string", "", "blob"}, expireItem = {"table", {}}, --物品过期检查 funcOpen = {"table", {}}, --功能是否开放 funcLv = {"table", {}}, --功能等级 @@ -77,7 +78,7 @@ Role.schema = { --冒险相关 advPass = {"table", {}}, -- 通关记录 {chapterId = layer} - advItems = {"string", ""}, -- 冒险临时背包 + advItems = {"string", "", "blob"}, -- 冒险临时背包 advInfo = {"table", {}}, -- 冒险关卡信息 advTeam = {"table", {}}, -- 冒险玩家队伍信息 advHang = {"table", {}}, -- 挂机信息 -- {chapterId = {format = teaminfo, time = endtime}} @@ -118,8 +119,8 @@ Role.schema = { bonusStar = {"table", {}}, -- 奖励关卡 通关星星 {[id] = 1} 三个二进制位 表示三个星 从低到高 (1 << 0) (1 << 1) (1 << 2) 满星 (1 << 3) - 1 --引导相关 - newerGuide = {"string","1=1"}, -- 新手引导 master=slave - funcGuide = {"string",""}, -- 功能引导 0=0跳过次数(999永久跳过) 1=1功能1触发情况 + newerGuide = {"string","1=1", "", 10}, -- 新手引导 master=slave + funcGuide = {"string","", "blob"}, -- 功能引导 0=0跳过次数(999永久跳过) 1=1功能1触发情况 pvpTC = {"table", {}}, -- pvp 编队普通 pvpTSC = {"table", {}}, -- pvp 他人可读的队伍信息 diff --git a/src/services/dbseed.lua b/src/services/dbseed.lua index 62d7052..eeeec54 100644 --- a/src/services/dbseed.lua +++ b/src/services/dbseed.lua @@ -8,6 +8,7 @@ require "skynet.manager" skynet = require "skynet" redisproxy = require("shared.redisproxy") +mysqlproxy = require "shared.mysqlproxy" SendPacket = function ( ... ) end @@ -26,22 +27,103 @@ local function initRedisDb( ... ) end end +-- 初始化服务器数据库以及服务器信息表 +local function initServerDatabase() + local servId = skynet.getenv("servId") + mysqlproxy:query(string.format("CREATE DATABASE IF NOT EXISTS server_%s DEFAULT CHARSET = utf8mb4 COLLATE utf8mb4_general_ci;", servId)) + mysqlproxy:query(string.format("use server_%s", servId)) + + -- 服务器信息表 开服时间 + mysqlproxy:query [[ + CREATE TABLE IF NOT EXISTS `server_info` ( + `key` varchar(45) NOT NULL, + `int_value` int(11) DEFAULT NULL, + `str_value` varchar(128) DEFAULT NULL, + PRIMARY KEY (`key`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + ]] + + local res = mysqlproxy:query("SELECT * FROM `server_info` where `key` = 'server_start';") + if not next(res) then + mysqlproxy:query(string.format("INSERT INTO `server_info`(`key`, `str_value`) VALUES('server_start', '%s');", + os.date("%Y%m%d", skynet.timex()))) + end +end + +local function initAutoIncreUidTable() + mysqlproxy:query [[ + CREATE TABLE IF NOT EXISTS `auto_increment_uid` ( + `key` varchar(45) NOT NULL, + `value` int(11) DEFAULT NULL, + PRIMARY KEY (`key`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + ]] + local servId = tonumber(skynet.getenv("servId")) + if servId then + local tpl = "INSERT INTO `auto_increment_uid`(`key`, `value`) values('%s', %d)" + mysqlproxy:query(string.format(tpl, "role", servId * MAX_ROLE_NUM)) + mysqlproxy:query(string.format(tpl, "union", servId * MAX_ROLE_NUM)) + mysqlproxy:query(string.format(tpl, "trade", servId * MAX_ROLE_NUM * 100)) + mysqlproxy:query(string.format(tpl, "email", 0)) + mysqlproxy:query(string.format(tpl, "emailTimestamp", 0)) + mysqlproxy:query(string.format(tpl, "delay_email", 0)) + end +end + +local function initAdvSeasonTable() + mysqlproxy:query [[ + CREATE TABLE IF NOT EXISTS `adv_season` ( + `key` varchar(45) NOT NULL, + `value` int(11) DEFAULT NULL, + PRIMARY KEY (`key`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + ]] + local servId = tonumber(skynet.getenv("servId")) + if servId then + local tpl = "INSERT INTO `adv_season`(`key`, `value`) values('%s', %d)" + + mysqlproxy:query(string.format(tpl, "idx", 0)) + mysqlproxy:query(string.format(tpl, "chapter", globalCsv.adv_endless_default_chapter)) + mysqlproxy:query(string.format(tpl, "overTime", 0)) + end +end + +local function checkRoleTables() + local role = require("models.Role").new({key = "key"}) + role:checkTableSchema() +end + local steps = { [1] = { handler = initRedisDb, desc = "initialize redis database " + }, + [2] = { + handler = initServerDatabase, + desc = "initialize server database " + }, + [3] = { + handler = initAutoIncreUidTable, + desc = "initialize auto_increment_uid table " + }, + [4] = { + handler = initAdvSeasonTable, + desc = "initialize adv_season table " + }, + [5] = { + handler = checkRoleTables, + desc = "check role tables " } } skynet.start(function () redisproxy = require("shared.redisproxy") - - local new = redisproxy:hsetnx("autoincrement_set", "server_start", os.date("%Y%m%d", skynet.timex())) == 1 - if not new then - print("server has been initialized...") - skynet.exit() - return - end + --local new = redisproxy:hsetnx("autoincrement_set", "server_start", os.date("%Y%m%d", skynet.timex())) == 1 + --if not new then + -- print("server has been initialized...") + -- skynet.exit() + -- return + --end csvdb = require "shared.csvdata" globalCsv = csvdb["GlobalDefineCsv"] diff --git a/src/services/mysqld.lua b/src/services/mysqld.lua new file mode 100644 index 0000000..2ba3a1f --- /dev/null +++ b/src/services/mysqld.lua @@ -0,0 +1,42 @@ +local skynet = require "skynet" +require "skynet.manager" +local mysql = require "skynet.db.mysql" + +local db +local idx = ... +local command = {} + +function command.open(conf) + local function on_connect(db) + db:query("set charset utf8mb4"); + end + db=mysql.connect({ + host="127.0.0.1", + port=3306, + database="mysql", + user="root", + password="123456", + max_packet_size = 1024 * 1024, + on_connect = on_connect + }) + if not db then + print("failed to connect") + end + local servId = skynet.getenv("servId") + db:query(string.format("use server_%s", servId)) +end + +skynet.start(function() + skynet.dispatch("lua", function(session, address, cmd, ...) + if cmd == "open" then + local f = command[string.lower(cmd)] + skynet.ret(skynet.pack(f(...))) + else + skynet.ret(skynet.pack(db[string.lower(cmd)](db, ...))) + end + end) + skynet.info_func(function() + return skynet.stat("mqlen") + end) + skynet.register(".mysql" .. idx) +end) \ No newline at end of file diff --git a/src/shared/ModelBaseMysql.lua b/src/shared/ModelBaseMysql.lua new file mode 100644 index 0000000..5c21249 --- /dev/null +++ b/src/shared/ModelBaseMysql.lua @@ -0,0 +1,466 @@ +local ModelBaseMysql = class("ModelBaseMysql") +ModelBaseMysql.key = "key" +ModelBaseMysql.schema = {} + +local string_format = string.format +local table_insert = table.insert +local table_unpack = table.unpack +local assert = assert +local next = next +local ipairs = ipairs +local pairs = pairs +local tostring = tostring +local tonumber = tonumber +local mysqlproxy = mysqlproxy + +local function filterProperties(properties, filter) + for i, field in ipairs(filter) do + properties[field] = nil + end +end + +function ModelBaseMysql:ctor(properties) + self.cacheFields = {} --缓存字段 不更新数据库的字段 + + self[self.class.key .. "_"] = properties[self.class.key] --数据库key + properties[self.class.key] = nil + + if not self:isValidKey() then + print(string_format("%s [%s:key] should be give in new(ctor)", tostring(self), self.class.__cname)) + return + end + + if type(properties) ~= "table" then properties = {} end + self:loadProperties(properties) --缺少的域将设置默认值 + self:getPriKey() +end + +-- startCache 和 endCache 在恰当的时候*配对使用* 嵌套使用多次增加引用计数 直到引用计数为0 写入 +function ModelBaseMysql:startCache( ... ) + for _, field in ipairs({ ... }) do + if self.class.schema[field] then + self.cacheFields[field] = (self.cacheFields[field] or 0) + 1 + end + end +end + +--减少缓存引用计数 为时写入, 无参数 强制刷新所有缓存 +function ModelBaseMysql:endCache( ... ) + local args = { ... } + local params = {} + + local function doOneCache(field) + local propname = field .. "_" + table_insert(params, field) + if self.class.schema[field][1] == "table" then + table_insert(params, MsgPack.pack(self[propname])) + else + table_insert(params, self[propname]) + end + end + + if not next(args) then + for field, _ in pairs(self.cacheFields) do + doOneCache(field) + end + self.cacheFields = {} + else + for _, field in ipairs(args) do + if self.cacheFields[field] then + self.cacheFields[field] = self.cacheFields[field] - 1 + if self.cacheFields[field] <= 0 then + self.cacheFields[field] = nil + doOneCache(field) + end + end + end + end + + if next(params) then + redisproxy:hmset(self:getKey(), table_unpack(params)) + end +end +--[[-- + +返回对象的 ID 值。 + +**Returns:** + +- ID 值 + +]] +function ModelBaseMysql:getKey() + local id = self[self.class.key .. "_"] + assert(id ~= nil, string_format("%s [%s:getKey()] Invalid key", tostring(self), self.class.__cname)) + return id +end + +function ModelBaseMysql:getPriKey() + for k, v in pairs(self.class.schema) do + local objType, def, keyType, length = table_unpack(v) + if keyType == "pri" then + self.pri_key = k + end + end +end + +function ModelBaseMysql:load(properties) + if not self:isValidKey() then + print(string_format("%s [%s:id] should be set before load", tostring(self), self.class.__cname)) + return false + end + + if not properties then + print(string_format("SELECT * from %s where `%s` = %s;", self.class.__cname, self.pri_key, self:getKey())) + properties = mysqlproxy:query(string_format("SELECT * from %s where `%s` = %s;", self.class.__cname, self.pri_key, self:getKey())) + end + if not next(properties) then return false end + + self:loadProperties(properties[1]) + + self:onLoad() + + return true +end + +--创建model对应的redis数据, 必须已经设置了ID +function ModelBaseMysql:create() + if not self:isValidKey() then + print(string_format("%s [%s:key] should be set before create", tostring(self), self.class.__cname)) + return nil + end + + self:save() + self:onCreate() + + return self +end + +-- save 忽略 缓存配置 +function ModelBaseMysql:save() + local redisProperties = self:getProperties() + + local params = {} + for fieldName, value in pairs(redisProperties) do + local propname = fieldName .. "_" + if self.class.schema[fieldName][1] == "table" then + if not next(self[propname]) then + params[fieldName] = "NULL" + else + params[fieldName] = "'" .. MsgPack.pack(self[propname]) .. "'" + end + elseif self.class.schema[fieldName][1] == "string" then + params[fieldName] = "'" .. self[propname] .. "'" + else + params[fieldName] = self[propname] + end + end + if next(params) then + -- insert update + local sql = "INSERT INTO %s (%s) VALUES (%s) ON DUPLICATE KEY UPDATE %s;" + local tbName = self.class.__cname + local key_list = "" + local value_list = "" + local update_list = "" + for k, v in pairs(params) do + if key_list ~= "" then + key_list = key_list .. "," + end + if value_list ~= "" then + value_list = value_list .. "," + end + if update_list ~= "" then + update_list = update_list .. "," + end + + key_list = key_list .. k + value_list = value_list .. v + update_list = update_list .. k .. "=" .. v + end + sql = string_format(sql, tbName, key_list, value_list, update_list) + mysqlproxy:query(sql) + end +end + +--[[-- + +确定对象是否设置了有效的 key。 + +]] +function ModelBaseMysql:isValidKey() + local propname = self.class.key .. "_" + local key = self[propname] + return type(key) == "string" and key ~= "" +end + +--[[-- + +加载对象的属性进内存。 +NOTE: 如果properties缺少schema中的域, 将用默认值来填充 + +**Parameters:** + +- properties: 包含属性值的数组 + +]] +function ModelBaseMysql:loadProperties(properties) + assert(type(properties) == "table", "Invalid properties") + for field, schema in pairs(self.class.schema) do + local typ, def = table_unpack(schema) + local propname = field .. "_" + + if typ == "table" and type(properties[field]) == "string" then + properties[field] = MsgPack.unpack(properties[field]) + end + + local val = properties[field] or def + if val ~= nil then + if typ == "number" then val = tonumber(val) end + assert(type(val) == typ, + string_format("%s [%s:loadProperties()] Type mismatch, %s expected %s, actual is %s", + tostring(self), self.class.__cname, field, typ, type(val))) + self[propname] = val + end + end +end + +--[[-- + +取得对象的属性值。 + +**Parameters:** + +- fields: 要取得哪些属性的值,如果未指定该参数,则返回 fields 中设定的属性 +- filter: 要从结果中过滤掉哪些属性,如果未指定则不过滤 + +**Returns:** + +- 包含属性值的数组 + +]] +function ModelBaseMysql:getProperties(fields, filter) + local schema = self.class.schema + if type(fields) ~= "table" then fields = table.keys(self.class.schema) end + + local properties = {} + for i, field in ipairs(fields) do + local propname = field .. "_" + local typ = schema[field][1] + local val = self[propname] + assert(type(val) == typ, + string_format("%s [%s:getProperties()] Type mismatch, %s expected %s, actual is %s", + tostring(self), self.class.__cname, field, typ, type(val))) + properties[field] = val + end + + if type(filter) == "table" then + filterProperties(properties, filter) + end + + return properties +end + +function ModelBaseMysql:getProperty(property) + if type(property) ~= "string" then return nil end + if not self.class.schema[property] then return nil end + return self:getProperties({property})[property] +end + +function ModelBaseMysql:setProperty(property, value) + if not self.class.schema[property] then + print(string_format("%s [%s:setProperty()] Invalid property : %s", + tostring(self), self.class.__cname, property)) + return + end + + local typ, def = table_unpack(self.class.schema[property]) + local propname = property .. "_" + + if typ == "number" then value = tonumber(value) end + if typ == "table" and not value then + value = self[propname] -- table 可以用自己的缓冲 + end + assert(type(value) == typ, + string_format("%s [%s:setProperties()] Type mismatch, %s expected %s, actual is %s", + tostring(self), self.class.__cname, property, typ, type(value))) + self[propname] = value + + if not self.cacheFields[property] then + -- table 使用msgpack + if typ == "table" then + value = MsgPack.pack(value) + end + --redisproxy:hset(self:getKey(), property, value) + self:save() + end +end + +function ModelBaseMysql:setProperties(fields) + local result = {} + for property, value in pairs(fields) do + if not self.class.schema[property] then + print(string_format("%s [%s:setProperty()] Invalid property : %s", + tostring(self), self.class.__cname, property)) + else + local typ, def = table_unpack(self.class.schema[property]) + local propname = property .. "_" + if typ == "number" then value = tonumber(value) end + if typ == "table" and not value then + value = self[propname] -- table 可以用自己的缓冲 + end + assert(type(value) == typ, + string_format("%s [%s:setProperties()] Type mismatch, %s expected %s, actual is %s", + tostring(self), self.class.__cname, property, typ, type(value))) + self[propname] = value + + if not self.cacheFields[property] then + table_insert(result, property) + if typ == "table" then + table_insert(result, MsgPack.pack(self[propname])) + else + table_insert(result, self[propname]) + end + end + end + end + if next(result) then + --redisproxy:hmset(self:getKey(), table_unpack(result)) + self:save() + end +end + +function ModelBaseMysql:incrProperty(property, value) + if not self.class.schema[property] then + print(string_format("%s [%s:setProperty()] Invalid property : %s", + tostring(self), self.class.__cname, property)) + return + end + + local typ, def = table_unpack(self.class.schema[property]) + local propname = property .. "_" + + if typ == "table" then return end + if typ == "number" then value = tonumber(value) end + + assert(type(value) == typ, + string_format("%s [%s:setProperties()] Type mismatch, %s expected %s, actual is %s", + tostring(self), self.class.__cname, property, typ, type(value))) + self[propname] = self[propname] + value + + if not self.cacheFields[property] then + --return redisproxy:hincrby(self:getKey(), property, value) + self:save() + end +end + +function ModelBaseMysql:onLoad() +end + +function ModelBaseMysql:onCreate() +end + +function ModelBaseMysql:checkTableSchema() + -- 1.检测是否表存在 + local typeMap = { + number = {"int", 0, 10}, + string = {"varchar", "", 128}, + table = {"blob", "NULL"} + } + local tbName = self.class.__cname + local create_sql = [[ + CREATE TABLE IF NOT EXISTS `%s` ( + %s + PRIMARY KEY (`%s`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + ]] + local alter_sql = [[ + ALTER TABLE `%s` ADD COLUMN ( + %s + ) ; + ]] + local field_tpl_str = "`%s` %s%s DEFAULT %s" + local field_str = "" + + local res = mysqlproxy:query("desc ".. tbName .. ";") + if res["err"] then -- 表不存在 + local schema = {} + for k, v in pairs(self.class.schema) do + local keyType = v[3] + if keyType == "pri" then + self.pri_key = k + table_insert(schema, 1, {k, v}) + else + table_insert(schema, {k, v}) + end + end + for _, tbl in ipairs(schema) do + local k, v = tbl[1], tbl[2] + local objType, def, keyType, length = table_unpack(v) + assert(typeMap[objType], string_format("schema invalid type, %s, %s", tbName, k)) + + local info = typeMap[objType] + local suffix = "" + local fieldType = info[1] + if objType == "table" or not def or def == "" then def = info[2] end + if type(def) == "string" and def ~= "NULL" then def = "'" .. def .. "'" end + if info[3] and not length then length = info[3] end + -- 设置字段长度 + if info[3] then suffix = string.format("(%d)", length) end + -- 很长的string使用blob + if keyType == "blob" then + fieldType = keyType + suffix = "" + def = "NULL" + end + + field_str = field_str .. string.format(field_tpl_str..",", k, fieldType, suffix, def) + end + + assert(self.pri_key, string_format("table not include primary key, [%s]", tbName)) + -- 创建表格 + mysqlproxy:query(string_format(create_sql, tbName, field_str, self.pri_key)) + else -- 检测是否有添加新字段 + local addCol = {} + local curCols = {} + for _, col in ipairs(res) do + curCols[col["Field"]] = 1 + end + for k, v in pairs(self.class.schema) do + local objType, def, keyType, length = table_unpack(v) + if keyType == "pri" then + self.pri_key = k + end + if not curCols[k] then + print(string_format("table [%s] add new column [%s]", tbName, k)) + assert(typeMap[objType], string_format("schema invalid type, [%s], [%s]", tbName, k)) + + local info = typeMap[objType] + local suffix = "" + local fieldType = info[1] + if objType == "table" or not def or def == "" then def = info[2] end + if type(def) == "string" and def ~= "NULL" then def = "'" .. def .. "'" end + if info[3] and not length then length = info[3] end + -- 设置字段长度 + if info[3] then suffix = string.format("(%d)", length) end + -- 很长的string使用blob + if keyType == "blob" then + fieldType = keyType + suffix = "" + def = "NULL" + end + local sep = "," + if field_str == "" then + sep = "" + end + field_str = field_str .. string.format(sep..field_tpl_str, k, fieldType, suffix, def) + end + end + -- 添加新列 + if field_str ~= "" then + mysqlproxy:query(string_format(alter_sql, tbName, field_str)) + end + end + +end + +return ModelBaseMysql \ No newline at end of file diff --git a/src/shared/mysqlproxy.lua b/src/shared/mysqlproxy.lua new file mode 100644 index 0000000..3685436 --- /dev/null +++ b/src/shared/mysqlproxy.lua @@ -0,0 +1,34 @@ +local skynet = require "skynet" +require "utils.init" + +local mysqld_count = tonumber(skynet.getenv("thread")) +local mysqld +skynet.init(function() + local idx = math.randomInt(1, mysqld_count) + mysqld = skynet.localname(".mysql" .. idx) + +end) + +local table_insert = table.insert + +local mysqlproxy = {} + + +setmetatable(mysqlproxy, { __index = function(t, k) + local cmd = string.upper(k) + local f = function (self, ...) + if k == "query" then + --print(...) + end + local ok, result = pcall(skynet.call, mysqld, "lua", cmd, ...) + if not ok then + skynet.error(cmd, ..., "\n", debug.traceback(coroutine.running(), nil)) + return + end + return result + end + t[k] = f + return f +end}) + +return mysqlproxy \ No newline at end of file -- libgit2 0.21.2