Nodejs mongoose如何事物回滚

Nodejs mongoose如何事物回滚

comment.save(function(error, comment){ BlogModel.update({_id: blogId}, { $push: { comments: comment } }, function(error, number){ if(number == 0){ comment.remove(function(error){ if(!error){ options.error({msg: ‘create comment fail: the speciall blog not exists’}) } }); }else{ DBUtil.handleQueryResult(error, comment, options); } }); 如果number等于0,此时comment实例新增成功,我还要手动将它delete,是否可以有一种方式让这个事物回滚


4 回复

在 Node.js 中使用 Mongoose 进行数据库操作时,如果你希望确保一系列的操作要么全部成功,要么全部失败(即事务),你可以使用 Mongoose 的事务支持。Mongoose 从版本 5.11 开始引入了对 MongoDB 事务的支持。下面是一个简单的示例来展示如何实现事务处理以及在发生错误时进行回滚。

示例代码

const mongoose = require('mongoose');
const BlogSchema = new mongoose.Schema({
    // 定义你的博客字段
});

const CommentSchema = new mongoose.Schema({
    // 定义你的评论字段
});

const Blog = mongoose.model('Blog', BlogSchema);
const Comment = mongoose.model('Comment', CommentSchema);

async function createComment(blogId, commentData, options) {
    const session = await mongoose.startSession();
    
    try {
        session.startTransaction();

        const comment = new Comment(commentData);
        
        await comment.save({ session });
        
        await Blog.updateOne(
            {_id: blogId},
            {$push: {comments: comment._id}},
            {session}
        );

        await session.commitTransaction();
        session.endSession();

        return comment;
    } catch (error) {
        console.error("Error occurred:", error);
        await session.abortTransaction();
        session.endSession();
        throw error; // 或者你可以在 catch 块中处理错误
    }
}

// 使用示例
createComment('blogIdHere', {text: 'Hello World'}, {error: function(err) {
    console.log(err.msg); // 输出错误信息
}});

解释

  1. 开始会话mongoose.startSession() 创建一个新的会话。
  2. 启动事务session.startTransaction() 启动一个新事务。
  3. 保存数据:在事务中保存 Comment 实例,并且通过 { session } 参数传递当前的会话对象。
  4. 更新博客:更新博客中的 comments 字段,同样使用 { session } 参数以确保操作属于同一个事务。
  5. 提交或回滚事务
    • 如果所有操作都成功,则调用 session.commitTransaction() 提交事务。
    • 如果在操作过程中发生任何错误,catch 块会捕获错误,并调用 session.abortTransaction() 来回滚事务。

这样,当某个步骤失败时,整个事务都会被回滚,保持数据库的一致性。


为啥不反过来?

BlogModel.update({_id: blogId}, { $push: { comments: comment } }, function(error, number){
  if(number > 0){
      ....
      comment.save(function(error, comment){

是,这样也可以,我后来用了一个Middleware: commentSchema.pre(‘save’, function(next){ Blog.model.findById(this.blogId, function(error, blog){ if(error){ next(error); }else{ if(blog){ next(); }else{ var error = new Error(); error.msg = ‘create comment fail: the speciall blog not exists’; next(error); } } }); });

在 Mongoose 中,你可以使用事务来实现操作的原子性。当某个操作失败时,你可以回滚整个事务,从而保证数据的一致性。

以下是一个示例代码,展示了如何使用 Mongoose 进行事务处理,并在发生错误时回滚事务:

const mongoose = require('mongoose');
const BlogSchema = new mongoose.Schema({
    // your schema definition here
});

const Blog = mongoose.model('Blog', BlogSchema);

async function createComment(blogId, commentData, options) {
    const session = await mongoose.startSession();
    session.startTransaction();

    try {
        const comment = await new Blog(commentData).save({ session });

        await Blog.updateOne(
            { _id: blogId },
            { $push: { comments: comment._id } },
            { session }
        );

        await session.commitTransaction();
        session.endSession();

        return comment;
    } catch (error) {
        await session.abortTransaction();
        session.endSession();

        if (!error) {
            options.error({ msg: 'create comment fail: the special blog not exists' });
        } else {
            options.error({ msg: error.message });
        }
    }
}

// 调用函数
createComment(blogId, commentData, { error: console.error })
    .then(comment => console.log('Comment created:', comment))
    .catch(err => console.error('Error:', err));

解释

  1. 会话管理:使用 mongoose.startSession() 开启一个新的会话,并通过 session.startTransaction() 开始一个事务。
  2. 保存评论:创建并保存一个新的评论对象。
  3. 更新博客:将新评论添加到博客的评论列表中。
  4. 提交或回滚事务
    • 如果一切顺利,调用 session.commitTransaction() 提交事务。
    • 如果出现任何错误,调用 session.abortTransaction() 回滚事务。

通过这种方式,你可以确保在一个事务中所有操作要么全部成功,要么全部失败。

回到顶部