Transaction issue with knexjs, typescript and mariadb

房东的猫 提交于 2020-11-29 02:08:31

问题


I want to have a transaction, in typescript, to refresh some data in a table. To do so the following steps need to apply:

  1. Truncate all the records from a table
  2. Set the AUTO_INCREMENT to 1
  3. Insert the new records in the table

If something goes wrong I would like to rollback the transaction and not alter the existing records in the db table.

I have tried different things but I think I am missing something and I wish someone can spot what I am doing wrong.

1st Attempt

await knex.transaction(async (trx) => {
  await knex(tableName).truncate().transacting(trx);
  await knex.raw(`ALTER TABLE ${tableName} AUTO_INCREMENT=1;`).transacting(trx);
  await knex(tableName).insert(data).transacting(trx);
  await trx.commit();
});

2nd Attempt

await knex.transaction(async (trx) => {
  try {
    await knex(table).truncate().transacting(trx);
    await knex.raw(`ALTER TABLE ${table} AUTO_INCREMENT=1;`).transacting(trx);
    await knex(table).insert(data).transacting(trx);
    await trx.commit();
  } catch (e) {
    await trx.rollback();
  }
});

3rd Attempt

const promisify = (fn: any) => new Promise((resolve, reject) => fn(resolve));
const trx: knex.Transaction  = <knex.Transaction> await promisify(this.knex.transaction);
try {
  await this.knex(this.table).truncate().transacting(trx);
  await this.knex.raw(`ALTER TABLE ${this.table} AUTO_INCREMENT=1;`).transacting(trx);
  await this.knex(this.table).insert(data).transacting(trx);
  await trx.commit();
  return Promise.resolve(data);
} catch (e) {
  await trx.rollback();
  return Promise.reject(e);
}

Any idea would be really useful.


回答1:


With mysql all schema altering DDL queries does implicit commit and they cannot be rolled back. So you need to change your implementation to guarantee integrity of db in some other way.

https://dev.mysql.com/doc/refman/8.0/en/cannot-roll-back.html https://dev.mysql.com/doc/refman/8.0/en/implicit-commit.html




回答2:


Don't do it that way. Instead:

CREATE TABLE new LIKE real;
populate `new`
RENAME TABLE real TO old, new TO real;
DROP TABLE old;

If the CREATE or populate fail, then abandon the task; no harm done. (Well, need to DROP TABLE real.)

The RENAME TABLE is very fast, and atomic, and unlikely to fail.

This approach has the advantage that, to other queries, the real table is available and fully populated the entire time.



来源:https://stackoverflow.com/questions/54179669/transaction-issue-with-knexjs-typescript-and-mariadb

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!