精华内容
下载资源
问答
  • 游戏开发 数据库ID设计 ID生成器 对于滚服游戏开发,数据库的ID设计非常重要,关乎到合服操作的复杂性。数据库ID设计得好,合服就相当简单。合服主要是数据的合并。把两个或多个单独的服务器数据合并到一个服里面。 ...

    游戏开发 数据库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的结构。

    欢迎您点赞 评论,您的支持是我最大的动力~

    ↓ 动动您的贵手 点赞 收藏 (方便您下次查阅) 谢谢~(❁´◡`❁)✲゚

    展开全文
  • 优雅的数据库ID设计

    2020-04-29 17:37:25
    数据库表设计是项目开发中逃不掉的问题,每一张表,我们都会设计一个ID主键字段,关于表ID的生成方式,每个人都有自己的见解,我们就来讨论如何优雅的设计数据库ID 自增ID 这种方式用起来最简单,也是很多程序员...

    数据库表设计是项目开发中逃不掉的问题,每一张表,我们都会设计一个ID主键字段,关于表ID的生成方式,每个人都有自己的见解,我们就来讨论如何优雅的设计数据库ID

    自增ID

    这种方式用起来最简单,也是很多程序员喜欢用的方式。使用方法:mysql有auto_increment;oracle里有sequence

    这种方式的缺点很明显,容易被探测,假设我是一个博客系统,某一遍文章的id=10,那么显示在浏览器上的地址大概是这样子:www.xxxx.com/article?id=10,对于有点程序经验的人来说,他就会直接在浏览器上打www.xxxx.com/article?id=11,id=12等,更甚的可以用postman,jmeter等http测试工具,这样就可以探测出所有的文章。博客文章系统可能还不要紧,但如果是一些商城系统,就容易泄露重要信息,比如系统有多少笔订单,每笔订单的金额、状态都可以被试探出来。

    还有一个缺点,当我们在做一个新增操作时,这个ID是数据库自增的,但是代码业务层并不知道,如果我们要拿这个ID做其他操作,这时就只能重新查一遍数据库了。

    数据库UUID

    这种方式解决了自增ID容易被探测的问题,使用方法:mysql的uuid()函数,生成出来是32位的16进制数,在有生之年不会有重复,如下图:

    ä¼éçæ°æ®åºID设计

    但是它依然有一个缺点,就是新增操作时,业务层不知道ID,非要重新查一遍数据库才知道。

    JAVA生成UUID

    这种方式解决了数据库UUID的一个问题,ID是JAVA代码生成的,减少了一次数据库查询。这种方式是大多数项目在使用的方式,具体代码如下

    public class UuidUtil {
        /**
         * 获得一个UUID
         */
        public static String getUUID(){
            String uuid = UUID.randomUUID().toString();
            //去掉“-”符号
            return uuid.replaceAll("-", "");
        }
    }
    

     

    优雅的短UUID

    JAVA生成UUID的方式虽然已经很通用了,但是依然有一个小缺点,占用的空间太大,所有表的ID都要占用32位的字符。所以我自己设计了一个短UUID,原理就是生成一个8位的62进制数,将所有的数字、大小写字母全部用上(数据库UUID是16进制,只用了数字和6个字母)。代码如下

    public class UuidUtil {
    
        public static String[] chars = new String[] { "a", "b", "c", "d", "e", "f",
                "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
                "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5",
                "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I",
                "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
                "W", "X", "Y", "Z" };
    
    
        public static String getShortUuid() {
            StringBuffer shortBuffer = new StringBuffer();
            String uuid = UUID.randomUUID().toString().replace("-", "");
            for (int i = 0; i < 8; i++) {
                String str = uuid.substring(i * 4, i * 4 + 4);
                int x = Integer.parseInt(str, 16);
                shortBuffer.append(chars[x % 0x3E]);
            }
            return shortBuffer.toString();
    
        }
    }
    

     

    生成的ID如下:

    优雅的数据库ID设计

     

    ​将UUID的32位的16进制数,每4位转成62进制,看不懂的直接用就是了,这样的短ID不仅有UUID不重复的特性,还不占用空间,8位ID在一些查询等操作的性能上也优于32位ID,这就是优雅的UUID设计方案。

    展开全文
  • 数据库id设计

    千次阅读 2018-07-25 15:30:00
     id 应该是全局唯一的,不能用户表中有id为 000001 订单表中也有000001 2.粗咯有序  比如用户的id前n位是依据时间的有序性来生成的,后m位是顺序生成. 例如 秒级有序和毫秒级有序 说的就是在每秒或每毫秒中生成的...

    1.全局唯一:

      id 应该是全局唯一的,不能用户表中有id为 000001 订单表中也有000001

    2.粗咯有序

     比如用户的id前n位是依据时间的有序性来生成的,后m位是顺序生成. 例如 秒级有序和毫秒级有序 说的就是在每秒或每毫秒中生成的id是顺序的;

    3.可反解

    比如用户系统和订单系统中有两个表,用户表中的id为000001 则此用户的订单为00000101 这样就是可反解

    展开全文
  • 数据库设计

    2020-11-08 20:01:59
    数据库设计(一对多,多对多) 数据库实体间有三种对应关系:一对一,一对多,多对多 一对多 在多的里面建立一的字段,比如班级(一)和学生(多),在学生里面添加班级id 多对多 数据库设计多对多关系的几种...

    数据库表设计(一对多,多对多)

    数据库实体间有三种对应关系:一对一,一对多,多对多

    一对多

    • 在多的里面建立一的字段,比如班级(一)和学生(多),在学生里面添加班级id
      在这里插入图片描述

    多对多

    数据库设计多对多关系的几种形态

    • 多对多:比如课程和学生,建立一个关系表,表id,课程id,学生id 即可
      在这里插入图片描述

    多对多关系至少需要3个表:主表,关系表(字典表)、副表

    • 主表
    • 字典表:纪录比较少,而且基本稳定的
      • 例如:版块名称
    • 副表:内容比较多,内容变化的
      • 按照数据库的增删查改操作

    实现

    • 数据库中的多对多关联关系一般需采用中间表的方式处理,将多对多转化为两个一对多
    • 查找实现
      • inner join 或者 select * from 主表 where id in (select 主表id from 关系表)

    类型

    1,角色任命型

    • 特点:关系表两外键组合无重复纪录,关系表一般不需要时间字段和主键,有一个表是字典类型的表
    • 界面特点:显示主表,用checkbox或多选select设置多选关系
    • 例如:任命版主(用户表-关系表-版块名称表),角色权限控制等,用户是5个版块版主,只要关系表5行纪录就可以确立,关系表的两个外键具有联合主键性 质。 增加关系:如果没有组合纪录,insert之。 删除关系:如果有组合纪录,删除之。

    2,集合分组型

    • 特点:同角色任命型类似,关系表两外键组合无重复纪录,关系表一般不需要时间字段和主键
    • 区别是主副表都不是字典表,可能都很大不固定
    • 界面特点:显示主表,用搜索代替简单的checkbox或多选select,或者一条一条的添加
    • 例如:歌曲专集(专集表-关系表-歌曲表)。手机分组(分组表-关系表-手机表)。用户圈子(圈子表-关系表-用户表)。文章标签(文章表-关系表-标签 表) 增加关系:同版主任命型。 删除关系:同版主任命型。

    3,明细帐型

    • 特点:关系表可以有重复纪录,关系表一般有时间字段,有主键,可能还有文字型的字段用来说明每次发生关系的原因(消费)
    • 界面特点:显示关系表,用radio或下拉设置单选关系
    • 例如:现金消费明细帐或订单(用户表-订单表-消费原因表),用户可能多次在同一事情上重复消费。积分变化纪录也属于这类。 增加关系:不管有没有组合纪录,insert之,纪录时间。 删除关系:根据关系表PK删除。

    4,评论回复型

    • 特点:同明细帐型关系表一般有时间字段,有主键
    • 区别是重点在文字型的字段用来说明每次发生关系的内容(评论回复)
    • 界面特点:回复文本框。 例如:论坛回复(用户表-回复表-帖子表),用户可能多次在不同帖子上评论回复费。 增加关系:不管有没有组合纪录,insert之,纪录时间和文字。 删除关系:根据关系表(回复表)PK删除。

    5,站内短信型

    • 特点:主副表是同一个,关系表一般有时间字段,有主键,重点在关系表文字型的字段用来说明每次发生关系的内容(消息)或者其他标记位来表示文字已读 状态时间等
    • 界面特点:回复文本框。 例如:站内短信(用户表-短信表-用户表),用户可能给用户群发或者单发,有标记位来表示文字已读状态时间等。 增加关系:不管有没有组合纪录,insert之,纪录时间和文字。 删除关系:根据关系表(回复表)PK删除。

    6,用户好友型

    • 特点:主副表是同一个,同集合分组型,关系表两外键组合无重复纪录,关系表一般不需要时间字段和主键
    • 界面特点:同集合分组型,显示主表,用搜索代替简单的checkbox或多选select,或者一条一条的添加
    • 例如:下载站点的文件,(文件表-关系表-文件表)可以被软件工具打开,软件工具本身也是一种文件,可以被下载。用户的好友,也是用户(用户表-好友关系 表-用户表) 增加关系:同版主任命型。 删除关系:同版主任命型。

    7,未知属性型

    • 特点:在设计初期,主表的某些字段类型和名称是不确定的时候,关系表实际上是主表的可扩展字段, 一个[主表](ID), 一个[属性名称表](属性ID.属性名称), 一个[属性值表],包括3个字段: 属性值(属性Value varchar(500)) 主表ID 属性ID 这样可以作到最小冗余度。
    • 和常见的多对多关系不同的是:值统一用varchar来存储,因为这类型的值一般不会用来计算

    比如: 军队的数据库设计中有种物资叫做“战缴物资”,就是打仗的时候缴获的,军队自己都不知道这些物资有什么属性。

    比如缴获的化学品有化学名,通用名,是否有辐射,计量单位,包装规格,数量等等,或者不是化学品是其他任何未知的东西。 这样东西就可以

    某奇怪东西.属性集合[“某某奇怪属性名”]=“某某奇怪值”;

    某变态东西.属性集合[“某某变态属性名”]=“某某变态值”; 这样存储。

    再比如: 手机型号有几千种,除了共同属性外还有不同属性有几百个,属性名和值类型都不一样,有的手机有这属性,有的没有。 对于这样的“多态”,我们就采用上面的设计结构。 其效果相当于: 某奇怪手机.属性集合[“某某奇怪属性名”]=“某某奇怪值”; 某变态手机.属性集合[“某某变态属性名”]=“某某变态值”;

    界面特点:设置主表一行纪录的属性时候,要列出所有可能的属性名称,每个对应一个文本框。

    展开全文
  • 数据库ID字段的设计

    2010-06-06 07:49:58
    背景:  1、前段时间新疆地区网络不能对外访问,公司需要在新疆地区架设镜像站。结果又TM能访问了,公司又要求把镜像站与新疆地区独有的一些数据迁移回总公司...后来参考朋友公司的数据库,我想设计大型数据库时...
  • 数据库第八章 关系数据库设计 无损分解&有损分解 一个数据库的好坏主要取决于ER图的设计质量 该数据表: 存在数据的冗余,且如果一个系没有教师,则无法表示该系的信息(dept_name,building,budget) 因此可以...
  • 数据库设计

    2020-10-16 15:03:06
    我们在设计数据库的时候,是否会突破常规,找到最适合自己需求的设计方案,下面来举个例子: 常用的邻接表设计,都会添加 一个 parent_id 字段,比如区域表(国、省、市、区): CREATE TABLE Area( [id]...
  • 在线数据库设计| 历史| dbdesigner.id是作者的业余爱好项目。 首先,该项目只是学习使用画布。 现在这个项目已经发展成为真正的数据库设计。 感谢您提供有关此数据库设计器的所有建议和反馈。 科技栈 该数据库设计器...
  • CRM客户关系)crm数据库设计说明书 CRM数据库设计说明书 表格清单 1用户表sys_user 名称 字段 数据类型 说明 编号 Usr_id bigint 主键非空 用户名 Usr_name nvarchar(50) 非空 密码 Usr_password nvarchar(50) 非空 ...
  • 数据库设计 需求 表结构 字段类型、是否允许为null、是否有默认值 索引设计 数据库引擎的选择 根据产品原型分析,词性分析法,名词创建表或字段,动词表示关系。 数据存储:长期存储的数据, 1.主键...
  • 数据库表格设计

    2016-07-12 16:08:00
    数据库表格设计 1.user 字段数据类型说明 id int PRIMARY_KEY AUTO_INCREMENT date date user_name varchar(16) UNIQUE student_id varchar(16) email varchar(256) ...
  • 数据库设计

    2017-03-08 14:40:18
    这几天一直在做支付系统的数据库设计,感觉要设计一个数据库的表 实在是太难了,这几天总是数据库不是增加字段就是删减字段,然后搞得java代码一直在改,然后项目进度就一直被拖住,我说说自己的心得,第一 重要的...
  • 数据库外键设计

    2018-10-17 13:31:21
    数据库外键设计时,一般会遇到两个问题,无法创建外键,一个是联动删除。 拿班级表(t_class)和学生表(t_student)来说吧,t_class是父表,t_student是子表。t_student表的class_id关联着t_class表的id。 无法创建外键...
  • java返回新插入数据库的记录的id数据库设计id为自增长)
  • 数据库设计

    2019-09-01 18:44:16
    数据 库的设计 多表之间的关系 一对一: 人和身份证,一个人只有一个身份证,一个身份证值能对应一个人 ...数据库设计的范式 多对多 表的第三张表的建立 create table teb_favorite( rid int ,-----线路id data ...
  • 优雅的数据库ID设计方案

    千次阅读 2019-03-26 16:32:02
    数据库表设计是项目开发中逃不掉的问题,每一张表,我们都会设计一个ID主键字段,关于表ID的生成方式,每个人都有自己的见解,我们就来讨论如何优雅的设计数据库ID 自增ID 这种方式用起来最简单,也是很多程序员...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 7,719
精华内容 3,087
关键字:

数据库id设计