mongodb在游戏开发领域的优势

1、分布式id

游戏服务器里的大部分数据都是要求全局唯一的,例如玩家id,道具id。之所以有这种要求,是因为运营业务上需要进行合服操作,保证不同服的数据在进行合服之后,也能保证id不冲突。如果采用关系型数据库(例如mysql),常见的分布式id算法有以下方法。

  • 分段步长:把long型数字的前N位标记为区服id,剩余的后面所有位用作计算器自增长,并把最大的id进行持久化。
  • 雪花算法变种:将雪花算法与游戏区服、系统时间戳、计算器结合起来。

详情可参考: 游戏服务器框架之分布式id生成器

如果选择mongodb,由于其内置一个非常简单高效的分布式id生成算法,可以直接使用。不用业务代码自行设计。

详情可参考: Mongodb分布式id

2、数据库ddl自动化

目前,很多orm框架都不支持自动建表加字段(原生的mybatics,mybatics-plus均不支持,hibernate支持),因为要实现这个功能,需要应用层使用jpa或者其他注解显示表明哪些字段是需要持久化以及对应的类型。

而mongodb。甚至支持在同一个文档里有不同的文档结果。不过这种支持在应用层通常不会这么做,容易造成业务代码混乱。试想一下,把数据库的全部表数据全部打包到单独一个数据表,这种设计绝对是个噩梦。

  1. 自动创建集合:在 MongoDB 中,当你尝试向尚不存在的集合中插入一个文档时,MongoDB 会自动创建该集合。例如,如果你有一个文档并尝试将其保存到数据库中,而该集合不存在,MongoDB 将自动创建它。

    db.mycollection.insertOne({name: "example", value: "data"})
  2. 自动添加字段:当你插入一个新文档或更新现有文档时,如果文档中包含集合中其他文档不存在的字段,MongoDB 会自动将这些字段添加到文档中。例如:

    db.mycollection.updateOne({}, {$set: {newField: "value"}}, {upsert: true})

    这个命令会为集合中的每个文档添加 newField 字段,如果文档中已经存在该字段,则会更新它的值。

  3. 使用 $set 操作符$set 操作符可以用来为文档添加新字段或更新现有字段的值。如果指定的字段不存在,它会被添加。

    db.mycollection.updateMany({}, {$set: {newField: "defaultValue"}}, {multi: true})

3、嵌套数据处理

使用关系型数据,当我们需要保存用户某一个模块的内容,比如vip数据,我们一般会在Player类加一个嵌套bean,例如叫VipRight。这个嵌套的bean映射到MySQL,可以表示为一个字段。针对一个javabean到一个mysql字段的转换,通常有两种方法。

第一种,同时申明一个bean对象以及这个对象对应的json字符串,类似下面的定义

@Data
public class Player {private String id;private VipRight vipRight;private String vipRightJson;}

其中,VipRight又是另外一个javabean,定义如下:

@Data
public class VipRight {private int level;private int exp;
}

当我们从数据库里读取记录时,需要先将json进行反序列化为对应的javabean;当我们写入数据库的时候,则将javabean序列化为json,再持久化到数据库。这种方法写起来非常啰嗦。

另外一种方式,则是通过自定义的orm工具,通过特定的注解,程序自动将json与bean进行转换。例如jforgame-orm工具,就是采用这种方式。

@Data
public class PlayerEnt implements BaseEntity<Long> {@Id@Columnprivate long playerId;/*** 所属账号id*/@Columnprivate long accountId;@Columnprivate String name;@Columnprivate int level;@Column@Convert(converter = JpaObjectConverter.class)private VipRight vipRight;
}

如果采用Mongodb,则这种问题不复存在。Mongodb天生支持嵌套文档,springdata mongodb自动会对其进行转换,如下代码:

@Data
@Document("player")
public class Player {@Idprivate String id;@Fieldprivate VipRight vipRight;}

4、对嵌套bean数据的查询

