91引擎爱好者论坛

 找回密码
 立即注册
热搜: 91引擎
查看: 2222|回复: 8

分享一个封装Promise异步操作的数据库工具类

[复制链接]
  • TA的每日心情
    奋斗
    2024-3-5 11:13
  • 签到天数: 93 天

    连续签到: 2 天

    [LV.6]常住居民II

    7

    主题

    111

    帖子

    1105

    积分

    金牌会员

    Rank: 6Rank: 6

    积分
    1105
    发表于 2022-6-29 10:58:48 | 显示全部楼层 |阅读模式
    本帖最后由 心淡如猫 于 2022-7-12 10:34 编辑

    工具类代码:
    [TypeScript] 纯文本查看 复制代码
    // 数据库管理
    
    import { logger } from "./Log"
    
    const BBMIR = 'bbmir'
    
    /**
     * 数据库操作类
     */
    class Db {
        /**
         * 初始化数据库连接
         */
        public initConnection = () => {
            if (GameLib.R.dbReady) {
                return
            }
            const host = 'localhost'
            const port = 3306
            const dbName = BBMIR
            const user = 'root'
            const pass = ''
            let ret = false
            let tryTimes = 10
            while (!ret && tryTimes > 0) {
                tryTimes--
                try {
                    ret = GameLib.DBEngine.AddConection(BBMIR, host, port, user, pass, dbName)
                } catch (err) {
                    logger.debug(err)
                    if (err.message.startsWith('已经存在相同的配置名称')) {
                        ret = true
                        break
                    }
                }
            }
            logger.info(ret ? '数据库连接成功' : ' 数据库连接失败')
            GameLib.R.dbReady = ret
        }
    
        /**
         * 检查数据连接
         */
        public checkDb = () => {
            if (!GameLib.R.dbReady) {
                this.initConnection()
            }
            if (!GameLib.R.dbReady) {
                logger.error('数据库异常')
                throw Error('数据库异常, 无法连接')
            }
        }
    
        /**
         * 校验SQL,格式化
         * @param sql 
         * @param params 
         */
        public validate = (sql: string, params: any[]) => {
            for (const param of params) {
                if (/update|delete|exist|alter|create|drop/.test(String(param).toLowerCase())) {
                    logger.error('SQL中有非法参数')
                    throw Error('SQL中有非法参数')
                }
                if (typeof param == 'number') {
                    sql = sql.replace('?', String(param))
                } else if (typeof param == 'string') {
                    sql = sql.replace('?', `'${param}'`)
                } else if (Array.isArray(param)) {
                    sql = this.parseArrayParams(sql, param)
                } else {
                    sql = sql.replace('?', `'${param}'`)
                }
            }
            logger.debug('sql', sql)
            return sql
        }
    
        /**
         * 解析数组类型参数
         * @param sql 
         * @param param 
         * @returns 
         */
        public parseArrayParams = (sql: string, param: any[]) => {
            if (param.length == 0) {
                // 空数组
                sql = sql.replace('?', '')
            } else {
                // 数字数组
                if (typeof param[0] == 'number') {
                    sql = sql.replace('?', param.join(','))
                } else {
                    // 字符串数组
                    sql = sql.replace('?', param.map(x => `'${x}'`).join(','))
                }
            }
            return sql
        }
    
        /**
         * 执行SQL查询
         * @param sql
         * @param params
         */
        public query = <T> (sql: string, ...params: any) => {
            return new Promise((resolve: (rows: T[]) => void, reject: (err?: any) => void) => {
                this.checkDb()
                GameLib.DBEngine.QueryAsyncEx(BBMIR, this.validate(sql, params), (err, result) => {
                    if (err) {
                        reject(err)
                        return
                    }
                    const rows = []
                    while (!result.Eof()) {
                        this.parseRow(result, rows)
                        result.Next()
                    }
                    resolve(rows)
                })
            })
        }
    
        /**
         * 查询SQL返回第一行第一列值
         * @param sql 
         * @param params 
         */
        public queryScalar = <T> (sql: string, ...params: any) => {
            return new Promise((resolve: (value: T) => void, reject: (err?: any) => void) => {
                this.checkDb()
                GameLib.DBEngine.QueryAsyncEx(BBMIR, this.validate(sql, params), (err, result) => {
                    if (err) {
                        reject(err)
                        return
                    }
                    const rows = []
                    this.parseRow(result, rows)
                    let value: any
                    if (rows.length > 0) {
                        const row = rows[0]
                        const name = Object.getOwnPropertyNames(row)[0]
                        value = row[name]
                    }
                    resolve(value)
                })
            })
        }
    
        /**
         * 查询SQL返回第一行
         * @param sql 
         * @param params 
         */
         public queryOne = <T> (sql: string, ...params: any) => {
            return new Promise((resolve: (value: T) => void, reject: (err?: any) => void) => {
                this.checkDb()
                GameLib.DBEngine.QueryAsyncEx(BBMIR, this.validate(sql, params), (err, result) => {
                    if (err) {
                        reject(err)
                        return
                    }
                    const rows = []
                    this.parseRow(result, rows)
                    if (rows.length > 0) {
                        const row = rows[0]
                        resolve(row)
                    } else {
                        resolve(null)
                    }
                })
            })
        }
    
        /**
         * 解析行
         * @param ds 
         * @param rows 
         * @returns 
         */
        public parseRow = (ds: TDataSet, rows: any[]) => {
            if (ds.IsEmpty()) {
                return
            }
            const row = {}
            for (let i = 0; i < ds.GetFieldCount(); i++) {
                const field = ds.GetField(i)
                row[field.GetFieldName()] = this.parseFieldValue(field)
            }
            rows.push(row)
        }
    
        /**
         * 解析列
         * @param field
         * @returns 
         */
        public parseFieldValue = (field: TField) => {
            if (field.IsInt()) {
                return parseInt(field.AsString)
            }
            if (field.IsFloat()) {
                return field.AsFloat
            }
            if (field.IsDateTime()) {
                return field.AsDateTime
            }
            return field.AsString
        }
    
        /**
         * 执行SQL更新、删除
         * @param sql 
         * @param cb 
         */
        public execute = (sql: string, ...params: any) => {
            return new Promise((resolve: (result: boolean) => void, reject: (err?: any) => void) => {
                this.checkDb()
                GameLib.DBEngine.ExecAsyncEx(BBMIR, this.validate(sql, params), (err, affectRow) => {
                    if (err) {
                        reject(err)
                        return
                    }
                    resolve(affectRow > 0)
                })
            })
        }
    
        /**
         * 获取事务id
         * @param Player 
         * @param key 
         */
        public getTranID = (Player: TPlayObject, key: string) => {
            return `${Player.PlayerID}-${key}-${randomRange(0, 1000)}`
        }
    
    }
    
    export default new Db()


    使用样例:
    查询列表
    [TypeScript] 纯文本查看 复制代码
    // 获取所有委托单
    export const getAllCommissionOrders = async (moneyType: MoneyType, limit: number = 7) => {
        let ORDER = 'DESC'
        if (moneyType == MoneyType.YB) {
            ORDER = 'ASC'
        }
        return await Db.query<CommissionOrder>(`
            SELECT * 
            FROM CommissionOrder
            WHERE ServerID=? AND SellMoneyType=?
            ORDER BY Price ${ORDER} LIMIT ${limit}`,
            GameLib.ServerID, moneyType
        )
    }

    查询一行
    [TypeScript] 纯文本查看 复制代码
    // 获取当前委托单
    export const getCommissionOrder = async (Player: TPlayObject) => {
        return await Db.queryOne<CommissionOrder>(
            `SELECT * FROM CommissionOrder WHERE ServerID=? AND PlayerID=?`,
            GameLib.ServerID, Player.PlayerID
        )
    }

    更新数据
    [TypeScript] 纯文本查看 复制代码
    // 保存资产
    export const saveAsset = async (Asset: AssetHosting) => {
        const asset = await getAsset(Asset.PlayerID, Asset.MoneyType)
        // 更新
        if (asset) {
            await Db.execute(`
                UPDATE AssetHosting SET Balance=? WHERE PlayerID=? AND ServerID=? AND MoneyType=?`,
                Asset.Balance, Asset.PlayerID, Asset.ServerID, Asset.MoneyType
            )
        } else {
            // 插入
            await Db.execute(`
                INSERT INTO AssetHosting VALUES (?, ?, ?, ?)`,
                Asset.PlayerID, Asset.ServerID, Asset.MoneyType, Asset.Balance
            )
        }
    }


    删除数据
    [TypeScript] 纯文本查看 复制代码
    // 数量为0则删除
                await Db.execute(`DELETE FROM CommissionOrder WHERE OrderID=?`, order.OrderID)

    评分

    参与人数 2金币 +200 收起 理由
    星夜大哥 + 100 猫神我来学习了
    无名 + 100 很给力!

    查看全部评分

    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    2024-3-5 11:13
  • 签到天数: 93 天

    连续签到: 2 天

    [LV.6]常住居民II

    7

    主题

    111

    帖子

    1105

    积分

    金牌会员

    Rank: 6Rank: 6

    积分
    1105
     楼主| 发表于 2022-6-29 11:01:05 | 显示全部楼层
    本帖最后由 心淡如猫 于 2022-7-2 22:18 编辑

    1111111
    回复

    使用道具 举报

  • TA的每日心情
    无聊
    4 天前
  • 签到天数: 469 天

    连续签到: 7 天

    [LV.9]以坛为家II

    1

    主题

    502

    帖子

    4055

    积分

    论坛元老

    Rank: 8Rank: 8

    积分
    4055
    发表于 2022-6-29 13:18:34 | 显示全部楼层
    学习了   大佬厉害··!
    回复

    使用道具 举报

  • TA的每日心情
    郁闷
    2022-10-20 09:37
  • 签到天数: 23 天

    连续签到: 1 天

    [LV.4]偶尔看看III

    12

    主题

    75

    帖子

    1990

    积分

    超级版主

    Rank: 8Rank: 8

    积分
    1990
    发表于 2022-7-12 10:24:41 | 显示全部楼层
    很给力,感谢分享
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    昨天 18:52
  • 签到天数: 404 天

    连续签到: 1 天

    [LV.9]以坛为家II

    7

    主题

    422

    帖子

    2354

    积分

    金牌会员

    Rank: 6Rank: 6

    积分
    2354
    发表于 2022-8-6 11:33:20 | 显示全部楼层
    大佬牛逼!
    回复

    使用道具 举报

  • TA的每日心情
    开心
    昨天 19:13
  • 签到天数: 243 天

    连续签到: 5 天

    [LV.8]以坛为家I

    14

    主题

    256

    帖子

    2524

    积分

    实习版主

    Rank: 7Rank: 7Rank: 7

    积分
    2524
    发表于 2022-9-19 18:43:03 | 显示全部楼层
    import { logger } from "./Log"
    报错呀大佬
    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    2024-3-5 11:13
  • 签到天数: 93 天

    连续签到: 2 天

    [LV.6]常住居民II

    7

    主题

    111

    帖子

    1105

    积分

    金牌会员

    Rank: 6Rank: 6

    积分
    1105
     楼主| 发表于 2022-9-28 18:25:29 | 显示全部楼层
    oyql0102 发表于 2022-9-19 18:43
    import { logger } from "./Log"
    报错呀大佬

    logger相关的都可以删掉哈
    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    昨天 00:56
  • 签到天数: 451 天

    连续签到: 7 天

    [LV.9]以坛为家II

    50

    主题

    461

    帖子

    5454

    积分

    实习版主

    Rank: 7Rank: 7Rank: 7

    积分
    5454
    发表于 2023-6-1 14:56:54 | 显示全部楼层
    牛皮牛皮
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    3 天前
  • 签到天数: 46 天

    连续签到: 1 天

    [LV.5]常住居民I

    2

    主题

    59

    帖子

    795

    积分

    高级会员

    Rank: 4

    积分
    795
    发表于 2023-11-30 14:56:28 | 显示全部楼层
    666,牛逼
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    Archiver|手机版|小黑屋|妖孽游戏素材网|91引擎爱好者

    GMT+8, 2024-3-29 02:44 , Processed in 0.111594 second(s), 36 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.

    快速回复 返回顶部 返回列表