try...catch
區塊:
try {
} catch (err) {
// 處理錯誤
res.status(500).json({ errors: err })
throw err;
}
1.try
區塊:2.catch
區塊:try {
await transactionHandler(this.knexSql)
}
:
const execTransaction = async (): Promise<T> => {
const trx = await knex.transaction();
try {
if (isolation) await trx.raw(`SET TRANSACTION ISOLATION LEVEL SERIALIZABLE`)
const result = await callback(trx);
await trx.commit();
return result;
} catch (err: any) {
await trx.rollback();
if (err.code !== '1205') throw err;
if (attempts > retryTimes) throw Error('[Transaction] retry times is up to max');
attempts++;
await sleep(maxBackOff);
return execTransaction();
}
};
//新增 執行execTransaction的結果
return await execTransaction();
:
1.transactionHandler
函數:這個函數是用來處理整個交易邏輯的框架。它設置了重試機制和異常處理,確保在交易過程中任何操作失敗時能夠進行重試。
2.execTransaction
:這個內部函數實際上執行了交易操作,包括開始交易、執行回調函數、提交或回滾交易。
3.return await execTransaction();
:transactionHandler
的最後,確保呼叫 execTransaction
並等待其完成,然後將結果返回給調用者。transactionHandler
使用execTransaction
來實際執行交易操作。transactionHandler
則作為外部接口,調用和管理 execTransaction
的執行。await
來處理非同步操作:
try {
await transactionHandler(this.knexSql, async (trx: Knex.Transaction)
)}
:
try {
await transactionHandler(this.knexSql, async (trx: Knex.Transaction) => {
//對裡面每一個項目product做寫入database動作
contents.map(product) => this.productModel.
}
)}
productModel.preSell
方法:
productModel:
/production的型別和定義-新增(對伺服器來說是做預售的動作)
export interface IProductModel extends IBase<Product> {
preSell(product: Pick<Product, "id" | "amount" | "price">, trx?: Knex.Transaction)
: Promise<Boolean>;
}
IProductModel:
IBase<Product>
:preSell
方法,用於處理預售檢查:參數 trx
(可選):
:
public preSell = async
(product: Pick<Product, "id" | "amount" | "price">, trx?: Knex.Transaction)
=> {
//從資料庫裡面找資料
let queryBuilder = this.knexSql(this.tableName)
.where({ id: product.id })
.where(this.schema.amount, '>=', product.amount)
.update(
this.schema.preOrder,
this.knexSql.raw(`?? + ?`, [this.schema.preOrder, product.amount])
);
if (trx) queryBuilder = queryBuilder.transacting(trx);
const result = await queryBuilder;
//成功update就會是大於一的數字
return !!result;
}
let queryBuilder = this.knexSql(this.tableName)
.where({ id: product.id })
.where(this.schema.amount, '>=', product.amount)
.update(
this.schema.preOrder,
this.knexSql.raw(`?? + ?`, [this.schema.preOrder, product.amount])
);
raw
是 Knex.js 提供的一個方法,用於執行原始 SQL 查詢或建構複雜的 SQL 表達式。if (trx) queryBuilder = queryBuilder.transacting(trx);
const result = await queryBuilder;
return !!result;
:
const results = await Promise.all(
//對裡面每一個項目product做寫入database動作
contents.map(
async (product) =>
await this.productModel.preSell(
{
id: product.productId,
...pick(product, ['price', 'amount'])
},
trx
)));
Promise.all
:const results = await Promise.all()
async (product) => await this.productModel.preSell()
preSell
方法:await this.productModel.preSell(
{
id: product.productId,
...pick(product, ['price', 'amount'])
},
trx
)
pick
被用來選擇 product
物件中的 price
和 amount
屬性,然後將這些屬性與 id
一起傳遞給 preSell
。results
陣列中的任意一個元素是否為 false:
if (results.some(result => !result))
throw new Error('Cannot buy, because out of stuff.');
contents
陣列中所有產品的總價格:
const totalPrice = contents.reduce()
(acc, product) => acc + product.price * product.amount
0
:, 0
export const genUID = () => {
// timestamp 13+7 = 20
const alpha = 'abcdefghij'//每個數字去轉換成英文的大小寫
const timestampStr = new Date().getTime().toString();
const code = timestampStr.split('') //['1', '2', '3',...]
.map((v, idx) => idx % 2 ? v : alpha[Number(v)]) //['1', 'b', '3',...]
.join('')
const id = uuid().split('-')[0];
return `${code}${id.substring(0, id.length - 1)}`;
}
const alpha = 'abcdefghij';// 每個數字對應的字母
const timestampStr = new Date().getTime().toString();
const code = timestampStr.split('')
.map((v, idx) => idx % 2 ? v : alpha[Number(v)])
.join('');
npm install uid
const id = uuid().split('-')[0];
uuid()
方法生成一個新的 UUID。const uid = genUID();
const orderData = {
id: uid,
total: totalPrice,
createdAt: new Date(),
updatedAt: new Date(),
paymentProvider,
paymentWay,
status: OrderStatus.WAITING,
contents,
};
// 傳遞 orderData 並包括 trx
await this.orderModel.create(orderData, trx);
res.json({ status: 'success' })
uid
:const uid = genUID();
orderData
:const orderData = {
id: uid,
total: totalPrice,
createdAt: new Date(),
updatedAt: new Date(),
paymentProvider,
paymentWay,
status: OrderStatus.WAITING,
contents,
};
await this.orderModel.create(orderData, trx);
res.json({ status: 'success' });