还是以上边的例子,如果程序需要在启服的时候捞取vip等级前50的数据作为排行榜,如果采用mysql的话,由于mysql查询不支持json子查询,我们不得不在player类增加一个冗余字段,额外保存vip等级,例如下面的代码。在更新的时候需要两个位置一起更新,非常麻烦。

@Data
public class Player {private String id;private VipRight vipRight;private String vipRightJson;//冗余vip等级字段private int vipLevel;}

采用mongodb的话,由于其支持嵌套子查询,直接一个子bean搞定,在springdata mongodb里,插入与查询只需如下代码:

        PlayerRepository bean = SpringContext.getBean(PlayerRepository.class);Player demo = new Player();VipRight vipRight = new VipRight();vipRight.setExp(111);vipRight.setLevel(100);demo.setVipRight(vipRight);bean.insert(demo);List<Player> byVipRight = bean.findByVipRight(100);System.out.println(byVipRight.size());

其中,嵌套文档查询需要用自定义的行为

import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;
import org.springframework.stereotype.Repository;
import org.tea.editor.domain.Player;import java.util.List;@Repository
public interface PlayerRepository extends MongoRepository<Player, String> {@Query("{'vipRight.level':?0}")List<Player> findByVipRight(int level);
}

如果使用mongosh查询的话,查询语句如下:

 db.player.find({"vipRight.level":100})
//输出结果
[{_id: ObjectId('664ac4453b9f7f0308a03f2a'),vipRight: { level: 100, exp: 111 },_class: 'org.jforgame.Player'}
]

5、水平拓展

MongoDB 水平扩展:

MongoDB 支持通过分片集群实现数据的水平扩展。分片是一种将数据分布到多个服务器或集群上的技术,通过将数据分成多个片段并存储在多个服务器上,MongoDB 能够提高数据库的存储容量和吞吐量。分片集群包含两个主要概念:

  • 分片:将数据分割成多个片段,每个片段存储在集群中的一台服务器上。
  • 副本集:副本集是分片集群中的一种数据冗余技术,通过在多个服务器上保存同一份数据的副本来确保数据的可靠性和可用性。

分片集群的优点包括:

  • 读写水平扩展:MongoDB 可以将读写负载分布到集群中的不同分片上,提高吞吐量,并在高并发情况下保持高性能。
  • 数据冗余和可用性:副本集提供数据冗余和可用性保障,即使某个服务器发生故障,也能快速切换到其他可用服务器上。

MySQL 水平扩展:

MySQL 的水平扩展能力相对有限,通常需要通过分库分表的方式来实现。水平拆分是通过某种策略将数据分片存储,每片数据分散到不同的MySQL表或库,达到分布式的效果。MySQL的水平扩展主要包括:

  • 表分区:MySQL 支持表分区,这是一种简单的水平拆分,用户需要在建表时加上分区参数,对应用是透明的无需修改代码。
  • 读写分离:通过主从复制,可以实现读写分离,提高数据库的读取性能。
  • 分库分表:通过将数据分布到不同的MySQL实例,实现水平扩展。

MySQL 水平扩展的策略可能涉及:

  • 垂直拆分:根据数据库内数据表的相关性进行拆分。
  • 水平拆分:通过某种策略将数据分片存储,每片数据分散到不同的MySQL表或库。

水平扩展策略的选择需要考虑数据的增长模式、访问模式、分片关联性问题以及分片扩容问题。每种策略都有其优缺点,需要根据具体的业务需求和场景来决定最合适的扩展方案。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/15700.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++题解】1699 - 输出是2的倍数,但非3的倍数的数

问题&#xff1a;1699 - 输出是2的倍数&#xff0c;但非3的倍数的数 类型&#xff1a;循环 题目描述&#xff1a; 请从键盘读入一个整数 n&#xff0c;输出 1∼n 中所有是 2 的倍数&#xff0c;但非 3 的倍数的数&#xff0c;每行 1个。 比如&#xff0c;读入一个整数10 &…

Spring AI实战之二:Chat API基础知识大串讲(重要)

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码)&#xff1a;https://github.com/zq2599/blog_demos Spring AI实战全系列链接 Spring AI实战之一&#xff1a;快速体验(OpenAI)Spring AI实战之二&#xff1a;Chat API基础知识大串讲(重要)SpringAIOllama三部曲…

