Skip to content

cdk方式数据库设计和游戏脚本

数据库设计

sql
数据库表设计

gem_cdk 表
字段			类型		不是null	备注
cdk 			varchar 	√			主键, 非自增
state 			tinyint 	√			有效状态, 1=有效 0=无效
item_id			int			√			gem_item 表的 id
time			varchar					使用 CDK 的时间, 格式 yyyyMMddHHmmss, 这里为什么用 varchar, 因为要方便运维的人, 更直观
character_id	int						使用 CDK 的角色 id


gem_item 表 ( cdk 对应的奖励表 )
字段			类型		不是null	备注
id				int			√			主键, 自增
type			smallint	√			兑换的奖励/道具类型, 1=道具 2=金币 3=点券 4=抵用券... 按需增加
quantity		int			√			数量, 金币, 点券, 抵用券等等都有数量
attach			varchar					预留给道具或其他, 可以设置道具id, 不是道具一般留空
name			varchar					只是为了能记住该奖励的名字

注: 所有 smallint, tinyint 都可以改为 int

----------------------------------------------

数据库表创建语句
注意啊! 注意啊! 注意啊! 表引擎一律用 InnoDB !!! 我干 JAVA 这么多年了, 这圈子能干出来的事最离谱了!
不知道新建表要注意什么, 直接点击 "查询", 下面这是两条 SQL, 直接执行就行

CREATE TABLE `gem_cdk` (
  `cdk` varchar(255) NOT NULL,
  `state` tinyint(4) NOT NULL,
  `item_id` int(255) NOT NULL,
  `time` varchar(255) DEFAULT NULL,
  `character_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`cdk`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `gem_item` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `type` smallint(6) NOT NULL,
  `quantity` int(11) NOT NULL,
  `attach` varchar(255) DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

----------------------------------------------

批量插入 CDK 的 SQL 模板: 		INSERT INTO gem_cdk(cdk, state, item_id) VALUES('{cdk}', 1, {item_id});
批量删除某一个 item 的所有 CDK:	DELETE FROM gem_cdk WHERE item_id = {item_id}
查询某一个 item 的所有 CDK:		SELECT * FROM gem_cdk WHERE item_id = {item_id}

游戏脚本

js
/**
 * Author: 楠哥
 * Contact: 2639068583
 * Description: 事务控制, 数据安全, 无超售. 奖励类型支持丰富
 * Tip: 使用之前将 conn = cm.getConnection() 改适用于自己服的获取数据库连接的方法
 */
 
function start() {
    status = -1;
    action(1, 0, 0);
}

function action(mode, type, selection) {
	if (mode == -1) {
        cm.dispose();
    } else {
        if (status >= 0 && mode == 0) {
            cm.dispose();
            return;
        }
        if (mode == 1)
            status++;
        else
            status--;
        if (status == 0) {
			cm.sendGetText('欢迎光临 宝石商店 \n请输入CDK')
		} else if (status == 1) {
			var cdk = cm.getText()
			try {
				useCDK(cdk, function(type, quantity, attach) {
					if (type == 1) {
                        // 注意检查背包剩余可用格数, 拿到 id 可以用 xml 获得装备名字, 也可以提前写到数据库里
						cm.sendOk('获得 #v' + attach + '##z' + attach + '# x ' + quantity)
                        cm.gainItem(parseInt(attach), quantity)
                    } else if (type == 2) {
                        // 给金币
						cm.sendOk('获得 ' + quantity + ' 金币')
                        cm.gainMeso(quantity)
                    } else if (type == 3) {
                        // 给点券
						cm.sendOk('获得 ' + quantity + ' 点券')
                        cm.gainNX(quantity)
                    } else if (type == 4) {
                        // 给抵用券
						cm.sendOk('获得 ' + quantity + ' 抵用券')
                        cm.gainDY(quantity)
                    } else {
                        throw 102
                    }
				}, cm.getPlayer().getId())
			} catch (e) {
				if (e === 101) {
					cm.sendOk('卡密已被使用或不存在')
				} else {
					cm.sendOk('系统错误')
				}
			}
			cm.dispose();
		}
	}
}

/*
 * 兑换奖励
 * 异常会抛出错误码, 101: cdk 无效或已被使用
 */
function useCDK(cdk, callback, characterId) {
	var conn
	var ps
	var rs
	try {
		// conn 是数据库连接的意思, 每个端拿到数据库连接的方式都不太一样
		conn = cm.getConnection()				
		conn.setAutoCommit(false)
		
		// 先查是否有效并获取 item_id
		ps = conn.prepareStatement('SELECT item_id FROM gem_cdk WHERE state = 1 AND cdk = ?')
		ps.setString(1, cdk)
		rs = ps.executeQuery()
		if (!rs.next()) {
			// cdk 不存在或无效
			throw 101
		}
		var itemId = rs.getInt('item_id')
		rs.close()
		ps.close()
		
		// 更新 CDK
		ps = conn.prepareStatement('UPDATE gem_cdk SET state = 0, character_id = ?, time = ? WHERE cdk = ?')
		ps.setInt(1, characterId)
		ps.setString(2, getFormattedDateTime())
		ps.setString(3, cdk)
		if (ps.executeUpdate() == 0) {
			throw 1
		}
		ps.close()
		
		ps = conn.prepareStatement('SELECT type, quantity, `attach` FROM gem_item WHERE id = ?')
		ps.setInt(1, itemId)
		rs = ps.executeQuery()
		rs.next()
		// 发奖励啦
		callback(rs.getInt('type'), rs.getInt('quantity'), rs.getString('attach'))
		rs.close()
		ps.close()
		conn.setAutoCommit(true)
	} catch (e) {
		// 回滚
		try {
            if(conn != null && !conn.isClosed()) {
                conn.rollback()
            }
        } catch (e) {
            print(e)
        }
		// print(e)
		throw e
	} finally {
		try {
			if (rs != null) {
				rs.close()
			}
		} catch (e) {
			print(e)
			// e.printStackTrace()
		}
		try {
			if (ps != null) {
				ps.close()
			}
		} catch (e) {
			print(e)
			// e.printStackTrace()
		}
		try {
			if (conn != null && !conn.isClosed()) {
				conn.setAutoCommit(true)
				conn.close()
			}
		} catch (e) {
			print(e)
			// e.printStackTrace()
		}
	}
}

// 获取格式化的时间
function getFormattedDateTime() {
	var now = new Date()
	var year = now.getFullYear()
	var month = now.getMonth() + 1
	var day = now.getDate()
	var hours = now.getHours()
	var minutes = now.getMinutes()
	var seconds = now.getSeconds()
	return '' + year + (month > 9 ? month : '0' + month) 
		+ (day > 9 ? day : '0' + day) 
		+ (hours > 9 ? hours : '0' + hours) 
		+ (minutes > 9 ? minutes : '0' + minutes)
		+ (seconds > 9 ? seconds : '0' + seconds)
}