【问题标题】:How To Implement ACID Transactions in Loopback如何在 Loopback 中实现 ACID 事务
【发布时间】:2016-01-23 16:15:00
【问题描述】:

我们一直在尝试在 Loopback 中实现 ACID 事务,但没有成功。文档中的唯一示例使用“创建”方法。我们已经尝试完全覆盖事件以及操作挂钩的多种变体。我们只能让 create 示例工作。

核心需求:我们需要能够在特定模型的 create 和 update 方法中启动一个事务,然后在事务中更新多个表(使用 Loopback 的 ORM 函数或直接使用 SQL ) 具有基于业务规则提交或回滚的能力。 例如,我们需要端点能够接受带有抬头和明细交易的发票,对其进行验证,更新各种表(例如库存和客户),然后保存(或回滚)一个 ACID 事务中的所有更改。

使用数据库事务: https://docs.strongloop.com/display/public/LB/Using+database+transactions)

这是文档中的示例:

Post.create({title: 't1', content: 'c1'}, {transaction: tx}, function(err, post) {
  post.updateAttributes({content: 'c2', {transaction: tx}, function(err, newPost) {
    //
    newPost.reviews.create({content: 'r1'}, {transaction: tx}, function(err, newPost) {
    });
  }
});

操作钩子: https://docs.strongloop.com/display/public/LB/Operation+hooks

我们只能成功覆盖几个核心方法:

    Item.create = function(id, cb){
        console.log('create');  // Success!
    }
    //
    Item.find = function(id, cb){
        console.log('find'); // Success!
    }

    Item.findById = function(id, cb){
        console.log('findById'); // Success!
    }

    Item.getById = function(id, cb){
        console.log('updateAttributes'); // Did not work!
    }

    Item.all = function(id, cb){
        console.log('all'); // Did not work!
    };

    Item.findOrCreate = function(id, test, cb){
        console.log('findOrCreate'); // Did not work!
    }

    Item.replicate = function(id, test, cb){
        console.log('replicate'); // Did not work!
    }

    Item.save = function(id, test, cb){
        console.log('save'); // Did not work!
    }

    Item.updateAll = function(id, test, cb){
        console.log('updateAll'); // Did not work!
    }

    Item.upsert = function(id, test, cb){
        console.log('upsert'); // Did not work!
    }

    Item.updateAttribute = function(id, cb){
        console.log('updateAttribute'); // Did not work!
    };

    Item.updateById = function(id, test, cb){
        console.log('updateById'); // Did not work!
    }

在操作挂钩中实现保存、更新等也不起作用:

Item.observe('before save', function(ctx, next) {

    console.log('before save');

    ctx.Model.beginTransaction({isolationLevel: ctx.Model.Transaction.READ_COMMITTED}, function(err, tx) {

        // Now we have a transaction (tx)
        console.log('begin transaction', err);

        //tx.commit(function(err) {
        //    console.log('commit', err);
        //})

        //tx.rollback(function(err) {
        //    console.log('rollback', err);
        //})

        next();
    });
})

【问题讨论】:

  • 到目前为止,我们无法找到任何完整的文档(包括 Loopback 文档)或任何使用 Loopback 的完整 ACID 事务的完整示例。这个功能真的完全发布了吗?
  • 经过一番挫折后,我们决定不使用 Loopback 中的数据库事务功能,并实现了 Knex SQL Query Builder。 Knex 有一个非常好的、独立于数据库的接口,支持多表事务。
  • 嗨,我评论只是为了添加环回 2 文档的新链接:loopback.io/doc/en/lb2/Using-database-transactions.htmlloopback.io/doc/en/lb2/Operation-hooks.html

标签: javascript transactions loopbackjs strongloop acid


【解决方案1】:

我已经设法使交易正常进行,但我不知道这是否是最好的方法。 我需要检查“实例”,因为当找不到用户时它不会返回错误,但实例为空。我使用内置的 Promise 做到了,因为使用回调会非常难看。

在以下示例中,我必须找到两个用户才能同时更新他们。只有当两个值都被修改时,事务才应该成功。如果在此期间发生了一个错误,则应停止事务(回滚)。

var firstUserInstance;
var secondUserInstance;

User.beginTransaction('READ COMMITTED', function(err, tx) {
      // find first user and pass it to first 'then'
      User.findById(firstUser.userId, {transaction: tx})
        .then(function(instance){
            if(instance){
                firstUserInstance = instance;
                //Pass second user instance to next 'then'
                return User.findById(firstUser.userId, {transaction: tx});
            }else{
                throw ({message: "User not found", status: 400});
            }
        })
        // Update first user
        .then(function(instance){
            if(instance){
                secondUserInstance = instance;
                //Update first user and pass result to next 'then'
                return firstUserInstance.updateAttribute("attribute", "newValue", {transaction: tx});
            }else{
                throw ({message: "User 'toUserId' not found", status: 400});
            }

        })
        // Update second user
        .then(function(instance){
            if(instance){
                //Update second user and pass result to next 'then'
                return secondUserInstance.updateAttribute("attribute", "newValue", {transaction: tx});
            }else{
                throw ({message: "Error updating", status: 401});
            }
        })
        .then(function(instance){
            if(instance){
                //Everything went OK - commit changes
                console.log(instance);
                tx.commit(function(err){});
            }else{
                throw ({message: "Error updating", status: 401});
            }

        })
        .catch(function(err){
            //Something happened - Any thrown errors will end here - rollback changes
            console.log(err);
            tx.rollback(function(err){});
        });

    });

我对此并不完全满意,我认为还有更好的方法,但我希望这会有所帮助!

【讨论】:

  • 在这里,您只对 User 表上的提交执行此操作。您知道是否可以创建跨多个表的事务?即:更新用户,更新个人资料,更新其他内容..
  • 您可以跨模型传递事务对象。这看起来更丑陋,但有效。 ``` Model.findOne({}, { transaction: tx }) ```
猜你喜欢
  • 2020-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多