Как использовать транзакции базы данных в MongoDB и Node.js
Программирование

Как использовать транзакции базы данных в MongoDB и Node.js

Обеспечьте максимальную надежность хранения данных с помощью транзакций MongoDB

Создание готового к производству веб-приложения требует обеспечения его безопасности и масштабируемости

Одним из наиболее важных моментов, которые необходимо знать о базах данных, является принцип ACID, который расшифровывается как атомарность, согласованность, изоляция и долговечность. Реляционные базы данных, такие как MySQL, поддерживают транзакции ACID. Но MongoDB является NoSQL базой данных и по умолчанию не поддерживает ACID транзакции

Как программист, вы должны знать, как внедрить свойства ACID в ваши базы данных MongoDB

Что такое транзакции базы данных?

Транзакция базы данных – это последовательность запросов или операций базы данных, которые выполняются как единое целое для выполнения одной задачи

Транзакции базы данных придерживаются концепции ACID-характеристик. Это позволяет гарантировать, что никаких изменений не произойдет, пока все операции не будут выполнены успешно. Это также обеспечивает согласованность базы данных

Объяснение свойств ACID

Четыре свойства, составляющие принципы ACID, следующие:

  • Атомарность – это свойство, которое концептуализирует транзакции как небольшие единицы программы. Это означает, что все запросы либо выполняются успешно, либо терпят неудачу.
  • Согласованность утверждает, что записи базы данных должны оставаться согласованными до и после каждой транзакции.
  • Изоляция гарантирует, что при одновременном выполнении нескольких транзакций одна из них не влияет на другую.
  • Долговечность ориентирована на системные сбои или неполадки. Она гарантирует, что зафиксированная транзакция не будет потеряна в случае системного сбоя. Это может включать методы, необходимые для автоматического восстановления данных из резервной копии после возобновления работы системы.
  • Как реализовать транзакции базы данных MongoDB в Node.js с помощью Mongoose

    MongoDB с годами стала широко используемой технологией баз данных благодаря своей природе NoSQL и гибкой модели на основе документов. Он также предлагает вам возможность лучше организовать ваши данные и более гибко, чем в SQL или реляционных базах данных

    Для реализации транзакций базы данных в MongoDB можно рассмотреть примерный сценарий приложения для размещения объявлений о вакансиях, где пользователь может разместить, обновить или удалить вакансию. Вот простой дизайн схемы базы данных для этого приложения:

    Чтобы следовать дальше, этот раздел требует базовых знаний программирования Node.js и MongoDB

    Транзакции не поддерживаются в автономных установках MongoDB. Для работы транзакций необходимо использовать набор реплик MongoDB или кластер MongoDB sharded. Поэтому самый простой способ использовать транзакции – это создать экземпляр MongoDB, размещенный в облаке (MongoDB Atlas). По умолчанию каждый экземпляр базы данных Atlas представляет собой набор реплик или кластер с черепками

    Создав рабочий проект Node.js и MongoDB, вы можете установить соединение с базой данных Mongo в Node.js. Если вы не сделали этого раньше, установите mongoose, выполнив npm install mongoose в терминале

    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
    }
    };

    Вы должны сохранить соединение в переменной, чтобы вы могли использовать его для инициирования транзакции позже в программе

    Вы можете реализовать коллекции пользователей и заданий следующим образом:

    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);

    Вы можете написать функцию для добавления пользователя в базу данных следующим образом:


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

    Приведенный ниже код демонстрирует функцию создания задания и добавления его в список заданий плаката с использованием транзакции базы данных


    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');
    }
    };

    Запрос create, выполняемый в транзакции, обычно принимает и возвращает массив. Вы можете увидеть это в приведенном выше коде, где он создает newJob и сохраняет его свойство _id в переменной newJobId

    Вот демонстрация того, как работают вышеупомянутые функции:

    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));

    Если вы сохраните этот код и запустите его с помощью npm start или команды node, он должен выдать результат, подобный этому:

    Другой способ реализации ACID-транзакций в MongoDB с помощью Mongoose – это использование функции withTransaction(). Этот подход обеспечивает небольшую гибкость, поскольку все запросы выполняются внутри функции обратного вызова, которую вы передаете в качестве аргумента функции

    Вы можете рефакторизовать приведенную выше транзакцию базы данных для использования функции withTransaction() следующим образом:

    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 {
    const transactionSuccess = await session.withTransaction(async () => {
    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);
    });

    if (transactionSuccess) {
    console.log('Successfully carried out DB transaction');
    } else {
    console.log('Transaction failed');
    }
    } catch (e) {
    console.error(e);
    console.log('Failed to complete database operations');
    } finally {
    await session.endSession();
    console.log('Ended transaction session');
    }
    };

    Это даст тот же результат, что и предыдущая реализация. Вы вольны выбирать, какой стиль использовать при реализации транзакций базы данных в MongoDB

    В этой реализации не используются функции commitTransaction() и abortTransaction(). Это связано с тем, что функция withTransaction() автоматически фиксирует успешные транзакции и прерывает неудачные. Единственная функция, которую вы должны вызывать во всех случаях – это функция session.endSession()

    Реализация ACID транзакций базы данных в MongoDB

    Транзакции баз данных просты в использовании, если они выполнены правильно. Теперь вы должны понимать, как работают транзакции баз данных в MongoDB и как их можно реализовать в приложениях Node.js

    Для дальнейшего изучения идеи транзакций ACID и того, как они работают в MongoDB, рассмотрите возможность создания финтех-кошелька или приложения для ведения блогов

    Об авторе

    Алексей Белоусов

    Привет, меня зовут Филипп. Я фрилансер энтузиаст . В свободное время занимаюсь переводом статей и пишу о потребительских технологиях для широкого круга изданий , не переставая питать большую страсть ко всему мобильному =)

    Комментировать

    Оставить комментарий