不要怂,就是干,撸起袖子干!

Added check to prevent multiple commit/rollback on a single transaction

when not using CLS #4491.
Added rollback to prepareEnvironment to abort half-initialized
transactions that run into error, fixes connection pool exhaust bug #4491.
1 parent 2bfa312f
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
- [ADDED] beforeRestore/afterRestore hooks [#4371](https://github.com/sequelize/sequelize/issues/4371) - [ADDED] beforeRestore/afterRestore hooks [#4371](https://github.com/sequelize/sequelize/issues/4371)
- [INTERNALS] `options` has been renamed to `$options` in instance.js [#4429](https://github.com/sequelize/sequelize/pull/4429) - [INTERNALS] `options` has been renamed to `$options` in instance.js [#4429](https://github.com/sequelize/sequelize/pull/4429)
- [FIXED] Reload doesn't synchronize a null include [#4353](https://github.com/sequelize/sequelize/issues/4353) - [FIXED] Reload doesn't synchronize a null include [#4353](https://github.com/sequelize/sequelize/issues/4353)
- [FIXED] commit/rollback multiple times on same transaction [#4491](https://github.com/sequelize/sequelize/issues/4491)
# 3.8.0 # 3.8.0
- [ADDED] `version` on `Sequelize` returning the current npm/package.json version [#4459](https://github.com/sequelize/sequelize/pull/4459) - [ADDED] `version` on `Sequelize` returning the current npm/package.json version [#4459](https://github.com/sequelize/sequelize/pull/4459)
......
...@@ -127,6 +127,10 @@ Transaction.LOCK = Transaction.prototype.LOCK = { ...@@ -127,6 +127,10 @@ Transaction.LOCK = Transaction.prototype.LOCK = {
Transaction.prototype.commit = function() { Transaction.prototype.commit = function() {
var self = this; var self = this;
if (this.finished) {
throw new Error('Transaction cannot be committed because it has been finished with state: ' + self.finished);
}
this.$clearCls(); this.$clearCls();
return this return this
...@@ -150,6 +154,10 @@ Transaction.prototype.commit = function() { ...@@ -150,6 +154,10 @@ Transaction.prototype.commit = function() {
Transaction.prototype.rollback = function() { Transaction.prototype.rollback = function() {
var self = this; var self = this;
if (this.finished) {
throw new Error('Transaction cannot be rolled back because it has been finished with state: ' + self.finished);
}
this.$clearCls(); this.$clearCls();
return this return this
...@@ -180,6 +188,10 @@ Transaction.prototype.prepareEnvironment = function() { ...@@ -180,6 +188,10 @@ Transaction.prototype.prepareEnvironment = function() {
return self.setIsolationLevel(); return self.setIsolationLevel();
}).then(function () { }).then(function () {
return self.setAutocommit(); return self.setAutocommit();
}).catch(function (setupErr) {
return self.rollback().finally(function () {
throw setupErr;
});
}).tap(function () { }).tap(function () {
if (self.sequelize.constructor.cls) { if (self.sequelize.constructor.cls) {
self.sequelize.constructor.cls.set('transaction', self); self.sequelize.constructor.cls.set('transaction', self);
......
...@@ -134,6 +134,42 @@ describe(Support.getTestDialectTeaser('Transaction'), function() { ...@@ -134,6 +134,42 @@ describe(Support.getTestDialectTeaser('Transaction'), function() {
).to.eventually.be.rejected; ).to.eventually.be.rejected;
}); });
it('does not allow commits after commit', function () {
var self = this;
return expect(self.sequelize.transaction().then(function (t) {
return t.commit().then(function () {
return t.commit();
});
})).to.be.rejectedWith('Error: Transaction cannot be committed because it has been finished with state: commit');
});
it('does not allow commits after rollback', function () {
var self = this;
return expect(self.sequelize.transaction().then(function (t) {
return t.rollback().then(function () {
return t.commit();
});
})).to.be.rejectedWith('Error: Transaction cannot be committed because it has been finished with state: rollback');
});
it('does not allow rollbacks after commit', function () {
var self = this;
return expect(self.sequelize.transaction().then(function (t) {
return t.commit().then(function () {
return t.rollback();
});
})).to.be.rejectedWith('Error: Transaction cannot be rolled back because it has been finished with state: commit');
});
it('does not allow rollbacks after rollback', function () {
var self = this;
return expect(self.sequelize.transaction().then(function (t) {
return t.rollback().then(function () {
return t.rollback();
});
})).to.be.rejectedWith('Error: Transaction cannot be rolled back because it has been finished with state: rollback');
});
if (dialect === 'sqlite'){ if (dialect === 'sqlite'){
it('provides persistent transactions', function () { it('provides persistent transactions', function () {
var sequelize = new Support.Sequelize('database', 'username', 'password', {dialect: 'sqlite'}) var sequelize = new Support.Sequelize('database', 'username', 'password', {dialect: 'sqlite'})
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!