Linux:进程地址空间、进程控制(一.进程创建、进程终止、进程等待)

上次介绍了环境变量&#xff1a;Linux&#xff1a;进程概念&#xff08;四.main函数的参数、环境变量及其相关操作&#xff09; 文章目录 1.程序地址空间知识点总结上述空间排布结构是在内存吗&#xff1f;&#xff08;进程地址空间引入&#xff09; 2.进程地址空间明确几个点进…

NDIS小端口驱动开发(三)

微型端口驱动程序处理来自过度驱动程序的发送请求&#xff0c;并发出接收指示。 在单个函数调用中&#xff0c;NDIS 微型端口驱动程序可以指示具有多个接收 NET_BUFFER_LIST 结构的链接列表。 微型端口驱动程序可以处理对每个NET_BUFFER_LIST结构上具有多个 NET_BUFFER 结构的多…

JAVA -- > 初识JAVA

初始JAVA 第一个JAVA程序详解 public class Main {public static void main(String[] args) {System.out.println("Hello world");} }1.public class Main: 类型,作为被public修饰的类,必须与文件名一致 2.public static 是JAVA中main函数准写法,记住该格式即可 …

python皮卡丘动画代码

在Python中&#xff0c;我们可以使用多种方法来创建皮卡丘的动画&#xff0c;例如使用matplotlib库。 解决方案1&#xff1a;使用matplotlib库 以下是一个使用matplotlib库创建皮卡丘动画的例子&#xff1a; import matplotlib.pyplot as plt import matplotlib.animation …

Slash后台管理系统代码阅读笔记 如何实现环形统计图表卡片?

目前&#xff0c;工作台界面的上半部分已经基本梳理完毕了。 接下来&#xff0c;我们看看这个环形图卡片是怎么实现的&#xff1f; 具体代码如下&#xff1a; {/*图表卡片*/} <Row gutter{[16, 16]} className"mt-4" justify"center">{/*环形图表…

U盘引导盘制作Rufus v4.5.2180

软件介绍 Rufus小巧实用开源免费的U盘系统启动盘制作工具和格式化U盘的小工具&#xff0c;它可以快速将ISO镜像文件制作成可引导的USB启动安装盘&#xff0c;支持Windows或Linux启动&#xff0c;堪称写入镜像速度最快的U盘系统制作工具。 软件截图 更新日志 github.com/pbat…

嵌入式全栈开发学习笔记---C语言笔试复习大全24

目录 内存管理 内存分配 堆和栈的区别&#xff1f;&#xff08;面试重点&#xff09; 申请内存的函数 malloc realloc free gcc工具链 编译的过程&#xff08;面试重点&#xff09; 第一步&#xff0c;预处理&#xff1a; 第二步&#xff0c;编译&#xff1a; 第三…

【Spring Boot】使用 Redis + Cafeine 实现二级缓存

使用 Redis Caffeine 实现二级缓存可以有效提升应用的性能和缓存的命中率。Caffeine 是一个高效的 Java 本地缓存库&#xff0c;而 Redis 是一个分布式缓存解决方案。通过将两者结合&#xff0c;Caffeine 作为一级缓存用于快速访问常用数据&#xff0c;Redis 作为二级缓存用于…

解决LabVIEW通过OPC Server读取PLC地址时的错误180121602

在使用LabVIEW通过OPC Server读取PLC地址时&#xff0c;若遇到错误代码180121602&#xff0c;建议检查网络连接、OPC Server和PLC配置、用户权限及LabVIEW设置。确保网络畅通&#xff0c;正确配置OPC变量&#xff0c;取消缓冲设置以实时读取数据&#xff0c;并使用诊断工具验证…

