用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.all
, then
立即应用该承诺。
我期待这个代码是在迁移文件,默认情况下创build隐式事务。 所以,因为查询被发送到相同的连接,他们将不会并行解决。
在这种情况下,数据库驱动程序(至less是pg
)实际上会caching第二个查询并等待,直到第一个查询被parsing,然后将第二个查询发送到数据库服务器。
唯一重要的是这两个查询被执行并发送到pg-driver。
由于Promise.all
不保证它会在knex.schema.createTable('messages',...)
之前执行knex.schema.createTable('users',...)
查询knex.schema.createTable('messages',...)
这意味着有理论上的可能那第一个代码将会失败。
tl; dr第一种方法不容易出现竞争条件,但如果查询按错误顺序执行,则可能会失败。 第二种方法更好。