游戏开发 数据库ID设计 ID生成器
对于滚服游戏开发,数据库的ID设计非常重要,关乎到合服操作的复杂性。数据库ID设计得好,合服就相当简单。合服主要是数据的合并。把两个或多个单独的服务器数据合并到一个服里面。
数据库表设计是游戏开发中必不可少的,通常每一张表,我们都会设计一个ID主键字段,关于表ID的生成方式。这里我们选择根据区服ID及玩家数量自增,其他同学喜欢用UUID那就另说。
ID结构: 自增序列+四位区服号。
这里我们以区服ID作为基数,个位到千位是区服号,万位以上是玩家ID自增ID开始。如1区服即0001, 2区服是0002.
以玩家基础数据表的ID设计为例,如果以区服1为示例,那么ID结构是这样的:玩家自增序列+0001。即1区服的第1号玩家ID是:10001;1区服的第19876号玩家ID是:198760001。2区服的第1号玩家ID是:10002;2区服的第19876号玩家ID是:198760002。
这里说明一下,ID区服段为什么是个位到千位,而不是到万位呢?通常滚服开服区服数量不会太多,除非非常爆款的游戏。一般开到上千服已经很不错了。所以这里设计区服区间为1-9999个服。即ID基数是:0001-9999。
下面是实现这种结构ID设计的实例
以JAVA代码示例。
1. ID生成管理类 IdManager.java
初始化ID和生成新ID的实现。
@Service
public class IdManager {
private static final Logger logger = LogManager.getLogger(IdManager.class);
@Resource
private GameDBConfiguration gameServerConfiguration;
private final Map<String, Long> ids = new ConcurrentHashMap<>();
public void init() {
logger.info("id生成器开始。");
try {
Field[] declaredFields = TableNameConstant.class.getDeclaredFields();
for (Field f : declaredFields) {
String tableName = f.get(TableNameConstant.class).toString();
long maxId = gameServerConfiguration.getMaxId(tableName);
if (maxId == 0) {
if (tableName.equals(TableNameConstant.T_PLAYER)) {
ids.put(tableName, IdMaxConstant.ROLE);
} else {
ids.put(tableName, IdMaxConstant.COMMON);
}
} else {
ids.put(tableName, maxId);
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
logger.info("id生成器结束。");
}
/**
* 创建并获取新的id
*/
public Long createNewId(String tableName) {
synchronized (tableName) {
Long maxId = ids.get(tableName);
if (maxId == null) {
logger.error("id生成规则出错,tableName={}", tableName);
return null;
}
long newId = 0;
int serverId = ServerHelper.getServerId();//获取当前区服ID。
newId = (maxId / IdMaxConstant.SERVER_BASE_VALUE + 1) * IdMaxConstant.SERVER_BASE_VALUE + serverId;
/*if(tableName.equalsIgnoreCase(TableNameConstant.T_PLAYER)){
newId = (maxId / IdMaxConstant.SERVER_BASE_VALUE + 1) * IdMaxConstant.SERVER_BASE_VALUE + serverId;
}else{
newId = maxId + 1;
}*/
ids.put(tableName, newId);
return newId;
}
}
}
2. 获取数据库表最大ID方法 getMaxId()
从数据库中查询当前表格最大的ID序号。
public long getMaxId(String tableName) {
String sql = "select max(id) from " + tableName;
Long maxId = jdbcTemplate.queryForObject(sql, Long.class);
return maxId == null ? 0 : maxId;
}
3. 表格常量类 TableNameConstant.java
存放需要管理ID的表格名称。
public class TableNameConstant {
public static final String T_PLAYER = "t_player";
public static final String T_PLAYER_GOODS = "t_player_goods";
//...
}
4. 常量类 IdMaxConstant.java
public class IdMaxConstant {
/**
* role表id起始值
*/
public static final long ROLE = 0L;
/**
* 通用表id起始值
*/
public static final long COMMON = 0L;
}
5. 使用示例
long playerId = idManager.createNewId(TableNameConstant.T_PLAYER);
Player player = new Player();
player.setPlayerId(playerId);
player.setUsername(username);
player.setGameSite(gameSite);
player.setNickname(nickname.trim());
player.setCreateTime(new Date());
//...
至此,一波操作完成。
实际应用中根据具体项目可以修改 IdMaxConstant.java 起始值来改变ID的结构。
欢迎您点赞 评论,您的支持是我最大的动力~
↓ 动动您的贵手 点赞 收藏 (方便您下次查阅) 谢谢~(❁´◡`❁)✲゚