https://itbilu.com/nodejs/npm/NJ5VAqfYZ.html
Sequelize 中事务的使用-启动、提交、回滚
数据库中的事务是指单个逻辑所包含的一系列数据操作,要么全部执行,要么全部不执行。在一个事务中,可能会包含开始(START)、提交(COMMIT)、回滚(ROLLBACK)等操作,Sequelize 通过Transaction类来实现事务相关功能。Sequelize 中的事务有两种使用:可以基于Promise结果链进行自动提交或回滚,也可以由用户控制提交或回滚。
- Transaction类的构造函数
- 实例化
- 事务控制
- sequelize - 一个已配置的 Sequlize 实例
- options是一个包含以下可选值的对象:
- autocommit - Boolean,是否自动提交
- type - String,事务类型
- isolationLevel - String,事务的隔离级别
- autocommit - String,立即或延迟检查约束
2. 实例化
虽然Transaction类可以直接访问(通过require(‘sequelize’).Transaction或sequelize.Transaction),但一般不需要直接实例化。
其创建对象(实例化)可以使用Sequlize实例的sequelize.transaction()方法,创建Transaction对象后,被创建的对象回调到then回调链中。
如,创建一个事务并在其中执行一些操作: ```javascript var Sequelize = require(‘sequelize’);
var sequelize = new Sequelize(‘modelTest’, ‘root’, ‘111111’, {host: ‘localhost’, port:3306, logging:console.log}); var User = sequelize.import(‘./user.js’); var UserCheckin = sequelize.import(‘./userCheckin.js’);
// 创建事务 sequelize.transaction(function (t) { // 在事务中执行操作 return User.create({username: ‘itbilu.com’, password: ‘pwd’, active: true}, {transaction:t}) .then(function(user){ return UserCheckin.create({userId: user.id, loginIp:’localhost’}, {transaction:t}) }); }).then(function (results){ / 操作成功,事务会自动提交 / }).catch(function(err){ / 操作失败,事件会自动回滚 / });
以上示例执行结果类似如下:
```javascript
Executing (3e756dc6-4f73-40f6-aa1c-d21ae832a302): START TRANSACTION;
Executing (3e756dc6-4f73-40f6-aa1c-d21ae832a302): SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
Executing (3e756dc6-4f73-40f6-aa1c-d21ae832a302): SET autocommit = 1;
Executing (3e756dc6-4f73-40f6-aa1c-d21ae832a302): INSERT INTO `user` (`id`,`username`,`password`,`active`,`created_at`,`updated_at`) VALUES (DEFAULT,'itbilu.com','pwd',true,'2016-08-09 09:34:46','2016-08-09 09:34:46');
Executing (3e756dc6-4f73-40f6-aa1c-d21ae832a302): INSERT INTO `userCheckin` (`id`,`user_id`,`login_ip`,`created_at`,`updated_at`) VALUES (DEFAULT,2,'127.0.0.1','2016-08-09 09:34:46','2016-08-09 09:34:46');
Executing (3e756dc6-4f73-40f6-aa1c-d21ae832a302): COMMIT;
3. 事务控制
一个事务实例(创建事务对象)就表示一个正在执行事务,即:启动一个事务。Sequelize 中的事务可以基于Promise结果链进行自动提交或回滚。也可以由用户控制,通过调用事务实例的commit()或rollback()来手工提交或回滚。
在一个关系型数据库的事务中,可能会包含开始(START)、提交(COMMIT)、回滚(ROLLBACK)等操作三个操作。Sequelize中同样会有这三种操作,创建一个Transaction类实例就是“开始”一个事务。事务启动后,对于受管理的事务(auto-callback)可以基于Promise回调链由Sequelize自动“提交”或“回滚”事务;而对于不受管理的事务(then-callback),我们可以手工调用commit()方法来“提交”事务,或调用rollback()来“回滚”事务。
3.1 受管理事务的提交与回滚
在使用sequelize.transaction()创建类实列时(启动事务),可以向其传递一个回调函数。通过这种方式创建的事务,是受管理的事务:
// 启动一个受管理的事务
return sequelize.transaction(function (t) {
// 一些在事务中进行的操作
}).then(function (result) {
// Transaction 会自动提交
// result 是事务回调中使用promise链中执行结果
}).catch(function (err) {
// Transaction 会自动回滚
// err 是事务回调中使用promise链中的异常结果
});
创建受管理事务后,传递给回调函数的transaction会返回一个promise链,在promise返回的then或catch方法中,并不能调用t.commit()或t.rollback()来控制事务。在这种方式下,如果使用事务的所有promise链都执行成功,则自动提交;如果其中之一执行失败(即:catch()方法被调用),则自动回滚。
注意:也不建议回调函数内部调t.commit()或t.rollback()提交或回滚事务,这样会造成阻塞。
强制回调
虽然不能在promise返回的then或catch方法中手工提交或回滚方法,但可以基于promise通过抛出异常来强制回滚事务:
return sequelize.transaction(function (t) {
return User.create({
firstName: 'Abraham',
lastName: 'Lincoln'
}, {transaction: t}).then(function (user) {
// 注意,虽然所有操作成功但仍会回滚
throw new Error();
});
});
3.2 不受管理事务的提交与回滚
如果调用sequelize.transaction()创建事务实例时不传入回调函数,会启动一个不受管理事务。不受管理的事务需要你强制(手工)提交或回滚,如果不进行这些操作,事务会一直保持挂起状态直到超时。
不受管理的事务对象会被传递至then方法的回调函数中,在这里我们可以通过调用t.commit()或t.rollback()提交或回滚事务:
// 启动一个不受管理的事务
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();
});
});