簡述vue常用指令

Vue.js 提供了许多内置指令&#xff0c;这些指令用于在模板中添加特殊功能。以下是一些 Vue 的常用内置指令的简要说明&#xff1a; v-text&#xff1a; 更新元素的 textContent。示例&#xff1a;<span v-text"message"></span> v-html&#xff1a; 更…

2 使用香橙派AIpro报错 No module named ‘acllite utils‘

当使用jupyter运行香橙派的notebooks下面的案例的时候启动使用jupyter lab 然后自动跳转到jupyter页面。如下图: 这是自动跳转过来的。然后运行下面的包的导入后报错: 报错为No module named ‘acllite utils’,那么我们打开notebooks文件夹下面的start_notebooks.sh文件:…

【C++练级之路】【Lv.21】C++11——列表初始化和声明

快乐的流畅&#xff1a;个人主页 个人专栏&#xff1a;《算法神殿》《数据结构世界》《进击的C》 远方有一堆篝火&#xff0c;在为久候之人燃烧&#xff01; 文章目录 引言一、列表初始化1.1 内置类型1.2 结构体或类1.3 容器 二、声明2.1 auto2.2 decltype2.3 nullptr 三、STL的…

A*算法搜索的路径是最优的么?

A * 算法&#xff08;A* Search Algorithm&#xff09;是一种启发式搜索算法&#xff0c;它旨在找到从起点到终点的最短路径。在满足以下条件时&#xff0c;A*算法能够保证找到最优路径&#xff1a; 启发式函数的一致性&#xff08;Consistency&#xff09;或可采纳性&#xf…

从“反超”到“引领”,中国卫浴品牌凭何遥遥领先?

作者 | 曾响铃 文 | 响铃说 前不久&#xff0c;第28届中国国际厨房、卫浴设施展览会(以下简称“中国国际厨卫展”)在上海如期举行&#xff0c;就结果来说真的让人大开眼界。 冲水声比蚊子声更小的马桶、能化身无感交互平台的魔镜柜、可以语音交互的淋浴器&#xff0c;这些“…

Keli5烧写STM32程序时出现ST-LINK USB communication error错误(USB 通信错误)

1错误原图 2错误原因 前提驱动安装正确 原因1 usb接触不良&#xff08;极少出现&#xff09; 解决方法 更换USB线 还不行连下载器一起更换 原因2&#xff08;出现概率比较大&#xff09; 下载器的固件出现问题或下载器固件版本与Keli5的版本不匹配 解决方法 在Keli5的…

[音视频]ffmepg常用命令

ffmpeg 在音视频的世界里&#xff0c;ffmpeg可是如雷贯耳的存在&#xff0c;学习音视频开发&#xff0c;ffmpeg是必须掌握的技能 常用命令 保存m3u8文件 ffmpeg -i http://xxxxx/test.m3u8 -c copy result.mp4

今日早报 每日精选15条新闻简报 每天一分钟 知晓天下事 5月26日,星期日

每天一分钟&#xff0c;知晓天下事&#xff01; 2024年5月26日 星期日 农历四月十九 1、 医保局&#xff1a;支持将符合条件的村卫生室纳入医保定点&#xff0c;方便农村居民就医。 2、 网传养老金储备严重不足&#xff1f;央视辟谣&#xff1a;这笔钱二十多年来从未动用过&a…

搭建企业级AI应用的流程

搭建企业级AI应用的流程是一个复杂且系统化的工程&#xff0c;它需要从多个维度出发&#xff0c;确保最终的应用既符合企业的业务需求&#xff0c;也具备高效、稳定和可扩展的特性。以下是详细的步骤&#xff1a; 初步接触与需求分析是整个项目的基础。在这一阶段&#xff0c;我…