[jOOQ/jOOQ#11543] Emulate FOR UPDATE .. WAIT n using SET SESSION innodb_lock_wait_timeout in MySQL dialects

This commit is contained in:
Lukas Eder 2021-07-02 14:19:18 +02:00
parent 04a5a0ffe7
commit 661195af53
4 changed files with 32 additions and 6 deletions

View File

@ -39,11 +39,13 @@ package org.jooq;
import org.jetbrains.annotations.*;
// ...
// ...
import static org.jooq.SQLDialect.MARIADB;
// ...
import static org.jooq.SQLDialect.MYSQL;
// ...
// ...
import static org.jooq.SQLDialect.POSTGRES;
// ...
// ...
@ -119,7 +121,7 @@ public interface SelectForUpdateWaitStep<R extends Record> extends SelectForStep
* @see SelectQuery#setForLockModeWait(int)
*/
@NotNull @CheckReturnValue
@Support({ MARIADB, POSTGRES })
@Support({ MARIADB, MYSQL, POSTGRES })
SelectForStep<R> wait(int seconds);
/**

View File

@ -1170,7 +1170,7 @@ public interface SelectQuery<R extends Record> extends Select<R>, ConditionProvi
*
* @param seconds The number of seconds to wait for a lock
*/
@Support({ MARIADB, POSTGRES })
@Support({ MARIADB, MYSQL, POSTGRES })
void setForLockModeWait(int seconds);
/**

View File

@ -48,7 +48,9 @@ import static org.jooq.SQLDialect.H2;
import static org.jooq.SQLDialect.HSQLDB;
import static org.jooq.SQLDialect.MARIADB;
// ...
// ...
import static org.jooq.SQLDialect.MYSQL;
// ...
import static org.jooq.SQLDialect.POSTGRES;
// ...
// ...
@ -65,7 +67,10 @@ import static org.jooq.impl.Keywords.K_WITH;
import static org.jooq.impl.Keywords.K_WITH_LOCK;
import static org.jooq.impl.Names.N_LOCK_TIMEOUT;
import static org.jooq.impl.QueryPartCollectionView.wrap;
import static org.jooq.impl.Tools.appendSQL;
import static org.jooq.impl.Tools.prependSQL;
import static org.jooq.impl.Tools.BooleanDataKey.DATA_GROUP_CONCAT_MAX_LEN_SET;
import static org.jooq.impl.Tools.BooleanDataKey.DATA_LOCK_WAIT_TIMEOUT_SET;
import java.util.Set;
@ -77,6 +82,7 @@ import org.jooq.QueryPart;
import org.jooq.SQLDialect;
import org.jooq.Select;
import org.jooq.Table;
import org.jooq.impl.Tools.BooleanDataKey;
import org.jooq.impl.Tools.DataExtendedKey;
/**
@ -92,7 +98,8 @@ final class ForLock extends AbstractQueryPart {
private static final Set<SQLDialect> EMULATE_FOR_UPDATE_WAIT = SQLDialect.supportedBy(POSTGRES);
private static final Set<SQLDialect> EMULATE_FOR_UPDATE_WAIT_MY = SQLDialect.supportedUntil(MYSQL);
private static final Set<SQLDialect> EMULATE_FOR_UPDATE_WAIT_PG = SQLDialect.supportedBy(POSTGRES);
QueryPartList<Field<?>> forLockOf;
TableList forLockOfTables;
@ -168,9 +175,20 @@ final class ForLock extends AbstractQueryPart {
if (forLockWaitMode != null) {
// [#11243] PostgreSQL FOR UPDATE WAIT <n> emulation
if (forLockWaitMode == ForLockWaitMode.WAIT && EMULATE_FOR_UPDATE_WAIT.contains(ctx.dialect())) {
if (forLockWaitMode == ForLockWaitMode.WAIT && EMULATE_FOR_UPDATE_WAIT_PG.contains(ctx.dialect())) {
prependSQL(ctx.skipUpdateCount(), ctx.dsl().setLocal(N_LOCK_TIMEOUT, inline(forLockWait * 1000)));
}
else if (forLockWaitMode == ForLockWaitMode.WAIT && EMULATE_FOR_UPDATE_WAIT_MY.contains(ctx.dialect())) {
if (ctx.data(DATA_LOCK_WAIT_TIMEOUT_SET) == null) {
ctx.skipUpdateCounts(2).data(DATA_LOCK_WAIT_TIMEOUT_SET, true);
prependSQL(ctx,
ctx.dsl().query("{set} @t = @@innodb_lock_wait_timeout"),
ctx.dsl().query("{set} @@innodb_lock_wait_timeout = {0}", inline(forLockWait))
);
appendSQL(ctx, ctx.dsl().query("{set} @@innodb_lock_wait_timeout = @t"));
}
}
else {
ctx.sql(' ').visit(forLockWaitMode.toKeyword());

View File

@ -538,7 +538,13 @@ final class Tools {
* [#12092] Whether the @@group_concat_max_len value has already been
* set.
*/
DATA_GROUP_CONCAT_MAX_LEN_SET
DATA_GROUP_CONCAT_MAX_LEN_SET,
/**
* [#11543] Whether the @@innodb_lock_wait_timeout value has already
* been set.
*/
DATA_LOCK_WAIT_TIMEOUT_SET
}