19
19
import java .sql .ResultSetMetaData ;
20
20
import java .sql .SQLException ;
21
21
import java .sql .Statement ;
22
- import java .util .ArrayList ;
23
22
import java .util .Arrays ;
24
23
import java .util .Collection ;
25
- import java .util .List ;
26
24
import java .util .Map ;
27
25
26
+ import org .apache .ibatis .binding .MapperMethod .ParamMap ;
28
27
import org .apache .ibatis .executor .Executor ;
29
28
import org .apache .ibatis .executor .ExecutorException ;
30
29
import org .apache .ibatis .mapping .MappedStatement ;
30
+ import org .apache .ibatis .reflection .ArrayUtil ;
31
31
import org .apache .ibatis .reflection .MetaObject ;
32
32
import org .apache .ibatis .session .Configuration ;
33
+ import org .apache .ibatis .session .defaults .DefaultSqlSession .StrictMap ;
33
34
import org .apache .ibatis .type .JdbcType ;
34
35
import org .apache .ibatis .type .TypeHandler ;
35
36
import org .apache .ibatis .type .TypeHandlerRegistry ;
@@ -42,6 +43,7 @@ public class Jdbc3KeyGenerator implements KeyGenerator {
42
43
43
44
/**
44
45
* A shared instance.
46
+ *
45
47
* @since 3.4.3
46
48
*/
47
49
public static final Jdbc3KeyGenerator INSTANCE = new Jdbc3KeyGenerator ();
@@ -53,29 +55,24 @@ public void processBefore(Executor executor, MappedStatement ms, Statement stmt,
53
55
54
56
@ Override
55
57
public void processAfter (Executor executor , MappedStatement ms , Statement stmt , Object parameter ) {
56
- processBatch (ms , stmt , getParameters ( parameter ) );
58
+ processBatch (ms , stmt , parameter );
57
59
}
58
60
59
- public void processBatch (MappedStatement ms , Statement stmt , Collection <Object > parameters ) {
61
+ public void processBatch (MappedStatement ms , Statement stmt , Object parameter ) {
62
+ final String [] keyProperties = ms .getKeyProperties ();
63
+ if (keyProperties == null || keyProperties .length == 0 ) {
64
+ return ;
65
+ }
60
66
ResultSet rs = null ;
61
67
try {
62
68
rs = stmt .getGeneratedKeys ();
63
69
final Configuration configuration = ms .getConfiguration ();
64
- final TypeHandlerRegistry typeHandlerRegistry = configuration .getTypeHandlerRegistry ();
65
- final String [] keyProperties = ms .getKeyProperties ();
66
- final ResultSetMetaData rsmd = rs .getMetaData ();
67
- TypeHandler <?>[] typeHandlers = null ;
68
- if (keyProperties != null && rsmd .getColumnCount () >= keyProperties .length ) {
69
- for (Object parameter : parameters ) {
70
- // there should be one row for each statement (also one for each parameter)
71
- if (!rs .next ()) {
72
- break ;
73
- }
74
- final MetaObject metaParam = configuration .newMetaObject (parameter );
75
- if (typeHandlers == null ) {
76
- typeHandlers = getTypeHandlers (typeHandlerRegistry , metaParam , keyProperties , rsmd );
77
- }
78
- populateKeys (rs , metaParam , keyProperties , typeHandlers );
70
+ if (rs .getMetaData ().getColumnCount () >= keyProperties .length ) {
71
+ Object soleParam = getSoleParameter (parameter );
72
+ if (soleParam != null ) {
73
+ assignKeysToParam (configuration , rs , keyProperties , soleParam );
74
+ } else {
75
+ assignKeysToOneOfParams (configuration , rs , keyProperties , (Map <?, ?>) parameter );
79
76
}
80
77
}
81
78
} catch (Exception e ) {
@@ -91,25 +88,83 @@ public void processBatch(MappedStatement ms, Statement stmt, Collection<Object>
91
88
}
92
89
}
93
90
94
- private Collection <Object > getParameters (Object parameter ) {
95
- Collection <Object > parameters = null ;
96
- if (parameter instanceof Collection ) {
97
- parameters = (Collection ) parameter ;
98
- } else if (parameter instanceof Map ) {
99
- Map parameterMap = (Map ) parameter ;
100
- if (parameterMap .containsKey ("collection" )) {
101
- parameters = (Collection ) parameterMap .get ("collection" );
102
- } else if (parameterMap .containsKey ("list" )) {
103
- parameters = (List ) parameterMap .get ("list" );
104
- } else if (parameterMap .containsKey ("array" )) {
105
- parameters = Arrays .asList ((Object []) parameterMap .get ("array" ));
91
+ protected void assignKeysToOneOfParams (final Configuration configuration , ResultSet rs , final String [] keyProperties ,
92
+ Map <?, ?> paramMap ) throws SQLException {
93
+ // Assuming 'keyProperty' includes the parameter name. e.g. 'param.id'.
94
+ int firstDot = keyProperties [0 ].indexOf ('.' );
95
+ if (firstDot == -1 ) {
96
+ throw new ExecutorException (
97
+ "Could not determine which parameter to assign generated keys to. "
98
+ + "Note that when there are multiple parameters, 'keyProperty' must include the parameter name (e.g. 'param.id'). "
99
+ + "Specified key properties are " + ArrayUtil .toString (keyProperties ) + " and available parameters are "
100
+ + paramMap .keySet ());
101
+ }
102
+ String paramName = keyProperties [0 ].substring (0 , firstDot );
103
+ Object param ;
104
+ if (paramMap .containsKey (paramName )) {
105
+ param = paramMap .get (paramName );
106
+ } else {
107
+ throw new ExecutorException ("Could not find parameter '" + paramName + "'. "
108
+ + "Note that when there are multiple parameters, 'keyProperty' must include the parameter name (e.g. 'param.id'). "
109
+ + "Specified key properties are " + ArrayUtil .toString (keyProperties ) + " and available parameters are "
110
+ + paramMap .keySet ());
111
+ }
112
+ // Remove param name from 'keyProperty' string. e.g. 'param.id' -> 'id'
113
+ String [] modifiedKeyProperties = new String [keyProperties .length ];
114
+ for (int i = 0 ; i < keyProperties .length ; i ++) {
115
+ if (keyProperties [i ].charAt (firstDot ) == '.' && keyProperties [i ].startsWith (paramName )) {
116
+ modifiedKeyProperties [i ] = keyProperties [i ].substring (firstDot + 1 );
117
+ } else {
118
+ throw new ExecutorException ("Assigning generated keys to multiple parameters is not supported. "
119
+ + "Note that when there are multiple parameters, 'keyProperty' must include the parameter name (e.g. 'param.id'). "
120
+ + "Specified key properties are " + ArrayUtil .toString (keyProperties ) + " and available parameters are "
121
+ + paramMap .keySet ());
106
122
}
107
123
}
108
- if (parameters == null ) {
109
- parameters = new ArrayList <>();
110
- parameters .add (parameter );
124
+ assignKeysToParam (configuration , rs , modifiedKeyProperties , param );
125
+ }
126
+
127
+ private void assignKeysToParam (final Configuration configuration , ResultSet rs , final String [] keyProperties ,
128
+ Object param )
129
+ throws SQLException {
130
+ final TypeHandlerRegistry typeHandlerRegistry = configuration .getTypeHandlerRegistry ();
131
+ final ResultSetMetaData rsmd = rs .getMetaData ();
132
+ // Wrap the parameter in Collection to normalize the logic.
133
+ Collection <?> paramAsCollection = null ;
134
+ if (param instanceof Object []) {
135
+ paramAsCollection = Arrays .asList ((Object []) param );
136
+ } else if (!(param instanceof Collection )) {
137
+ paramAsCollection = Arrays .asList (param );
138
+ } else {
139
+ paramAsCollection = (Collection <?>) param ;
140
+ }
141
+ TypeHandler <?>[] typeHandlers = null ;
142
+ for (Object obj : paramAsCollection ) {
143
+ if (!rs .next ()) {
144
+ break ;
145
+ }
146
+ MetaObject metaParam = configuration .newMetaObject (obj );
147
+ if (typeHandlers == null ) {
148
+ typeHandlers = getTypeHandlers (typeHandlerRegistry , metaParam , keyProperties , rsmd );
149
+ }
150
+ populateKeys (rs , metaParam , keyProperties , typeHandlers );
151
+ }
152
+ }
153
+
154
+ private Object getSoleParameter (Object parameter ) {
155
+ if (!(parameter instanceof ParamMap || parameter instanceof StrictMap )) {
156
+ return parameter ;
157
+ }
158
+ Object soleParam = null ;
159
+ for (Object paramValue : ((Map <?, ?>) parameter ).values ()) {
160
+ if (soleParam == null ) {
161
+ soleParam = paramValue ;
162
+ } else if (soleParam != paramValue ) {
163
+ soleParam = null ;
164
+ break ;
165
+ }
111
166
}
112
- return parameters ;
167
+ return soleParam ;
113
168
}
114
169
115
170
private TypeHandler <?>[] getTypeHandlers (TypeHandlerRegistry typeHandlerRegistry , MetaObject metaParam , String [] keyProperties , ResultSetMetaData rsmd ) throws SQLException {
0 commit comments