MongoDB 的事务处理方式详解

在前端开发领域,很多应用都需要使用数据库来存储数据。MongoDB 是一种常用的 NoSQL 数据库,它的快速性能和灵活性受到广泛认可。但是,MongoDB 在事务处理方面的处理一直以来备受争议。该文章将详细介绍 MongoDB 的事务处理方式,深入探讨了这种处理的优缺点,并提供一些实用的指导意义和示例代码。

MongoDB 的事务处理

如果您之前不知道,MongoDB 的文档是一个完整的 JSON 对象。因此,作为文档式数据库,之前一直被认为是无法支持事务处理。然而,自从 MongoDB 4.0 推出以来,该数据库现已支持多文档事务处理。这是 MongoDB 开始成为支持关系型数据库的首选解决方案的一个重要里程碑。

MongoDB 的事务处理使用了两阶段提交协议(2PC),这是一种常用的处理分布式事务的协议。在 MongoDB 中,事务的所有操作都必须在同一个副本集合(Replica Set)或者分片集群(Sharded Cluster)中进行。因此,事务处理是分布式的,需要有效的协议来保证原子性、一致性、隔离性、持久性。

在 MongoDB 的事务处理中,有两种类型:基于副本集合的事务处理和基于分片集群的事务处理。这两种方式都涉及到多个文档的读写操作。事务中的操作可以分为读操作和写操作。读操作不需要提交事务,但写操作需要提交事务。

四种事务的执行顺序和结果

MongoDB 中的事务处理是基于四种不同的执行顺序和结果。它们是:

  • 单个操作:单个操作不需要事务而执行。我们不需要考虑提交或回滚这些操作。
  • 多个独立操作:每个操作是独立的,即使其中一个操作失败也不影响其他操作。只有在事务成功提交后,所有操作的结果才会持久化并对客户端可见。
  • 隐式事务:这是一个单个的写操作,它会触发事务,并将操作结果提交到数据库。
  • 显式事务:显式事务是完整的事务,包括开始、提交或回滚三个步骤。这种事务必须包含有一个或多个读写操作,并且需要显式提交才能生效。

在这里,我们主要关注显式事务和其中使用的操作。

MongoDB 的事务处理的优缺点

使用事务处理在任何应用程序中都是有优缺点的。MongoDB 的事务处理也不例外。在这里我们来看看 MongoDB 的事务处理的优缺点:

优点

  • 支持多文档事务:MongoDB 的事务处理支持并发读写多个文档,这意味着多个操作可以在同一个事务内提交或回滚。
  • 原子性:MongoDB 的事务处理为操作序列提供了原子性保证,即使在故障情况下也不会影响数据的完整性。
  • 一致性:操作会遵循事务原则,即事务不完全执行时,MongoDB 会自动回滚到标志位置,使得文档集合保持一致性。
  • 隔离性:MongoDB 的事务处理提供了隔离级别。事务是在隔离级别 SERIALIZABLE 和 READ COMMITTED 下运行的。 READ COMMITTED 提供了非常高的隔离级别,但实现更简单。 SERIALIZABLE 提供了最高级别的隔离,但更加复杂和影响性能。

缺点

  • 性能影响:MongoDB 的事务处理会影响系统性能,因为这需要提供更多的服务器资源来保证事务的性能和可扩展性。
  • 不支持跨文档、跨集合的事务处理:在 MongoDB 的事务处理中只能处理同一副本集或分片集群中的数据。如果需要处理跨文档或跨集合的数据,需要重新设计数据的结构。

MongoDB 的事务处理示例

下面是一个使用 MongoDB 的显式事务处理的示例代码。我们将使用一个简单的账户系统,其中包含用户账户和交易信息的集合。

在这个示例中,我们将使用两个简单的文件:一个用于测试应用程序代码的文件(test.ts),另一个包含商业代码的文件(app.ts)。以下是有关于如何使用 MongoDB 的显式事务处理的示例代码:

app.ts

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

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

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

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

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

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

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

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

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

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

此代码使用 MongoDB 的 MongoClient API 进行连接到数据库,默认端口(27017)。在此之后,该代码初始化了一个事务会话(session),并开始事务处理。在后续的代码中,会第一次查询到 users 集合中的相应数据,并确保资金充足,而且必须至少有两个查询才能提交或回滚事务。

test.ts

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

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

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

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

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

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

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

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

此代码在 test() 函数中使用 MongoClient API 连接到 MongoDB,并在 'users' 集合中插入示例数据。在此之后,它调用了从 app.ts 导入的 transferCredit() 函数。请注意,该函数没有返回值,因为它通过打印输出到控制台来展示其执行的结果。测试结束后,请将编写的代码根据测试情况进行修改。

结论

在 MongoDB 4.0 及更高版本中,显式事务处理为支持多文档事务提供了一个更可靠的方式。尽管提供事务处理是一个正确且令人惊喜的决定,但是事务处理仅适用于同一龙门阵集合或分片集群中的数据。因此,当需要处理跨多个集合或数据库的数据时,需要重新设计数据模型。

总的来说,如何有效使用 MongoDB 的事务处理取决于你的应用程序的需求。在大多数情况下,建议仅使用单个文档操作,除非必须在多个文档之间添加事务处理。因此需要权衡性能和数据一致性的影响,以确定是否使用事务。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/670f49fc5f551281026390da