對(duì)數(shù)據(jù)庫(kù)的操作很多時(shí)候需要同時(shí)進(jìn)行幾個(gè)操作,比如需要同時(shí)改動(dòng)幾張表的數(shù)據(jù),或者對(duì)同一張表中不同行(row)或列(column)做不同操作,比較典型的例子就是用戶轉(zhuǎn)賬問(wèn)題(A賬戶向B賬號(hào)匯錢(qián)):
1 從A賬號(hào)中把余額讀出來(lái)。
2 對(duì)A賬號(hào)做減法操作。
3 把結(jié)果寫(xiě)回A賬號(hào)中。
4 從B賬號(hào)中把余額讀出來(lái)。
5 對(duì)B賬號(hào)做加法操作。
6 把結(jié)果寫(xiě)回B賬號(hào)中。
為了數(shù)據(jù)的一致性,這6件事,要么操作全部成功,要么全部失敗回滾。這就是事務(wù)的一個(gè)特性:原子性。關(guān)于事務(wù)的四大特性(ACID)這里不做深究。
項(xiàng)目使用的是 Egg+egg-sequelize 模式,查閱了一下 sequelize 的官方文檔,使用方法如下:
// 受管理的事務(wù)(auto-callback)
return sequelize.transaction(function (t) {
// 要確保所有的查詢鏈都有return返回
return User.create({
firstName: 'Abraham',
lastName: 'Lincoln'
}, {transaction: t}).then(function (user) {
return user.setShooter({
firstName: 'John',
lastName: 'Boothe'
}, {transaction: t});
});
}).then(function (result) {
// Transaction 會(huì)自動(dòng)提交
// result 是事務(wù)回調(diào)中使用promise鏈中執(zhí)行結(jié)果
}).catch(function (err) {
// Transaction 會(huì)自動(dòng)回滾
// err 是事務(wù)回調(diào)中使用promise鏈中的異常結(jié)果
});
// 不受管理的事務(wù)(then-callback)
return sequelize.transaction().then(function (t) {
return User.create({
firstName: 'Homer',
lastName: 'Simpson'
}, {transaction: t}).then(function (user) {
return user.addSibling({
firstName: 'Lisa',
lastName: 'Simpson'
}, {transaction: t});
}).then(function () {
return t.commit();
}).catch(function (err) {
return t.rollback();
});
});
使用 ES6 的語(yǔ)法如下:
let transaction;
try {
transaction = await this.ctx.model.transaction();
await this.service.xxx.xxx(parms, transaction);
await this.service.xxx.xxx(parms1, parms2, transaction);
await transaction.commit();
return true
} catch (e) {
await transaction.rollback();
return false
}