zoukankan      html  css  js  c++  java
  • 最近使用LuaSqlite3时,不得不说的——事务提交ATTACH语句的巨坑

    在做不同来源的db数据合并新db时,遇见的 

    lua 事务无法处理附加数据库操作

    --[[
    AnsiToUTF8(InputString):将传入的字符串转为UTF8字符串,并将其返回
    PRINT(InputString):将传入的字符串在日志输出中打印
    FileDelete(FilePath):删除FilePath,返回Boolean
    FileCopy(FilePathA,FilePathB):将文件A复制到文件B,返回Boolean
    FileExists(FilePath):判断FilePath是否存在,返回Boolean
    --]]
    --package.path=";?.lua;"
    --PRINT(package.path)
    --package.cpath=package.cpath..";?.dll"
    --PRINT(package.cpath)
    function newStack ()
        return {""}   -- starts with an empty string
    end
    
    function addString (stack, s)
        table.insert(stack, s)   -- push 's' into the the stack
        for i=table.getn(stack)-1, 1, -1 do
           if string.len(stack[i]) > string.len(stack[i+1]) then
               break
           end
           stack[i] = stack[i] .. table.remove(stack)
        end
    end
    
    function rows(cur,mode)
        return function(cur)
            local t = {}
            if(nil ~= cur:fetch(t, mode or 'a')) then
                return t
            else
                return nil
            end
        end,cur
    end
    
    function print(...)
        local t = {}
        for i=1,select('#',...) do
            table.insert(t,tostring(select(i,...)))
        end
        PRINT(table.concat(t," "))
    end
    
    function OnStart(SavePath,MasterPath,SlavePath)
        print("OnStart 1 : "..os.clock())
        --os.execute("lua.exe")
        require("luasql.sqlite3")
        g_env = assert(luasql.sqlite3())
        local lfs = require("lfs")
        print(luasql)
        print(lfs.mkdir)
        --newfile=io.open("log.txt","w+")
        
        g_SavePath=SavePath..'Mir200\Envir\LuaEnvir\sqliteDB\'
        g_MasterPath=MasterPath..'Mir200\Envir\LuaEnvir\sqliteDB\'
        g_SlavePath=SlavePath..'Mir200\Envir\LuaEnvir\sqliteDB\'
        print("lua合区路径: "..g_SavePath)
        print("
    ")
        print("lua主区路径: "..g_MasterPath)
        print("
    ")
        print("lua从区路径: "..g_SlavePath)
        print("
    ")
        
        --os.execute('mkdir '..g_SavePath) -- 创建合区luaDB目录
        lfs.mkdir(SavePath.."Mir200\")
        lfs.mkdir(SavePath.."Mir200\Envir\")
        lfs.mkdir(SavePath.."Mir200\Envir\LuaEnvir\")
        lfs.mkdir(g_SavePath)
    
        print('删除旧的合区db!')
        local res,err = os.remove(g_SavePath..'LUADB.db')
        print(res,err)
    
        g_MasterRoleTab={} -- 主库角色名记录
        g_MasterItemTab={} -- 主库物品makeIndex记录
    
        g_SlaveRoleTab={}  -- 从库角色名记录
        g_SlaveItemTab={}  -- 从库物品makeIndex记录
    
        g_masterTabNameTab = {} -- 主库luaDB所有的表名
        g_slaveTabNameTab = {}  -- 从库luaDB所有的表名
    
        g_masterOldIdTab ={}  -- 主库luaDB所有的表ID记录
        g_slaveOldIdTab = {}  -- 从库luaDB所有的表ID记录
        
        g_MasterConn =assert(g_env:connect(AnsiToUTF8(g_MasterPath..'LUADB.db'))) 
        g_SlaveConn = assert(g_env:connect(AnsiToUTF8(g_SlavePath..'LUADB.db')))
        g_SaveConn = assert(g_env:connect(AnsiToUTF8(g_SavePath..'LUADB.db')))
        
        g_SaveConn:execute("PRAGMA synchronous = OFF;") 
    
        local masterSysRes  = g_MasterConn:execute("SELECT name FROM sqlite_master where type ='table' order by name;")
        local slaveSysRes  = g_SlaveConn:execute("SELECT name FROM sqlite_master where type ='table' order by name;")
        
        for r in rows(masterSysRes) do
            if r == nil then
                break
            end
            local tabName= r["name"]
            print("主库表名:"..tabName)
            table.insert(g_masterTabNameTab,tabName)
        end
        print('----------------------')
        for r in rows(slaveSysRes) do
            if r == nil then
                break
            end
            local tabName= r["name"]
            print("从库表名:"..tabName)
            table.insert(g_slaveTabNameTab,tabName)
        end
        print('----------------------')
        masterSysRes:close()
        slaveSysRes:close()
    
        for i=1,#g_masterTabNameTab do  
            --local tabName = string.lower(g_masterTabNameTab[i])
            local tabName = g_masterTabNameTab[i]
            local sqlstr = string.format( "SELECT * FROM %s;", tabName)
            g_masterOldIdTab[tabName] = {}
            
            local res = assert(g_MasterConn:execute(sqlstr))
            local coltypes = res:getcoltypes()
            for r in rows(res,'n') do
                for i=2,#coltypes do
                    local coltype = string.lower(coltypes[i])
                    if string.find(coltype,'char') or string.find(coltype,'text')  then
                        r[i] = string.format("%q",r[i])
                    end
                end
    
                g_masterOldIdTab[tabName][r[1]] = table.concat(r,',',2)
            end
            
            res:close()
        end
    
        for i=1,#g_slaveTabNameTab do  
            --local tabName = string.lower(g_slaveTabNameTab[i])
            local tabName = g_slaveTabNameTab[i]
            local sqlstr = string.format( "SELECT * FROM %s;", tabName)
            g_slaveOldIdTab[tabName] = {}
            
            local res = assert(g_SlaveConn:execute(sqlstr))
            local coltypes = res:getcoltypes()
            for r in rows(res,'n') do
                
                for i=2,#coltypes do
                    local coltype = string.lower(coltypes[i])
                    if string.find(coltype,'char') or string.find(coltype,'text')  then
                        r[i] = string.format("%q",r[i])
                    end
                end
    
                g_slaveOldIdTab[tabName][r[1]] = table.concat(r,',',2)
            end
            
            res:close()
        end
    
        print("OnStart 2 : "..os.clock())
    
    end
    
    function OnAccountChanged(OldAccount,NewAccount)
        
    end
    
    -- sFlag说明:HumDataDB_M,HeroDataDB_M,UserShopItemDB_M,HumDataDB_S,HeroDataDB_S,UserShopItemDB_S
    function OnMakeIndexChanging(RoleName,OldMakeIndex,NewMakeIndex,sFlag)
        --if OldMakeIndex ~= NewMakeIndex then
            if string.find(sFlag,"_S$") then
                --newfile:write("从区物品makeindex改变:"..RoleName..":"..OldMakeIndex.." ====>  "..NewMakeIndex.."   "..sFlag)
                --newfile:write("
    ")
                --table.insert( g_SlaveItemTab,{OldMakeIndex,NewMakeIndex})
                g_SlaveItemTab[tostring(OldMakeIndex)] = tostring(NewMakeIndex)
            else
                --newfile:write("主区物品makeindex改变:"..RoleName..":"..OldMakeIndex.." ====>  "..NewMakeIndex.."   "..sFlag)
                --newfile:write("
    ")
                --table.insert( g_MasterItemTab,{OldMakeIndex,NewMakeIndex})
                g_MasterItemTab[tostring(OldMakeIndex)] = tostring(NewMakeIndex)
            end
        --end
    end
    
    -- 
    function OnRoleNameChanged(Account,OldRoleName,NewRoleName)
    --    if OldRoleName ~= NewRoleName then
            print(string.format("账号:%s  旧角色名:%s   新角色名:%s",Account,OldRoleName,NewRoleName))
            --newfile:write("从区玩家名改变: "..Account..":"..OldRoleName.." ====>"..NewRoleName)
            --newfile:write("
    ")
            --table.insert( g_SlaveRoleTab,{OldRoleName,NewRoleName})
            g_SlaveRoleTab[OldRoleName]=NewRoleName
    --    end
    end
    
    function OnGetMRoleName( RoleName )
        --print( "主区存在玩家名:" .. name )
        --table.insert( g_MasterRoleTab,RoleName )
        g_MasterRoleTab[RoleName] = true
    end
    
    function OnStop()
        print("OnStop 1 : "..os.clock())
        local sqlTab = {}
        local sqlTab1= {}
        local sqlstr = string.format("ATTACH '%s' AS 'A';",AnsiToUTF8(g_MasterPath.."LUADB.db"))
        table.insert(sqlTab1,sqlstr)
    
        for i=1,#g_masterTabNameTab do 
            -- 复制主表结构
            local tabName = string.lower(g_masterTabNameTab[i])
            sqlstr = string.format( "CREATE TABLE IF NOT EXISTS %s AS SELECT * FROM A.%s WHERE 1=0;",tabName,tabName) 
            table.insert(sqlTab1,sqlstr)
            if string.find(tabName,"^all") then
                tabName = g_masterTabNameTab[i]
                for id,item in pairs(g_masterOldIdTab[tabName]) do
                    local invalid = true
                    local newID =  g_MasterItemTab[id]
                    if newID then
                        invalid = false
                    end
                    if not invalid then
                        sqlstr = string.format("INSERT INTO %s  VALUES(%s,%s);",tabName,newID,item)
                        table.insert( sqlTab,sqlstr )
                    end
                end
            elseif string.find(tabName,"^role") then --清除已删除角色数据
                tabName = g_masterTabNameTab[i]
                for id,item in pairs(g_masterOldIdTab[tabName]) do
                    local invalid = true
                    if g_MasterRoleTab[id] then
                        invalid = false
                    else
                        local taskID,name = string.match(id,"(%S+)&(%S+)$")
                        if name and g_MasterRoleTab[name] then
                            invalid = false
                        end
                    end
    
                    if not invalid then
                        sqlstr = string.format("INSERT INTO %s VALUES(%q,%s);",tabName,id,item)
                        table.insert( sqlTab,sqlstr )
                    end
                end
            end
        end
        print("OnStop 2 : "..os.clock())
        -- 复制从表结构
        sqlstr = string.format("ATTACH '%s' AS 'B';",AnsiToUTF8(g_SlavePath.."LUADB.db"))
        table.insert(sqlTab1,sqlstr)
        for i=1,#g_slaveTabNameTab do  
            local tabName = string.lower(g_slaveTabNameTab[i])
            sqlstr = string.format( "CREATE TABLE IF NOT EXISTS %s AS SELECT * FROM B.%s WHERE 1=0;",tabName,tabName) 
            table.insert(sqlTab1,sqlstr)
            if string.find(tabName,"^all") then --清除不存在物品数据
                tabName = g_slaveTabNameTab[i]
                for id,item in pairs(g_slaveOldIdTab[tabName]) do
                    local invalid = true
                    local newID =  g_SlaveItemTab[id]
                    if newID then
                        invalid = false
                    end
                    if not invalid then
                        sqlstr = string.format("INSERT INTO %s  VALUES(%s,%s);",tabName,newID,item)
                        table.insert( sqlTab,sqlstr )
                    end
                end
            elseif string.find(tabName,"^role") then --    清除已删除角色数据
                tabName = g_slaveTabNameTab[i]
                for id,item in pairs(g_slaveOldIdTab[tabName]) do
                    local invalid = true
                    local newName= g_SlaveRoleTab[id]
                    local newID = ''
                    if g_SlaveRoleTab[id] then
                        invalid = false
                        newID = newName
                    else
                        local taskID,name = string.match(id,"(%S+)&(%S+)$")
                        if name and g_SlaveRoleTab[name] then
                            invalid = false
                            newID = taskID..'&'..newName
                        end
                    end
    
                    if not invalid then
                        sqlstr = string.format("INSERT INTO %s VALUES(%q,%s);",tabName,newID,item)
                        table.insert( sqlTab,sqlstr )
                    end
                end
            end
        end
        print("OnStop 3 : "..os.clock())
        print(type(g_SlaveConn))
        print(type(g_MasterConn))
        print(type(g_SaveConn))
    
        local res,err
    
        for i=1,#sqlTab1 do
            local str = sqlTab1[i]
            --print(str)
            res,err = assert(g_SaveConn:execute(str))
            --print(res,err)
        end
        
        g_SaveConn:setautocommit(false)
        for i=1,#sqlTab do
            local str = sqlTab[i]
            --print(str)
            res,err = assert(g_SaveConn:execute(str))
            --print(res,err)
        end
        assert(g_SaveConn:commit())
    
        print("OnStop 3 : "..os.clock())
        print("OnStop 4 : "..os.clock())
        print("执行sql语句条数:" .. #sqlTab)
        
        print('关闭从库链接!')
        g_SlaveConn:close()
        print('关闭主库链接!')
        g_MasterConn:close()
        print('关闭合区库链接!')
        g_SaveConn:close()
        print('关闭数据库操作环境!')
        g_env:close()
        
        print("合区成功!!!!")
        print("OnStop 5 : "..os.clock())
    end
  • 相关阅读:
    python 全栈开发,Day127(app端内容播放,web端的玩具,app通过websocket远程遥控玩具播放内容,玩具管理页面)
    队列Queue FIFO先进先出 栈Stack FILO先进后出
    sql server 2008 学习笔记
    c#剪切板
    c#复制图片到粘贴板
    C# GUID的使用
    winform自定义控件
    进程和线程
    vs常用快捷键
    c# foreach循环二维数组
  • 原文地址:https://www.cnblogs.com/welcome-to-fang-qi-blog/p/13724150.html
Copyright © 2011-2022 走看看