前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java与MongoDB 4.0多文档事务新特性体验

Java与MongoDB 4.0多文档事务新特性体验

作者头像
MongoDB中文社区
发布2018-12-27 11:55:45
2.6K0
发布2018-12-27 11:55:45
举报
文章被收录于专栏:MongoDB中文社区MongoDB中文社区

作者:Maxime Beugnet

译者:徐雷( Frank Xu)

01

MongoDB4.0多文档事务新特性介绍

MongoDB 4.0增加了对多文档ACID事务的支持。但等等......这是否意味着MongoDB直到现在才支持事务?不,实际上MongoDB已经提供了对单个文档事务的支持。 MongoDB 4.0跨多文档、多语句、多集合和多数据库扩展了事务保证。 如果没有任何形式的事务数据完整性保证,数据库还有什么用呢?

在我们深入阅读这篇博文之前,大家可以在此处找到所有代码并尝试多文档ACID事务新特性。

02

快速入门

步骤1: 启动MongoDB

使用最小版本4.0.0,以ReplicaSet模式在localhost本机端口27017上启动MongoDB数据库。

如果使用的是Docker工具:

•可以使用start-mongo.sh启动数据库。

•完成后,可以使用stop-mongo.sh停止数据库。

•如果要使用Mongo Shell连接到MongoDB,可以使用connect-mongo.sh。

如果喜欢手动方式启动mongod:

  • mkdir /tmp/data && mongod --dbpath /tmp/data --replSet rs
  • mongo --eval 'rs.initiate()'

步骤2: 启动Java程序

该Demo包含两个主要程序:

1.ChangeStreams.java

2.Transactions.java。

•Change Steams允许收取MongoDB集合或数据库中任何数据更改的通知。

•事务过程就是Demo本身。

需要两个shell来运行它们。

如果使用 Docker:

第一个shell:

第二个shell:

如果没有使用Docker,则需要安装Maven 3.5.X和JDK 10(或至少JDK 8,但需要更新pom.xml中的Java版本):

第一个shell:

第二个shell:

我们将现有的单文档事务与MongoDB 4.0 ACID多文档事务进行比较,看看如何利用Java来使用这一新特性。

03

MongoDB4.0之前版本

在MongoDB 3.6及更早版本中,每个写操作都表示为单个文档级别的事务。 由于文档模型将相关数据汇集在一起,否则这些数据将以表格schema在单独的父子表中建模,因此MongoDB的原子单文档操作提供了满足大多数应用程序的数据完整性需求的事务语义。

修改多个文档的典型写操作实际上都发生在几个独立的事务中:每个文档一个。

让我们以一个非常简单的电商库存管理数据库为例。

首先,需要一个MongoDB副本集,请按照上面说明启动MongoDB数据库。

现在让我们将以下文档插入到产品product 集合中:

假设有一个销售活动,我们希望为客户提供所有产品20%的折扣。

但在使用此折扣之前,我们希望通过Change Streams监控MongoDB中这些操作的发生时间。

在Mongo Shell中执行以下命令:

将此shell保留,打开另一个Mongo Shell并应用折扣:

如上所示,两个文档都使用单个命令行进行更新,但不是在一个事务中。 以下是我们在Change Stream shell中可以看到的内容:

如上所示,两个操作的集群时间(clusterTime)不同:操作在同一秒内发生,但时间戳的计数器已增加1。

因此,这里文档一次更新一个,即使这种操作非常快,其他人也可以在更新运行时阅读文档,只看到两个产品中的一个有折扣。

大多数情况下,可以在MongoDB数据库中容忍这种情况,因为我们尽可能地尝试在同一文档中嵌入紧密链接或相关数据。 因此,同一文档的两个更新发生在一个事务中:

但是,有时候,无法在单个文档中对所有相关数据进行建模,并且可能还有很多正当理由不去使用嵌入文档方式。

04

MongoDB4.0多文档ACID事务

MongoDB的多文档ACID事务与传统关系数据库中已知的事务非常类似。

MongoDB事务是一组相关操作,必须以全有或全无的形式提交或全部回滚。

事务用于确保在多个集合或数据库中操作是原子性的。 因此,对于快照隔离读取,另一个用户要么看到所有操作或要么看不到操作。

现在让我们在Demo示例中添加购物车。

对于此示例,需要2个集合,因为我们正在处理2个不同的业务实体:每个客户在购物期间可以创建库存管理和购物车。 这些集合中每个文档的生命周期是不同的。

商品集合中的文档代表我正在销售的商品。 这包含商品的当前价格和当前库存。 我创建了一个POJO来代表它:Product.java。

当客户在购物车中添加第一个商品时会创建购物车,并在客户端结帐或离开网站时将其删除。 我创建了一个POJO来代表购物车:Cart.java。

这里的挑战在于我不能卖得比库存多:如果我有5瓶啤酒可以卖,不能在购物车上分发超过5瓶啤酒。

为了确保这一点,我必须确保创建或更新客户端购物车的操作与库存更新是原子性的。 这就是多文档事务发挥作用的地方。 如果有人试图购买库存中没有的东西,事务必须失败。 我在产品库存上添加约束:

注意 这些已包含在Java代码中。

为了监控我们的示例,我们将使用MongoDB 3.6中引入的MongoDB Change Streams。

在这个名为ChangeStreams.java进程的每个线程中,将监视2个集合中的一个,并使用其关联的集群时间打印每个操作。

在这个例子中,我们有5种啤酒可供出售。 Alice希望购买2瓶啤酒,但我们不会为此使用新的MongoDB 4.0多文档事务。

我们将在变更流中观察两个操作:一个创建购物车,另一个在两个不同的集群时间更新库存。

然后Alice在购物车中添加了2瓶啤酒,这次我们使用事务。变更流中的结果将监控在同一群集时间发生的2个操作。

最后,她将尝试订购2个额外的啤酒,但jsonSchema验证器将无法通过产品更新并导致事务回滚。 我们不会在变更流中看到任何内容。 这是Transaction.java源代码:

这里是Change Stream的控制台:

正如大家在此处所看到的,我们监控到四个操作信息,因为最后两个操作没有提交到数据库,因此变更流没有任何显示。

大家还可以注意到,两个第一个集群时间是不同的,因为我们没有对两个第一个操作使用事务,并且最后两个操作共享相同的集群时间,因为我们使用了新的MongoDB 4.0多文档事务特性,因此 这2个操作是原子性的。

这是Transaction.java进程的控制台,总结了我之前说过的所有内容。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-08-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Mongoing中文社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 MongoDB
腾讯云数据库 MongoDB(TencentDB for MongoDB)是腾讯云基于全球广受欢迎的 MongoDB 打造的高性能 NoSQL 数据库,100%完全兼容 MongoDB 协议,支持跨文档事务,提供稳定丰富的监控管理,弹性可扩展、自动容灾,适用于文档型数据库场景,您无需自建灾备体系及控制管理系统。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档