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

Commit 7b163084 by joshuacullen Committed by Sushant

feat(postgres): skip locked support (#9197)

1 parent 2752bf7a
...@@ -261,5 +261,26 @@ model.afterSave((instance, options) => { ...@@ -261,5 +261,26 @@ model.afterSave((instance, options) => {
} }
// Save done outside a transaction, safe for callers to fetch the updated model // Save done outside a transaction, safe for callers to fetch the updated model
// Notify // Notify
## Locks
Queries within a `transaction` can be performed with locks
```
return User.findAll({
limit: 1,
lock: true,
transaction: t1
})
```
Queries within a transaction can skip locked rows
```
return User.findAll({
limit: 1,
lock: true,
skipLocked: true,
transaction: t2
}) })
``` ```
...@@ -1327,6 +1327,9 @@ class QueryGenerator { ...@@ -1327,6 +1327,9 @@ class QueryGenerator {
if (this._dialect.supports.lockOf && options.lock.of && options.lock.of.prototype instanceof Model) { if (this._dialect.supports.lockOf && options.lock.of && options.lock.of.prototype instanceof Model) {
query += ' OF ' + this.quoteTable(options.lock.of.name); query += ' OF ' + this.quoteTable(options.lock.of.name);
} }
if (this._dialect.supports.skipLocked && options.skipLocked) {
query += ' SKIP LOCKED';
}
} }
return `${query};`; return `${query};`;
......
...@@ -33,6 +33,7 @@ PostgresDialect.prototype.supports = _.merge(_.cloneDeep(AbstractDialect.prototy ...@@ -33,6 +33,7 @@ PostgresDialect.prototype.supports = _.merge(_.cloneDeep(AbstractDialect.prototy
lockOf: true, lockOf: true,
lockKey: true, lockKey: true,
lockOuterJoinFailure: true, lockOuterJoinFailure: true,
skipLocked: true,
forShare: 'FOR SHARE', forShare: 'FOR SHARE',
index: { index: {
concurrently: true, concurrently: true,
......
...@@ -290,6 +290,19 @@ class Transaction { ...@@ -290,6 +290,19 @@ class Transaction {
* ``` * ```
* UserModel will be locked but TaskModel won't! * UserModel will be locked but TaskModel won't!
* *
* You can also skip locked rows:
*
*```js
* t1 // is a transaction
* Model.findAll({
* where: ...,
* transaction: t1,
* lock: true,
* skipLocked: true
* });
* ```
* The query will now return any rows that aren't locked by another transaction
*
* @return {Object} * @return {Object}
* @property UPDATE * @property UPDATE
* @property SHARE * @property SHARE
......
...@@ -528,6 +528,50 @@ if (current.dialect.supports.transactions) { ...@@ -528,6 +528,50 @@ if (current.dialect.supports.transactions) {
}); });
}); });
if (current.dialect.supports.skipLocked) {
it('supports for update with skip locked', function() {
const User = this.sequelize.define('user', {
username: Support.Sequelize.STRING,
awesome: Support.Sequelize.BOOLEAN
});
return this.sequelize.sync({ force: true }).then(() => {
return Promise.all([
User.create(
{ username: 'jan'}
),
User.create(
{ username: 'joe'}
)
]);
}).then(() => {
return this.sequelize.transaction().then(t1 => {
return User.findAll({
limit: 1,
lock: true,
transaction: t1
}).then(results => {
const firstUserId = results[0].id;
return this.sequelize.transaction().then(t2 => {
return User.findAll({
limit: 1,
lock: true,
skipLocked: true,
transaction: t2
}).then(secondResults => {
expect(secondResults[0].id).to.not.equal(firstUserId);
return Promise.all([
t1.commit(),
t2.commit()
]);
});
});
});
});
});
});
}
it('fail locking with outer joins', function() { it('fail locking with outer joins', function() {
const User = this.sequelize.define('User', { username: Support.Sequelize.STRING }), const User = this.sequelize.define('User', { username: Support.Sequelize.STRING }),
Task = this.sequelize.define('Task', { title: Support.Sequelize.STRING, active: Support.Sequelize.BOOLEAN }), Task = this.sequelize.define('Task', { title: Support.Sequelize.STRING, active: Support.Sequelize.BOOLEAN }),
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!