用knex迁移保证所有的比赛条件

有人告诉我,Promise.all可以解决诺言的顺序是没有保证的。 但是,我并没有看到它不能从Promise.all原生文档中sorting。

因此,以下knex迁移方法应该不起作用,因为messages具有对用户表的引用。

然而,我从来没有遇到过一次这样的情况,在几次迁徙中,出现了种族差错的情况。 意思是,好像Promise,所有的都是按照索引位置来解决的。

所以,我的问题是:下面的代码片段容易出现竞争状态吗?

  return Promise.all([ knex.schema.createTable('users', function(table) { table.increments().primary(); ... }), knex.schema.createTable('messages', function(table) { table.increments().primary(); table.bigInteger('user_id').unsigned().index() .references('id').inTable('users'); }), 

这是更好的方法吗?

  return Promise.all([ knex.schema.createTable('users', function(table) { table.increments().primary(); ... }), ]).then(function() { return Promise.all([ knex.schema.createTable('messages', function(table) { table.increments().primary(); table.bigInteger('user_id').unsigned().index() .references('id').inTable('users'); }), }); }) 

既然你有一个依赖关系,那么你需要先创build第一个表,然后才能在第二个表中引用它,那么应该使用这个方法。

Promise.all是否会看到它的承诺是否按索引顺序解决,与Promise.all本身无关,而是以个别承诺作为parameter passing给它。 虽然您可以期望JavaScript(而不是Promise.all )按顺序评估参数列表,但您不能一般性地知道哪些promise会先解决。 这是由个人承诺决定的,而不是由Promise.all

就像你的情况一样,这些个体承诺也会做类似的事情,比如创build一个表,并且你的数据库引擎可能会按顺序处理这些语句,而没有并发性,你可能会在实践中看到承诺总是按照你列出的顺序来解决,但是依靠这种做法是不好的做法。

请注意,如果您向Promise.all传递一个只有一个承诺的数组, Promise.all您可以跳过Promise.allthen立即应用该承诺。

我期待这个代码是在迁移文件,默认情况下创build隐式事务。 所以,因为查询被发送到相同的连接,他们将不会并行解决。

在这种情况下,数据库驱动程序(至less是pg )实际上会caching第二个查询并等待,直到第一个查询被parsing,然后将第二个查询发送到数据库服务器。

唯一重要的是这两个查询被执行并发送到pg-driver。

由于Promise.all不保证它会在knex.schema.createTable('messages',...)之前执行knex.schema.createTable('users',...)查询knex.schema.createTable('messages',...)这意味着有理论上的可能那第一个代码将会失败。


tl; dr第一种方法不容易出现竞争条件,但如果查询按错误顺序执行,则可能会失败。 第二种方法更好。

    Interesting Posts