Knex迁移:交易查询已完成

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Knex迁移:交易查询已完成相关的知识,希望对你有一定的参考价值。

使用knex我想向现有表中添加2个其他列。为了预先存在记录,我想基于计算添加一个值。以下是我的迁移文件。它在第二行失败:Cannot read property 'resolve' of undefined

exports.up = function (knex, Promise) {
  return Promise.resolve()
    .then(function(){
            ... cut to shorten question...
    })
};

更新:我删除了Promise,现在下面有迁移代码。这仍然会产生两个错误,可能与forEach循环有关,并且它不会等待循环的一部分完成之后再进行下一部分(但是我不知道该怎么做) ):

未处理的拒绝MigrationLocked:迁移表已被锁定

交易查询已经完成,请使用DEBUG = knex:tx来运行以获取更多信息

const Coupon = require('../../models/coupon');
const Plan = require('../../models/plan');

exports.up = function (knex) {
    return knex.schema.table('transactions', (table) => {
      table.decimal('plan_price', 10, 2);
      table.decimal('discount', 10, 2).defaultTo(0);
    })

    .then(function(return_value){
      knex.select().from('transactions')
      .then((transactions) => {
        transactions.forEach(async function(trans){
          let original_price;
          let total_coupon_discount = 0;

          const plan = await Plan.where({id: trans.plan_id}).fetch();
          if (plan) { original_price = plan.get("price") };

          if (trans.coupon_id) {
            const coupon = await Coupon.where({id: trans.coupon_id}).fetch();
            if (coupon) {
              total_coupon_discount = coupon.get("discount_amount");
              original_price = trans.amount_ex_vat + couponAmount;
            }
          }

          const promise = await knex('transactions')
          .where('id', '=', trans.id)
          .update({
            plan_price: original_price,
            discount: total_coupon_discount
          }).catch(function(error){
            console.log(error)
          }).then(function(){
            console.log('Added data to transaction record');
          })
        })
      })

      return return_value;
    })
};

exports.down = function (knex) {
  return knex.schema.table('transactions', (table) => {
    table.dropColumn('plan_price');
    table.dropColumn('discount');
  });
};

Update2: @Rich Churcher的答案中建议的迁移语法使迁移得以完成。但是有关MigrationLock的错误消息仍然存在。 Here讨论了类似的问题。建议从migration_table中删除锁,但是即使完全清空该表也对我没有影响。

所以我在DEBUG=knex:*中添加了variables.env,因为该网站也建议这样做。然后,当我对最新迁移进行回滚时,将获得以下输出。任何想法可能导致错误的原因以及如何解决此问题?

