diff --git a/ebean-api/src/main/java/io/ebean/ExpressionList.java b/ebean-api/src/main/java/io/ebean/ExpressionList.java index 5ac3d7de8..33cf9efcb 100644 --- a/ebean-api/src/main/java/io/ebean/ExpressionList.java +++ b/ebean-api/src/main/java/io/ebean/ExpressionList.java @@ -169,14 +169,38 @@ public interface ExpressionList { */ UpdateQuery asUpdate(); + /** + * Execute the query with the given lock type and WAIT. + *

+ * Note that forUpdate() is the same as + * withLock(LockType.UPDATE). + *

+ * Provides us with the ability to explicitly use Postgres + * SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks. + */ + Query withLock(Query.LockType lockType); + + /** + * Execute the query with the given lock type and lock wait. + *

+ * Note that forUpdateNoWait() is the same as + * withLock(LockType.UPDATE, LockWait.NOWAIT). + *

+ * Provides us with the ability to explicitly use Postgres + * SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks. + */ + Query withLock(Query.LockType lockType, Query.LockWait lockWait); + /** * Execute using "for update" clause which results in the DB locking the record. */ Query forUpdate(); /** + * Deprecated - migrate to withLock(). * Execute using "for update" with given lock type (currently Postgres only). */ + @Deprecated Query forUpdate(Query.LockType lockType); /** @@ -188,8 +212,10 @@ public interface ExpressionList { Query forUpdateNoWait(); /** + * Deprecated - migrate to withLock(). * Execute using "for update nowait" with given lock type (currently Postgres only). */ + @Deprecated Query forUpdateNoWait(Query.LockType lockType); /** @@ -201,8 +227,10 @@ public interface ExpressionList { Query forUpdateSkipLocked(); /** + * Deprecated - migrate to withLock(). * Execute using "for update skip locked" with given lock type (currently Postgres only). */ + @Deprecated Query forUpdateSkipLocked(Query.LockType lockType); /** diff --git a/ebean-api/src/main/java/io/ebean/Query.java b/ebean-api/src/main/java/io/ebean/Query.java index 200704cfd..ab1c97122 100644 --- a/ebean-api/src/main/java/io/ebean/Query.java +++ b/ebean-api/src/main/java/io/ebean/Query.java @@ -184,7 +184,8 @@ public interface Query { */ enum LockType { /** - * The default lock type - See PlatformConfig.forUpdateNoKey option. + * The default lock type being either UPDATE or NO_KEY_UPDATE based on + * PlatformConfig.forUpdateNoKey configuration (Postgres option). */ DEFAULT, @@ -194,17 +195,17 @@ public interface Query { UPDATE, /** - * FOR NO KEY UPDATE. + * FOR NO KEY UPDATE (Postgres only). */ NO_KEY_UPDATE, /** - * FOR SHARE UPDATE. + * FOR SHARE (Postgres only). */ SHARE, /** - * FOR KEY SHARE UPDATE. + * FOR KEY SHARE (Postgres only). */ KEY_SHARE } @@ -1643,40 +1644,69 @@ public interface Query { */ String getGeneratedSql(); + /** + * Execute the query with the given lock type and WAIT. + *

+ * Note that forUpdate() is the same as + * withLock(LockType.UPDATE). + *

+ * Provides us with the ability to explicitly use Postgres + * SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks. + */ + Query withLock(LockType lockType); + + /** + * Execute the query with the given lock type and lock wait. + *

+ * Note that forUpdateNoWait() is the same as + * withLock(LockType.UPDATE, LockWait.NOWAIT). + *

+ * Provides us with the ability to explicitly use Postgres + * SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks. + */ + Query withLock(LockType lockType, LockWait lockWait); + /** * Execute using "for update" clause which results in the DB locking the record. + *

+ * The same as withLock(LockType.UPDATE, LockWait.WAIT). */ Query forUpdate(); /** * Execute using "for update" with given lock type (currently Postgres only). */ + @Deprecated Query forUpdate(LockType lockType); /** * Execute using "for update" clause with "no wait" option. *

* This is typically a Postgres and Oracle only option at this stage. - *

+ *

+ * The same as withLock(LockType.UPDATE, LockWait.NOWAIT). */ Query forUpdateNoWait(); /** * Execute using "for update nowait" with given lock type (currently Postgres only). */ + @Deprecated Query forUpdateNoWait(LockType lockType); /** * Execute using "for update" clause with "skip locked" option. *

* This is typically a Postgres and Oracle only option at this stage. - *

+ *

+ * The same as withLock(LockType.UPDATE, LockWait.SKIPLOCKED). */ Query forUpdateSkipLocked(); /** * Execute using "for update skip locked" with given lock type (currently Postgres only). */ + @Deprecated Query forUpdateSkipLocked(LockType lockType); /** diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java index 2cb12ea2a..569fb0868 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java @@ -486,6 +486,16 @@ public class DefaultExpressionList implements SpiExpressionList { return query.filterMany(manyProperty).where(expressions, params); } + @Override + public Query withLock(Query.LockType lockType) { + return query.withLock(lockType); + } + + @Override + public Query withLock(Query.LockType lockType, Query.LockWait lockWait) { + return query.withLock(lockType, lockWait); + } + @Override public Query forUpdate() { return query.forUpdate(); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java index 37dab58f9..81548b19a 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java @@ -491,6 +491,16 @@ class JunctionExpression implements SpiJunction, SpiExpression, Expression return exprList.findOneOrEmpty(); } + @Override + public Query withLock(Query.LockType lockType) { + return exprList.withLock(lockType); + } + + @Override + public Query withLock(Query.LockType lockType, Query.LockWait lockWait) { + return exprList.withLock(lockType, lockWait); + } + @Override public Query forUpdate() { return exprList.forUpdate(); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/DefaultFetchGroupQuery.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/DefaultFetchGroupQuery.java index f0fc5a923..063f2071c 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/DefaultFetchGroupQuery.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/DefaultFetchGroupQuery.java @@ -544,6 +544,16 @@ class DefaultFetchGroupQuery implements SpiFetchGroupQuery { throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup"); } + @Override + public Query withLock(LockType lockType) { + throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup"); + } + + @Override + public Query withLock(LockType lockType, LockWait lockWait) { + throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup"); + } + @Override public Query forUpdate() { throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup"); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java index a7cb9bd64..0bb1b3e45 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -963,6 +963,16 @@ public class DefaultOrmQuery implements SpiQuery { return this; } + @Override + public Query withLock(LockType lockType) { + return setForUpdateWithMode(LockWait.WAIT, lockType); + } + + @Override + public Query withLock(LockType lockType, LockWait lockWait) { + return setForUpdateWithMode(lockWait, lockType); + } + @Override public DefaultOrmQuery forUpdate() { return setForUpdateWithMode(LockWait.WAIT, LockType.DEFAULT); diff --git a/ebean-core/src/test/java/org/tests/basic/TestQueryForUpdatePostgresLock.java b/ebean-core/src/test/java/org/tests/basic/TestQueryForUpdatePostgresLock.java index 799850500..ecda6bee2 100644 --- a/ebean-core/src/test/java/org/tests/basic/TestQueryForUpdatePostgresLock.java +++ b/ebean-core/src/test/java/org/tests/basic/TestQueryForUpdatePostgresLock.java @@ -55,7 +55,7 @@ public class TestQueryForUpdatePostgresLock extends BaseTestCase { private void lockArticle(Integer id) { timePreLock = System.currentTimeMillis(); log.info("lock start"); - DB.find(Article.class).setId(id).forUpdate(NO_KEY_UPDATE).findOne(); + DB.find(Article.class).setId(id).withLock(NO_KEY_UPDATE).findOne(); sleep(1000); timePostLock = System.currentTimeMillis(); log.info("lock done"); diff --git a/ebean-querybean/src/main/java/io/ebean/typequery/TQRootBean.java b/ebean-querybean/src/main/java/io/ebean/typequery/TQRootBean.java index 5f0e20185..66858dc10 100644 --- a/ebean-querybean/src/main/java/io/ebean/typequery/TQRootBean.java +++ b/ebean-querybean/src/main/java/io/ebean/typequery/TQRootBean.java @@ -685,6 +685,34 @@ public abstract class TQRootBean { return root; } + /** + * Execute the query with the given lock type and WAIT. + *

+ * Note that forUpdate() is the same as + * withLock(LockType.UPDATE). + *

+ * Provides us with the ability to explicitly use Postgres + * SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks. + */ + R withLock(Query.LockType lockType) { + query.withLock(lockType); + return root; + } + + /** + * Execute the query with the given lock type and lock wait. + *

+ * Note that forUpdateNoWait() is the same as + * withLock(LockType.UPDATE, LockWait.NOWAIT). + *

+ * Provides us with the ability to explicitly use Postgres + * SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks. + */ + R withLock(Query.LockType lockType, Query.LockWait lockWait) { + query.withLock(lockType, lockWait); + return root; + } + /** * Execute using "for update" clause which results in the DB locking the record. */ @@ -694,8 +722,10 @@ public abstract class TQRootBean { } /** + * Deprecated - migrate to withLock(). * Execute using "for update" with given lock type (currently Postgres only). */ + @Deprecated public R forUpdate(Query.LockType lockType) { query.forUpdate(lockType); return root; @@ -712,8 +742,10 @@ public abstract class TQRootBean { } /** + * Deprecated - migrate to withLock(). * Execute using "for update nowait" with given lock type (currently Postgres only). */ + @Deprecated public R forUpdateNoWait(Query.LockType lockType) { query.forUpdateNoWait(lockType); return root; @@ -731,8 +763,10 @@ public abstract class TQRootBean { } /** + * Deprecated - migrate to withLock(). * Execute using "for update skip locked" with given lock type (currently Postgres only). */ + @Deprecated public R forUpdateSkipLocked(Query.LockType lockType) { query.forUpdateSkipLocked(lockType); return root;