Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the @Options#timeoutString #2886

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/main/java/org/apache/ibatis/annotations/Options.java
Expand Up @@ -96,9 +96,26 @@ enum FlushCachePolicy {
* Returns the statement timeout.
*
* @return the statement timeout
*
* @see #timeoutString()
*/
int timeout() default -1;

/**
* Returns the statement timeout string.
* <p>
* Can specify configuration's variables such as {@code ${timeout.select}}. If not resolve variable value, fallback
* the {@link #timeout()} value.
* </p>
*
* @return the statement timeout string
*
* @see #timeout()
*
* @since 3.5.14
*/
String timeoutString() default "";

/**
* Returns whether use the generated keys feature supported by JDBC 3.0
*
Expand Down
Expand Up @@ -33,6 +33,7 @@
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

Expand Down Expand Up @@ -80,6 +81,7 @@
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.mapping.StatementType;
import org.apache.ibatis.parsing.GenericTokenParser;
import org.apache.ibatis.parsing.PropertyParser;
import org.apache.ibatis.reflection.TypeParameterResolver;
import org.apache.ibatis.scripting.LanguageDriver;
Expand All @@ -101,6 +103,8 @@ public class MapperAnnotationBuilder {
InsertProvider.class, DeleteProvider.class)
.collect(Collectors.toSet());

private static final GenericTokenParser TOKEN_PARSER = new GenericTokenParser("${", "}", t -> t);

private final Configuration configuration;
private final MapperBuilderAssistant assistant;
private final Class<?> type;
Expand Down Expand Up @@ -345,7 +349,8 @@ void parseStatement(Method method) {
useCache = options.useCache();
// issue #348
fetchSize = options.fetchSize() > -1 || options.fetchSize() == Integer.MIN_VALUE ? options.fetchSize() : null;
timeout = options.timeout() > -1 ? options.timeout() : null;
Integer fallbackTimeout = options.timeout() > -1 ? options.timeout() : null;
timeout = parseStringValue(options.timeoutString(), fallbackTimeout, Integer::parseInt);
statementType = options.statementType();
if (options.resultSetType() != ResultSetType.DEFAULT) {
resultSetType = options.resultSetType();
Expand All @@ -372,6 +377,20 @@ null, parameterTypeClass, resultMapId, getReturnType(method, type), resultSetTyp
});
}

private <T> T parseStringValue(String valueString, T fallbackValue, Function<String, T> valueTypeConverter) {
if (valueString.isEmpty()) {
return fallbackValue;
} else {
Properties defaults = new Properties();
Optional.ofNullable(fallbackValue).map(String::valueOf)
.ifPresent(x -> defaults.setProperty(TOKEN_PARSER.parse(valueString), x));
Properties variables = new Properties(defaults);
variables.putAll(configuration.getVariables());
return Optional.ofNullable(PropertyParser.parse(valueString, variables)).map(valueTypeConverter)
.orElse(fallbackValue);
}
}

private LanguageDriver getLanguageDriver(Method method) {
Lang lang = method.getAnnotation(Lang.class);
Class<? extends LanguageDriver> langClass = null;
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/org/apache/ibatis/parsing/PropertyParser.java
Expand Up @@ -88,8 +88,9 @@ public String handleToken(String content) {
return variables.getProperty(key, defaultValue);
}
}
if (variables.containsKey(key)) {
return variables.getProperty(key);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kazuki43zoo Just a question on this. Historically, it was suggested to check contains before getting it for some performance reason. Has that changed? I have seen recently less of doing it via containsKey.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hazendaz Thanks for your review comment!
Your comment right!!! I was tried getting Benchmark. As result, processing using with containsKey was high performance rather than without containsKey. Therefore, I reverted my changes via c8ff596.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

学习了,看到了

String value = variables.getProperty(key);
if (value != null) {
return value;
}
}
return "${" + content + "}";
Expand Down
Expand Up @@ -17,6 +17,8 @@

import static org.assertj.core.api.Assertions.assertThat;

import java.util.Properties;

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Select;
Expand All @@ -25,6 +27,7 @@
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultSetType;
import org.apache.ibatis.mapping.StatementType;
import org.apache.ibatis.parsing.PropertyParser;
import org.apache.ibatis.session.Configuration;
import org.junit.jupiter.api.Test;

Expand Down Expand Up @@ -93,6 +96,26 @@ void withoutOptionsWhenNotSpecifyDefaultValue() {
assertThat(mappedStatement.getResultSetType()).isEqualTo(ResultSetType.DEFAULT);
}

@Test
void timeout() {
Configuration configuration = new Configuration();
Properties variables = new Properties();
variables.setProperty(PropertyParser.KEY_ENABLE_DEFAULT_VALUE, "true");
variables.setProperty("timeout.select1", "200");
configuration.setVariables(variables);
MapperAnnotationBuilder builder = new MapperAnnotationBuilder(configuration, TimeoutMapper.class);
builder.parse();

assertThat(configuration.getMappedStatement("selectWithTimeoutStringByNumber").getTimeout()).isEqualTo(10);
assertThat(configuration.getMappedStatement("selectWithTimeoutStringByVariable").getTimeout()).isEqualTo(200);
assertThat(configuration.getMappedStatement("selectWithTimeoutStringByVariableDefaultValue").getTimeout())
.isEqualTo(30);
assertThat(configuration.getMappedStatement("selectWithTimeoutAndTimeoutStringVariableFound").getTimeout())
.isEqualTo(200);
assertThat(configuration.getMappedStatement("selectWithTimeoutAndTimeoutStringVariableNotFound").getTimeout())
.isEqualTo(40);
}

interface Mapper {

@Insert("insert into test (name) values(#{name})")
Expand All @@ -112,4 +135,26 @@ interface Mapper {

}

interface TimeoutMapper {
@Select("select * from test")
@Options(timeoutString = "10")
String selectWithTimeoutStringByNumber(Integer id);

@Select("select * from test")
@Options(timeoutString = "${timeout.select1}")
String selectWithTimeoutStringByVariable(Integer id);

@Select("select * from test")
@Options(timeoutString = "${timeout.select2:30}")
String selectWithTimeoutStringByVariableDefaultValue(Integer id);

@Select("select * from test")
@Options(timeout = 20, timeoutString = "${timeout.select1}")
String selectWithTimeoutAndTimeoutStringVariableFound(Integer id);

@Select("select * from test")
@Options(timeout = 40, timeoutString = "${timeout.select3}")
String selectWithTimeoutAndTimeoutStringVariableNotFound(Integer id);
}

}