Using environment: development
  knex:client acquired connection from pool: __knexUid1 +0ms
  knex:query select * from information_schema.tables where table_name = ? and table_schema = database() undefined +0ms
  knex:bindings [ 'migrations' ] undefined +0ms
  knex:client releasing connection to pool: __knexUid1 +18ms
  knex:client acquired connection from pool: __knexUid1 +1ms
  knex:query select * from information_schema.tables where table_name = ? and table_schema = database() undefined +17ms
  knex:bindings [ 'migrations_lock' ] undefined +17ms
  knex:client releasing connection to pool: __knexUid1 +4ms  
  knex:client acquired connection from pool: __knexUid1 +10ms
  knex:query select * from `migrations_lock` undefined +16ms 
  knex:bindings [] undefined +17ms
  knex:client releasing connection to pool: __knexUid1 +5ms  
  knex:client acquired connection from pool: __knexUid1 +2ms
  knex:query select `name` from `migrations` order by `id` asc undefined +13ms
  knex:bindings [] undefined +14ms
  knex:client releasing connection to pool: __knexUid1 +13ms
  knex:client acquired connection from pool: __knexUid1 +26ms
  knex:query select * from `migrations` where `batch` = (select max(`batch`) from `migrations`) order by `id` desc undefined +33ms
  knex:bindings [] undefined +32ms
  knex:client releasing connection to pool: __knexUid1 +7ms
  knex:tx trx2: Starting top level transaction +0ms
  knex:client acquired connection from pool: __knexUid1 +10ms
  knex:query BEGIN; trx2 +34ms
  knex:bindings undefined trx2 +35ms
  knex:query update `migrations_lock` set `is_locked` = ? where `is_locked` = ? trx2 +7ms
  knex:bindings [ 1, 0 ] trx2 +17ms
  knex:query COMMIT; trx2 +20ms
  knex:bindings undefined trx2 +27ms
  knex:tx trx2: releasing connection +95ms
  knex:client releasing connection to pool: __knexUid1 +138ms
  knex:client acquired connection from pool: __knexUid1 +409ms
  knex:query select max(`batch`) as `max_batch` from `migrations` trx2 +509ms
  knex:bindings [] trx2 +490ms
  knex:client releasing connection to pool: __knexUid1 +28ms
  knex:tx trx3: Starting top level transaction +500ms
  knex:client acquired connection from pool: __knexUid1 +18ms
  knex:query BEGIN; trx3 +60ms
  knex:bindings undefined trx3 +64ms
  knex:client acquired connection from pool: __knexUid4 +42ms
  knex:query select * from information_schema.tables where table_name = ? and table_schema = database() undefined +57ms
  knex:bindings [ 'migrations' ] undefined +54ms
  knex:query alter table `transactions` drop `plan_price` trx3 +13ms
  knex:bindings [] trx3 +17ms
  knex:client releasing connection to pool: __knexUid4 +82ms
  knex:client acquired connection from pool: __knexUid4 +1ms
  knex:query select * from information_schema.tables where table_name = ? and table_schema = database() undefined +33ms
  knex:bindings [ 'migrations_lock' ] undefined +28ms
  knex:client releasing connection to pool: __knexUid4 +4ms
  knex:client acquired connection from pool: __knexUid4 +34ms
  knex:query select * from `migrations_lock` undefined +42ms
  knex:bindings [] undefined +68ms
  knex:client releasing connection to pool: __knexUid4 +33ms
  knex:client acquired connection from pool: __knexUid4 +3ms
  knex:query select `name` from `migrations` order by `id` asc undefined +60ms
  knex:bindings [] undefined +34ms
  knex:client releasing connection to pool: __knexUid4 +31ms
  knex:tx trx5: Starting top level transaction +240ms
  knex:client acquired connection from pool: __knexUid4 +30ms
  knex:query BEGIN; trx5 +33ms
  knex:bindings undefined trx5 +33ms
  knex:query update `migrations_lock` set `is_locked` = ? where `is_locked` = ? trx5 +3ms
  knex:bindings [ 1, 0 ] trx5 +19ms
