Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit f9dfb6b

Browse filesBrowse files
committed
mybatis#101: Drastically improve performance by only checking if we can create the result once
Given that the mapping of the next rows would be identical, this is safe
1 parent 5be1b0c commit f9dfb6b
Copy full SHA for f9dfb6b

File tree

Expand file treeCollapse file tree

2 files changed

+31
-20
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

2 files changed

+31
-20
lines changed
Open diff view settings
Collapse file

‎src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java‎

Copy file name to clipboardExpand all lines: src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java
+22-16Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,12 +1035,17 @@ private String prependPrefix(String columnName, String prefix) {
10351035
private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap resultMap,
10361036
ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
10371037
final boolean useCollectionConstructorInjection = resultMap.hasResultMapsUsingConstructorCollection();
1038+
boolean verifyPendingCreationResult = true;
1039+
PendingConstructorCreation lastHandledCreation = null;
1040+
if (useCollectionConstructorInjection) {
1041+
verifyPendingCreationPreconditions(parentMapping);
1042+
}
1043+
10381044
final DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
10391045
ResultSet resultSet = rsw.getResultSet();
10401046
skipRows(resultSet, rowBounds);
10411047
Object rowValue = previousRowValue;
10421048

1043-
PendingConstructorCreation lastHandledCreation = null;
10441049
while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
10451050
final ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
10461051
final CacheKey rowKey = createRowKey(discriminatedResultMap, rsw, null);
@@ -1051,8 +1056,12 @@ private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap r
10511056
// issue #577, #542 && #101
10521057
if (useCollectionConstructorInjection) {
10531058
if (foundNewUniqueRow && lastHandledCreation != null) {
1054-
createAndStorePendingCreation(resultHandler, parentMapping, resultSet, resultContext, lastHandledCreation);
1059+
createAndStorePendingCreation(resultHandler, resultSet, resultContext, lastHandledCreation,
1060+
verifyPendingCreationResult);
10551061
lastHandledCreation = null;
1062+
// we only need to verify the first the result for a given result set
1063+
// as we can assume the next result will look exactly the same w.r.t its mapping
1064+
verifyPendingCreationResult = false;
10561065
}
10571066

10581067
rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject);
@@ -1074,7 +1083,8 @@ private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap r
10741083
}
10751084

10761085
if (useCollectionConstructorInjection && lastHandledCreation != null) {
1077-
createAndStorePendingCreation(resultHandler, parentMapping, resultSet, resultContext, lastHandledCreation);
1086+
createAndStorePendingCreation(resultHandler, resultSet, resultContext, lastHandledCreation,
1087+
verifyPendingCreationResult);
10781088
} else if (rowValue != null && mappedStatement.isResultOrdered()
10791089
&& shouldProcessMoreRows(resultContext, rowBounds)) {
10801090
storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
@@ -1221,26 +1231,22 @@ private boolean applyNestedPendingConstructorCreations(ResultSetWrapper rsw, Res
12211231
return foundValues;
12221232
}
12231233

1224-
private void verifyPendingCreationResultOrdered() {
1234+
private void verifyPendingCreationPreconditions(ResultMapping parentMapping) {
1235+
if (parentMapping != null) {
1236+
throw new ExecutorException(
1237+
"Cannot construct objects with collections in constructors using multiple result sets yet!");
1238+
}
1239+
12251240
if (!mappedStatement.isResultOrdered()) {
12261241
throw new ExecutorException("Cannot reliably construct result if we are not sure the results are ordered "
12271242
+ "so that no new previous rows would occur, set resultOrdered on your mapped statement if you have verified this");
12281243
}
12291244
}
12301245

1231-
private void createAndStorePendingCreation(ResultHandler<?> resultHandler, ResultMapping parentMapping,
1232-
ResultSet resultSet, DefaultResultContext<Object> resultContext, PendingConstructorCreation pendingCreation)
1246+
private void createAndStorePendingCreation(ResultHandler<?> resultHandler, ResultSet resultSet,
1247+
DefaultResultContext<Object> resultContext, PendingConstructorCreation pendingCreation, boolean shouldVerify)
12331248
throws SQLException {
1234-
if (parentMapping != null) {
1235-
throw new ExecutorException("Not supported in immutable constructor mode yet!");
1236-
}
1237-
1238-
verifyPendingCreationResultOrdered();
1239-
1240-
// todo: we can do this verification once per result type in the future
1241-
pendingCreation.verifyCanCreate(objectFactory);
1242-
final Object result = pendingCreation.create(objectFactory);
1243-
1249+
final Object result = pendingCreation.create(objectFactory, shouldVerify);
12441250
storeObject(resultHandler, resultContext, result, null, resultSet);
12451251
nestedResultObjects.clear();
12461252
}
Collapse file

‎src/main/java/org/apache/ibatis/executor/resultset/PendingConstructorCreation.java‎

Copy file name to clipboardExpand all lines: src/main/java/org/apache/ibatis/executor/resultset/PendingConstructorCreation.java
+9-4Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ void linkCollectionValue(ResultMapping constructorMapping, Object value) {
107107
* @param objectFactory
108108
* the object factory
109109
*/
110-
void verifyCanCreate(ObjectFactory objectFactory) {
110+
private void verifyCanCreate(ObjectFactory objectFactory) {
111111
// before we create, we need to get the constructor to be used and verify our types match
112112
// since we added to the collection completely unchecked
113113
final Constructor<?> resolvedConstructor = objectFactory.resolveConstructor(resultType, constructorArgTypes);
@@ -168,10 +168,16 @@ public String toString() {
168168
*
169169
* @param objectFactory
170170
* the object factory
171+
* @param verifyCreate
172+
* should we verify this object can be created, should only be needed once
171173
*
172174
* @return the new immutable result
173175
*/
174-
Object create(ObjectFactory objectFactory) {
176+
Object create(ObjectFactory objectFactory, boolean verifyCreate) {
177+
if (verifyCreate) {
178+
verifyCanCreate(objectFactory);
179+
}
180+
175181
final List<Object> newArguments = new ArrayList<>(constructorArgs.size());
176182
for (int i = 0; i < constructorArgs.size(); i++) {
177183
final PendingCreationMetaInfo creationMetaInfo = linkedCollectionMetaInfo.get(i);
@@ -191,8 +197,7 @@ Object create(ObjectFactory objectFactory) {
191197
final List<PendingConstructorCreation> linkedCreations = linkedCreationsByResultMapId.get(resultMapId);
192198

193199
for (PendingConstructorCreation linkedCreation : linkedCreations) {
194-
linkedCreation.verifyCanCreate(objectFactory);
195-
emptyCollection.add(linkedCreation.create(objectFactory));
200+
emptyCollection.add(linkedCreation.create(objectFactory, verifyCreate));
196201
}
197202

198203
newArguments.add(emptyCollection);

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.