Cách dùng Database Transaction với MongoDB và Node.js

Đảm bảo lưu trữ dữ liệu của bạn hoạt động mạnh mẽ nhất có thể bằng các giao dịch MongoDB. Dưới đây là cách dùng Database Transaction với MongoDB và Node.js.

Giao dịch cơ sở dữ liệu với MongoDB

Xây dựng ứng dụng web sẵn sàng hoạt động yêu cầu bạn phải đảm bảo nó an toàn và có thể mở rộng.

Một trong số điều quan trọng nhất cần biết về database là nguyên tắc ACID, viết tắt của atomicity - tính nguyên tử, consistency- nhất quán, isolation - cô lập và durability - độ bền. Cơ sở dữ liệu quan hệ như MySQL hỗ trợ các giao dịch ACID nguyên bản. Thế nhưng MongoDB là một database NoSQL và mặc định không hỗ trợ giao dịch ACID.

Là một lập trình viên, bạn cần biết cách đưa các thuộc tính ACID vào database MongoDB.

Database Transactions là gì?

Database Transaction là một chuỗi truy vấn hoặc hoạt động trên cơ sở dữ liệu chạy cùng nhau như một đơn vị để hoàn thành một nhiệm vụ.

Các giao dịch cơ sở dữ liệu tuân thủ những khái niệm về đặc điểm ACID. Điều này giúp đảm bảo không có thay đổi xảy ra trừ khi tất cả hoạt động đều thành công. Nó cũng đảm bảo cơ sở dữ liệu nhất quán.

4 thuộc tính tạo nên nguyên tắc ACID:

  • Atomicity là thuộc tính khái niệm hóa các giao dịch dưới dạng đơn vị nhỏ của một chương trình. Điều này áp dụng cho tất cả truy vấn cùng nhau chạy thành công hay thất bại.
  • Consistency chỉ ra rằng các bản ghi database phải giữ nguyên tính nhất quán trước và sau mỗi giao dịch.
  • Isolation đảm bảo khi nhiều giao dịch chạy đồng thời, không có giao dịch nào ảnh hưởng lẫn nhau.
  • Duration tập trung vào các thất bại hay lỗi hệ thống. Nó đảm bảo một giao dịch đã cam kết không bị mất trong sự kiện của lỗi hệ thống. Điều này có thể liên quan tới các kỹ thuật cần để khôi phục dữ liệu từ một bản sao lưu tự động khi hệ thống hoạt động trở lại.

Cách triển khai MongoDB Database Transaction trong Node.js bằng Mongoose

MongoDB đã trở thành công nghệ database được sử dụng rộng rãi suốt nhiều năm qua nhờ bản chất NoSQL và mô hình dựa trên tài liệu linh hoạt của nó. Nó cũng cung cấp cho bạn khả năng sắp xếp dữ liệu tốt và linh hoạt hơn trong SQL hoặc cơ sở dữ liệu quan hệ.

Để triển khai giao dịch database trong MongoDB, bạn có thể xem xét một tình huống mẫu trên ứng dụng liệt kê công việc tại nơi người dùng có thể đăng, cập nhật hoặc xóa một công việc. Đây là một thiết kế sơ đồ database đơn giản cho ứng dụng này:

Bảng sơ đồ công việc

Để tiếp tục, phần này yêu cầu bạn cần có kiến thức cơ bản về lập trình Node.js và MongoDB.

Lưu ý:

Giao dịch không được hỗ trợ trên bản cài MongoDB độc lập. Bạn cần dùng bản sao hoặc cụm phân đoạn MongoDB để tiến hành giao dịch. Do đó, cách dễ nhất để giao dịch là tạo một MongoDB trên đám mây (MongoDB Atlas). Mặc định, mọi phiên bản database Atlas là một bản sao hoặc cụm phân đoạn.

Sau khi thiết lập một dự án Node.js và MongoDB hoạt động, bạn có thể tạo kết nối tới một database Mongo trong Node.js. Nếu hiện chưa có, cài đặt mongoose bằng cách chạy npm install mongoose ở terminal.

import mongoose from 'mongoose'
 
let MONGO_URL = process.env.MONGO_URL || 'your-mongo-database-url';
 
let connection;
const connectDb = async () => {
  try {
    await mongoose.connect(MONGO_URL, {
      useNewUrlParser: true,
      useUnifiedTopology: true,
    });
 
    console.log("CONNECTED TO DATABASE");
    connection = mongoose.connection;
  } catch (err) {
    console.error("DATABASE CONNECTION FAILED!");
    console.error(err.message);
    process.exit(1); // close the app if database connection fails
  }
};

Bạn nên lưu trữ kết nối trong một biến để có thể dùng nó khởi tạo một giao dịch sau này trong chương trình.

Bạn có thể triển khai bộ sưu tập người dùng và công việc như sau:

const userSchema = new mongoose.Schema({
    name: String,
    email: String,
    jobs: [mongoose.Schema.Types.ObjectId]
});
 
const jobSchema = new mongoose.Schema({
    title: String,
    location: String,
    salary: String,
    poster: mongoose.Schema.Types.ObjectId
});
 
const userCollection = mongoose.model('user', userSchema);
const jobCollection = mongoose.model('job', jobSchema);

Bạn có thể viết một tính năng để thêm một người dùng vào database như sau:

const createUser = async (user) => {
    const newUser = await userCollection.create(user);
    console.log("User added to database");
    console.log(newUser);
}

Code bên dưới minh họa chức năng này để tạo một công việc và thêm nó vào danh sách cần đăng của các nhiệm vụ bằng một giao dịch database.

const createJob = async (job) => {
  const { userEmail, title, location, salary } = job;
 
  // get the user from the DB
  const user = await userCollection.findOne({ email: userEmail });
 
  // start transaction session
  const session = await connection.startSession();
 
  // run all database queries in a try-catch block
  try {
    await session.startTransaction();
 
    // create job
    const newJob = await jobCollection.create(
      [
        {
          title,
          location,
          salary,
          poster: user._id,
        },
      ],
      { session }
    );

    console.log("Created new job successfully!");
    console.log(newJob[0]);
 
    // add job to users list of posted jobs
    const newJobId = newJob[0]._id;

    const addedToUser = await userCollection.findByIdAndUpdate(
      user._id,
      { $addToSet: { jobs: newJobId } },
      { session }
    );
 
    console.log("Successfully added job to user's jobs list");
    console.log(addedToUser);
 
    await session.commitTransaction();
 
    console.log("Successfully carried out DB transaction");
  } catch (e) {
    console.error(e);
    console.log("Failed to complete database operations");
    await session.abortTransaction();
  } finally {
    await session.endSession();
    console.log("Ended transaction session");
  }
};

Đây là minh họa về cách thức hoạt động của chức năng trên:

const mockUser = {
  name: "Timmy Omolana",
  email: "jobposter@example.com",
};
 
const mockJob = {
  title: "Sales Manager",
  location: "Lagos, Nigeria",
  salary: "$40,000",
  userEmail: "jobposter@example.com", // email of the created user
};
 
const startServer = async () => {
  await connectDb();
  await createUser(mockUser);
  await createJob(mockJob);
};
 
startServer()
  .then()
  .catch((err) => console.log(err));

Nếu lưu code này và chạy nó bằng npm start hoặc lệnh node, nó sẽ cho kết quả như sau:

Giao dịch database bằng MongoDB

Trên đây là cách dùng giao dịch database với MongoDB và Node.js. Hi vọng bài viết hữu ích với các bạn.

Thứ Năm, 09/02/2023 16:44
51 👨 667
0 Bình luận
Sắp xếp theo