Can't take lock to run migrations: Migration table is already locked
If you are sure migrations are not running you can release the lock manually by deleting all the rows = require(migrations lock table: migrations_lock
  knex:query ROLLBACK trx5 +79ms
  knex:bindings undefined trx5 +63ms
  knex:tx trx5: releasing connection +110ms
  knex:client releasing connection to pool: __knexUid4 +86ms
Unhandled rejection MigrationLocked: Migration table is already locked
    (No stack trace)
From previous event:
    at Migrator._getLock (C:Usersxxx
ode_modulesknexlibmigrateMigrator.js:328:13)
    at Migrator._runBatch (C:Usersxxx
ode_modulesknexlibmigrateMigrator.js:343:12)
    at knex.transaction (C:Usersxxx
ode_modulesknexlibmigrateMigrator.js:92:25)
    at init.then.then (C:Usersxxx
ode_modulesknexlib	ransaction.js:91:24)
    at runCallback (timers.js:705:18)
    at tryOnImmediate (timers.js:676:5)
    at processImmediate (timers.js:658:5)
From previous event:
    at Transaction._promise.Bluebird.using (C:Usersxxx
ode_modulesknexlib	ransaction.js:77:12)
    at runCallback (timers.js:705:18)
From previous event:
    at new Transaction (C:Usersxxx
ode_modulesknexlib	ransaction.js:57:30)
    at new Transaction_mysql (C:Usersxxx
ode_modulesknexlibdialectsmysql	ransaction.js:7:1)
    at Client_MySQL.transaction (C:Usersxxx
ode_modulesknexlibdialectsmysqlindex.js:52:12)
    at Function.transaction (C:Usersxxx
ode_modulesknexlibutilmake-knex.js:40:31)
    at migrationListResolver.listAllAndCompleted.then.then (C:Usersxxx
ode_modulesknexlibmigrateMigrator.js:91:28)
From previous event:
    at Migrator.latest (C:Usersxxx
ode_modulesknexlibmigrateMigrator.js:72:8)
    at Object.<anonymous> (C:Usersxxxdbindex.js:9:14)
    at Module._compile (internal/modules/cjs/loader.js:701:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)
    at Module.load (internal/modules/cjs/loader.js:600:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:539:12)
    at Function.Module._load (internal/modules/cjs/loader.js:531:3)
    at Module.require (internal/modules/cjs/loader.js:637:17)
    at require (internal/modules/cjs/helpers.js:22:18)
    at Object.<anonymous> (C:Usersxxxmodelscoupon.js:1:81)
    at Module._compile (internal/modules/cjs/loader.js:701:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)
    at Module.load (internal/modules/cjs/loader.js:600:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:539:12)
    at Function.Module._load (internal/modules/cjs/loader.js:531:3)
    at Module.require (internal/modules/cjs/loader.js:637:17)
    at require (internal/modules/cjs/helpers.js:22:18)
    at Object.<anonymous> (C:Usersxxxdbmigrations20200105152452_add_plan_price_and_discount_to_transactions.js:1:78)
    at Module._compile (internal/modules/cjs/loader.js:701:30)
From previous event:
    at Migrator._runBatch (C:Usersxxx
ode_modulesknexlibmigrateMigrator.js:363:10)
    at migrationListResolver.listAllAndCompleted.then.then.then (C:Usersxxx
ode_modulesknexlibmigrateMigrator.js:193:23)      
    at runCallback (timers.js:705:18)
    at tryOnImmediate (timers.js:676:5)
    at processImmediate (timers.js:658:5)
From previous event:
    at Promise (C:Usersxxx
ode_modulesknexlibmigrateMigrator.js:192:10)
    at new Promise (<anonymous>)
    at Migrator.rollback (C:Usersxxx
ode_modulesknexlibmigrateMigrator.js:167:12)
    at Command.commander.command.description.option.option.action (C:UsersxxxAppDataRoaming
pm
ode_modulesknexincli.js:231:18)
    at Command.listener (C:UsersxxxAppDataRoaming
pm
ode_modulesknex
ode_modulescommanderindex.js:360:8)
    at Command.emit (events.js:189:13)
    at Command.parseArgs (C:UsersxxxAppDataRoaming
pm
ode_modulesknex
ode_modulescommanderindex.js:799:12)
    at Command.parse (C:UsersxxxAppDataRoaming
pm
ode_modulesknex
ode_modulescommanderindex.js:563:21)
    at Liftoff.invoke (C:UsersxxxAppDataRoaming
pm
ode_modulesknexincli.js:344:13)
    at Liftoff.execute (C:UsersxxxAppDataRoaming
pm
ode_modulesknex
ode_modulesliftoffindex.js:201:12)
    at module.exports (C:UsersxxxAppDataRoaming
pm
ode_modulesknex
ode_modulesflagged-respawnindex.js:51:3)
    at Liftoff.<anonymous> (C:UsersxxxAppDataRoaming
pm
ode_modulesknex
ode_modulesliftoffindex.js:191:5)
    at C:UsersxxxAppDataRoaming
pm
ode_modulesknex
ode_modulesliftoffindex.js:149:9
    at C:UsersxxxAppDataRoaming
pm
ode_modulesknex
ode_modulesv8flagsindex.js:138:14
    at C:UsersxxxAppDataRoaming
pm
ode_modulesknex
ode_modulesv8flagsindex.js:41:14
    at C:UsersxxxAppDataRoaming
pm
ode_modulesknex
ode_modulesv8flagsindex.js:53:7
    at process._tickCallback (internal/process/next_tick.js:61:11)

  knex:query alter table `transactions` drop `discount` trx3 +382ms
  knex:bindings [] trx3 +383ms
  knex:query COMMIT; trx3 +391ms
  knex:bindings undefined trx3 +391ms
  knex:tx trx3: releasing connection +777ms
  knex:client releasing connection to pool: __knexUid1 +803ms
  knex:client acquired connection from pool: __knexUid1 +26ms
  knex:query delete from `migrations` where `name` = ? trx3 +60ms
  knex:bindings [ '20200105152452_add_plan_price_and_discount_to_transactions.js' ] trx3 +59ms
  knex:client releasing connection to pool: __knexUid1 +17ms
  knex:client acquired connection from pool: __knexUid1 +17ms
  knex:query update `migrations_lock` set `is_locked` = ? trx3 +34ms
  knex:bindings [ 0 ] trx3 +34ms
  knex:client releasing connection to pool: __knexUid1 +18ms

[knex -V返回:“ Knex CLI版本:0.20.2”和“ Knex本地版本:0.20.3”。

答案

Knex不再采用第二个Promise参数,因为它转而使用了一段时间的本机Promise。因此,Promise在您的迁移中是undefined,因此绝对没有.resolve属性。

有人认为返回Promise.resolve().then绝对是个好主意,这很奇怪。您要执行的是模式修改,然后是数据修改。看起来像这样:

return knex.schema.table("transactions", t => {
  t.decimal('plan_price', 10, 2);
  // etc
})
  .then(() =>
    knex("transactions")
      .then(
        // Update values here
      );
  )
  .catch(console.error)

此外,您发现for_each并不总是非常适合异步工作。但是,我们仍然可以通过编写更复杂的查询(加入其他表格以获取我们想要的值)或通过修改当前表格以更好地与承诺:

exports.up = knex =>
  knex.schema
    .table("transactions", t => {
      t.decimal("plan_price", 10, 2);
      t.decimal("discount", 10, 2).defaultTo(0);
    })
    .then(() => {
      return knex("transactions").then(async transactions => {
        for (let trans of transactions) {
          let original_price;
          let total_coupon_discount = 0;

          const plan = await Plan.where({ id: trans.plan_id }).fetch();
          if (plan) {
            original_price = plan.get("price");
          }

          if (trans.coupon_id) {
            const coupon = await Coupon.where({ id: trans.coupon_id }).fetch();
            if (coupon) {
              total_coupon_discount = coupon.get("discount_amount");
              original_price = trans.amount_ex_vat + couponAmount;
            }
          }

          await knex("transactions")
            .where("id", "=", trans.id)
            .update({
              plan_price: original_price,
              discount: total_coupon_discount
            });
        }
      });
    });

我显然不能说出其他代码的正确性(在我看来像书架吗?),因为我没有您的架构,但这是总体思路。基本上,当你想使用async/ awaitfor... of搭配使用,可以使所有内容保持良好顺序。

[我认为值得注意的是,这种方法在大桌子上可能会比较慢,因为有三个transactions的每行单独的阻止查询。

以上是关于Knex迁移:交易查询已完成的主要内容,如果未能解决你的问题,请参考以下文章

Knex - 已经是最新的

Knex:使用 FOREIGN KEY 创建迁移

时光簿SKM代码库迁移到GitHub(已完成第一阶段的20%)

在knex迁移中更新枚举列类型

Knex.js 迁移问题:因`关系“knex_migrations”不存在而失败`

javascript knex交易