Skip to content

Commit 0b5e918

Browse files
author
mhyeon-lee
committed
DATAJDBC-498 Add LockClause to Dialect
1 parent b95cb06 commit 0b5e918

File tree

18 files changed

+627
-7
lines changed

18 files changed

+627
-7
lines changed

spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/NonQuotingDialect.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.springframework.data.relational.core.dialect.Dialect;
2020
import org.springframework.data.relational.core.dialect.HsqlDbDialect;
2121
import org.springframework.data.relational.core.dialect.LimitClause;
22+
import org.springframework.data.relational.core.dialect.LockClause;
2223
import org.springframework.data.relational.core.sql.IdentifierProcessing;
2324

2425
/**
@@ -27,6 +28,7 @@
2728
* @author Mark Paluch
2829
* @author Milan Milanov
2930
* @author Jens Schauder
31+
* @author Myeonghyeon Lee
3032
*/
3133
public class NonQuotingDialect extends AbstractDialect implements Dialect {
3234

@@ -39,6 +41,11 @@ public LimitClause limit() {
3941
return HsqlDbDialect.INSTANCE.limit();
4042
}
4143

44+
@Override
45+
public LockClause lock() {
46+
return HsqlDbDialect.INSTANCE.lock();
47+
}
48+
4249
@Override
4350
public IdentifierProcessing getIdentifierProcessing() {
4451
return IdentifierProcessing.create(new IdentifierProcessing.Quoting(""), IdentifierProcessing.LetterCasing.AS_IS);

spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/AnsiDialect.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,17 @@
2020
import org.springframework.data.relational.core.dialect.AbstractDialect;
2121
import org.springframework.data.relational.core.dialect.ArrayColumns;
2222
import org.springframework.data.relational.core.dialect.LimitClause;
23+
import org.springframework.data.relational.core.dialect.LockClause;
2324
import org.springframework.data.relational.core.sql.IdentifierProcessing;
25+
import org.springframework.data.relational.core.sql.LockOptions;
2426
import org.springframework.util.Assert;
2527
import org.springframework.util.ClassUtils;
2628

2729
/**
2830
* An SQL dialect for the ANSI SQL standard.
2931
*
3032
* @author Milan Milanov
33+
* @author Myeonghyeon Lee
3134
* @since 2.0
3235
*/
3336
public class AnsiDialect extends AbstractDialect {
@@ -78,6 +81,27 @@ public Position getClausePosition() {
7881
}
7982
};
8083

84+
private static final LockClause LOCK_CLAUSE = new LockClause() {
85+
86+
/*
87+
* (non-Javadoc)
88+
* @see org.springframework.data.relational.core.dialect.LockClause#getLock(LockOptions)
89+
*/
90+
@Override
91+
public String getLock(LockOptions lockOptions) {
92+
return "FOR UPDATE";
93+
}
94+
95+
/*
96+
* (non-Javadoc)
97+
* @see org.springframework.data.relational.core.dialect.LimitClause#getClausePosition()
98+
*/
99+
@Override
100+
public Position getClausePosition() {
101+
return Position.AFTER_ORDER_BY;
102+
}
103+
};
104+
81105
private final AnsiArrayColumns ARRAY_COLUMNS = new AnsiArrayColumns();
82106

83107
/*
@@ -89,6 +113,15 @@ public LimitClause limit() {
89113
return LIMIT_CLAUSE;
90114
}
91115

116+
/*
117+
* (non-Javadoc)
118+
* @see org.springframework.data.relational.core.dialect.Dialect#lock()
119+
*/
120+
@Override
121+
public LockClause lock() {
122+
return LOCK_CLAUSE;
123+
}
124+
92125
/*
93126
* (non-Javadoc)
94127
* @see org.springframework.data.relational.core.dialect.Dialect#getArraySupport()

spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/AbstractDialect.java

Lines changed: 98 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,16 @@
2020
import java.util.OptionalLong;
2121
import java.util.function.Function;
2222

23+
import org.springframework.data.relational.core.sql.LockMode;
24+
import org.springframework.data.relational.core.sql.LockOptions;
2325
import org.springframework.data.relational.core.sql.Select;
2426
import org.springframework.data.relational.core.sql.render.SelectRenderContext;
2527

2628
/**
2729
* Base class for {@link Dialect} implementations.
2830
*
2931
* @author Mark Paluch
32+
* @author Myeonghyeon Lee
3033
* @since 1.1
3134
*/
3235
public abstract class AbstractDialect implements Dialect {
@@ -38,9 +41,31 @@ public abstract class AbstractDialect implements Dialect {
3841
@Override
3942
public SelectRenderContext getSelectContext() {
4043

44+
Function<Select, ? extends CharSequence> afterFromTable = getAfterFromTable();
4145
Function<Select, ? extends CharSequence> afterOrderBy = getAfterOrderBy();
4246

43-
return new DialectSelectRenderContext(afterOrderBy);
47+
return new DialectSelectRenderContext(afterFromTable, afterOrderBy);
48+
}
49+
50+
/**
51+
* Returns a {@link Function afterFromTable Function}. Typically used for table hint for SQL Server.
52+
*
53+
* @return the {@link Function} called on {@code afterFromTable}.
54+
*/
55+
protected Function<Select, CharSequence> getAfterFromTable() {
56+
57+
Function<Select, ? extends CharSequence> afterFromTable = select -> "";
58+
59+
LockClause lockClause = lock();
60+
switch (lockClause.getClausePosition()) {
61+
62+
case AFTER_FROM_TABLE:
63+
afterFromTable = new LockRenderFunction(lockClause);
64+
65+
default:
66+
}
67+
68+
return afterFromTable.andThen(PrependWithLeadingWhitespace.INSTANCE);
4469
}
4570

4671
/**
@@ -50,34 +75,77 @@ public SelectRenderContext getSelectContext() {
5075
*/
5176
protected Function<Select, CharSequence> getAfterOrderBy() {
5277

53-
Function<Select, ? extends CharSequence> afterOrderBy;
78+
Function<Select, ? extends CharSequence> afterOrderByLimit = getAfterOrderByLimit();
79+
Function<Select, ? extends CharSequence> afterOrderByLock = getAfterOrderByLock();
80+
81+
return select -> {
5482

83+
StringBuilder afterOrderByBuilder = new StringBuilder();
84+
afterOrderByBuilder.append(afterOrderByLimit.apply(select));
85+
afterOrderByBuilder.append(afterOrderByLock.apply(select));
86+
return afterOrderByBuilder.toString();
87+
};
88+
}
89+
90+
private Function<Select, ? extends CharSequence> getAfterOrderByLimit() {
5591
LimitClause limit = limit();
5692

93+
Function<Select, ? extends CharSequence> afterOrderByLimit = select -> "";
94+
5795
switch (limit.getClausePosition()) {
5896

5997
case AFTER_ORDER_BY:
60-
afterOrderBy = new AfterOrderByLimitRenderFunction(limit);
98+
afterOrderByLimit = new AfterOrderByLimitRenderFunction(limit);
6199
break;
62100

63101
default:
64102
throw new UnsupportedOperationException(String.format("Clause position %s not supported!", limit));
65103
}
66104

67-
return afterOrderBy.andThen(PrependWithLeadingWhitespace.INSTANCE);
105+
return afterOrderByLimit.andThen(PrependWithLeadingWhitespace.INSTANCE);
106+
}
107+
108+
private Function<Select, ? extends CharSequence> getAfterOrderByLock() {
109+
LockClause lock = lock();
110+
111+
Function<Select, ? extends CharSequence> afterOrderByLock = select -> "";
112+
113+
switch (lock.getClausePosition()) {
114+
115+
case AFTER_ORDER_BY:
116+
afterOrderByLock = new LockRenderFunction(lock);
117+
118+
default:
119+
}
120+
121+
return afterOrderByLock.andThen(PrependWithLeadingWhitespace.INSTANCE);
68122
}
69123

70124
/**
71125
* {@link SelectRenderContext} derived from {@link Dialect} specifics.
72126
*/
73127
class DialectSelectRenderContext implements SelectRenderContext {
74128

129+
private final Function<Select, ? extends CharSequence> afterFromTable;
75130
private final Function<Select, ? extends CharSequence> afterOrderBy;
76131

77-
DialectSelectRenderContext(Function<Select, ? extends CharSequence> afterOrderBy) {
132+
DialectSelectRenderContext(
133+
Function<Select, ? extends CharSequence> afterFromTable,
134+
Function<Select, ? extends CharSequence> afterOrderBy) {
135+
136+
this.afterFromTable = afterFromTable;
78137
this.afterOrderBy = afterOrderBy;
79138
}
80139

140+
/*
141+
* (non-Javadoc)
142+
* @see org.springframework.data.relational.core.sql.render.SelectRenderContext#afterFromTable()
143+
*/
144+
@Override
145+
public Function<Select, ? extends CharSequence> afterFromTable() {
146+
return afterFromTable;
147+
}
148+
81149
/*
82150
* (non-Javadoc)
83151
* @see org.springframework.data.relational.core.sql.render.SelectRenderContext#afterOrderBy(boolean)
@@ -122,6 +190,31 @@ public CharSequence apply(Select select) {
122190
}
123191
}
124192

193+
/**
194+
* {@code LOCK} function rendering the {@link LockClause}.
195+
*/
196+
@RequiredArgsConstructor
197+
static class LockRenderFunction implements Function<Select, CharSequence> {
198+
199+
private final LockClause clause;
200+
201+
/*
202+
* (non-Javadoc)
203+
* @see java.util.function.Function#apply(java.lang.Object)
204+
*/
205+
@Override
206+
public CharSequence apply(Select select) {
207+
208+
LockMode lockMode = select.getLockMode();
209+
210+
if (lockMode == null) {
211+
return "";
212+
}
213+
214+
return clause.getLock(new LockOptions(lockMode));
215+
}
216+
}
217+
125218
/**
126219
* Prepends a non-empty rendering result with a leading whitespace,
127220
*/

spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/Dialect.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
*
2727
* @author Mark Paluch
2828
* @author Jens Schauder
29+
* @author Myeonghyeon Lee
2930
* @since 1.1
3031
*/
3132
public interface Dialect {
@@ -37,6 +38,13 @@ public interface Dialect {
3738
*/
3839
LimitClause limit();
3940

41+
/**
42+
* Return the {@link LockClause} used by this dialect.
43+
*
44+
* @return the {@link LockClause} used by this dialect.
45+
*/
46+
LockClause lock();
47+
4048
/**
4149
* Returns the array support object that describes how array-typed columns are supported by this dialect.
4250
*

spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/H2Dialect.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@
2020
import org.springframework.data.relational.core.sql.IdentifierProcessing;
2121
import org.springframework.data.relational.core.sql.IdentifierProcessing.LetterCasing;
2222
import org.springframework.data.relational.core.sql.IdentifierProcessing.Quoting;
23+
import org.springframework.data.relational.core.sql.LockOptions;
2324
import org.springframework.util.Assert;
2425
import org.springframework.util.ClassUtils;
2526

2627
/**
2728
* An SQL dialect for H2.
2829
*
2930
* @author Mark Paluch
31+
* @author Myeonghyeon Lee
3032
* @since 2.0
3133
*/
3234
public class H2Dialect extends AbstractDialect {
@@ -77,6 +79,27 @@ public Position getClausePosition() {
7779
}
7880
};
7981

82+
private static final LockClause LOCK_CLAUSE = new LockClause() {
83+
84+
/*
85+
* (non-Javadoc)
86+
* @see org.springframework.data.relational.core.dialect.LockClause#getLock(LockOptions)
87+
*/
88+
@Override
89+
public String getLock(LockOptions lockOptions) {
90+
return "FOR UPDATE";
91+
}
92+
93+
/*
94+
* (non-Javadoc)
95+
* @see org.springframework.data.relational.core.dialect.LockClause#getClausePosition()
96+
*/
97+
@Override
98+
public Position getClausePosition() {
99+
return Position.AFTER_ORDER_BY;
100+
}
101+
};
102+
80103
private final H2ArrayColumns ARRAY_COLUMNS = new H2ArrayColumns();
81104

82105
/*
@@ -88,6 +111,15 @@ public LimitClause limit() {
88111
return LIMIT_CLAUSE;
89112
}
90113

114+
/*
115+
* (non-Javadoc)
116+
* @see org.springframework.data.relational.core.dialect.Dialect#lock()
117+
*/
118+
@Override
119+
public LockClause lock() {
120+
return LOCK_CLAUSE;
121+
}
122+
91123
/*
92124
* (non-Javadoc)
93125
* @see org.springframework.data.relational.core.dialect.Dialect#getArraySupport()

spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/HsqlDbDialect.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,13 @@
1515
*/
1616
package org.springframework.data.relational.core.dialect;
1717

18+
import org.springframework.data.relational.core.sql.LockOptions;
19+
1820
/**
1921
* A {@link Dialect} for HsqlDb.
2022
*
2123
* @author Jens Schauder
24+
* @author Myeonghyeon Lee
2225
*/
2326
public class HsqlDbDialect extends AbstractDialect {
2427

@@ -31,6 +34,11 @@ public LimitClause limit() {
3134
return LIMIT_CLAUSE;
3235
}
3336

37+
@Override
38+
public LockClause lock() {
39+
return LOCK_CLAUSE;
40+
}
41+
3442
private static final LimitClause LIMIT_CLAUSE = new LimitClause() {
3543

3644
@Override
@@ -53,4 +61,17 @@ public Position getClausePosition() {
5361
return Position.AFTER_ORDER_BY;
5462
}
5563
};
64+
65+
private static final LockClause LOCK_CLAUSE = new LockClause() {
66+
67+
@Override
68+
public String getLock(LockOptions lockOptions) {
69+
return "FOR UPDATE";
70+
}
71+
72+
@Override
73+
public Position getClausePosition() {
74+
return Position.AFTER_ORDER_BY;
75+
}
76+
};
5677
}

0 commit comments

Comments
 (0)