源码分析-Mybatis源码阅读-主键生成器

源码解析-Mybatis
01 源码分析-Mybatis源码阅读准备
02 源码分析-Mybatis源码阅读-会话层
03 源码分析-Mybatis源码阅读-执行器
04 源码分析-Mybatis源码阅读-Statement语句处理器
05 源码分析-Mybatis源码阅读-参数处理器
06 源码分析-Mybatis源码阅读-结果集处理器
07 源码分析-Mybatis源码阅读-主键生成器
08 源码分析-Mybatis源码阅读-懒加载机制
09 源码分析-Mybatis源码阅读-游标
10 源码分析-Mybatis源码阅读-类型处理器
11 源码分析-Mybatis源码阅读-缓存
12 源码分析-Mybatis源码阅读-Mapper代理

一 主键生成器说明

主键生成器代码在org.apache.ibatis.executor.keygen包下,在03 源码分析-Mybatis源码阅读-执行器 文章中已经有介绍该包下所有类的相关说明。该包主要包含一个接口类和两个实现类,如下:

image-20210603175314115

二 主键生成器源码解读

KeyGenerator接口类源码解读如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* 主键生成器接口
* @author Clinton Begin
*/
public interface KeyGenerator {

/**
* 执行之前运行
* @param executor
* @param ms
* @param stmt
* @param parameter
*/
void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter);

/**
* 执行之后运行
* @param executor
* @param ms
* @param stmt
* @param parameter
*/
void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter);

}

Jdbc3KeyGenerator实现源码解读如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
/**
* 主键生成器 (自增的,也就是数据库自增后如果需要知道值,就用这个,这个是将自增结果回填到对象中)
* 比如 MySQL、PostgreSQL;会将执行SQL后从Statement中获取主键放到参数对象对应的属性里
* @author Clinton Begin
* @author Kazuki Shimizu
*/
public class Jdbc3KeyGenerator implements KeyGenerator {

private static final String SECOND_GENERIC_PARAM_NAME = ParamNameResolver.GENERIC_NAME_PREFIX + "2";

/**
* A shared instance.
*
* @since 3.4.3
*/
public static final Jdbc3KeyGenerator INSTANCE = new Jdbc3KeyGenerator();

private static final String MSG_TOO_MANY_KEYS = "Too many keys are generated. There are only %d target objects. "
+ "You either specified a wrong 'keyProperty' or encountered a driver bug like #1523.";

@Override
public void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
// do nothing
}

@Override
public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
processBatch(ms, stmt, parameter);
}

/**
* 将 {@code stmt} 返回的主键赋值到 {@code parameter}
* @param ms Mapper.xml文件的select,delete,update,insert这些DML标签的封装类
* @param stmt 执行SQL 语句并返回它所生成结果的对象。
* @param parameter 参数对象
*/
public void processBatch(MappedStatement ms, Statement stmt, Object parameter) {
// 拿到主键的属性名
final String[] keyProperties = ms.getKeyProperties();
if (keyProperties == null || keyProperties.length == 0) {
// 没有主键则无需操作
return;
}
// getGeneratedKeys:该方法获取由于执行此Statement对象而创建的所有自动生成的键
// 调用Statement对象的getGeneratedKeys方法获取自动生成的主键值
try (ResultSet rs = stmt.getGeneratedKeys()) {
// 获取结果集的元信息
final ResultSetMetaData rsmd = rs.getMetaData();
final Configuration configuration = ms.getConfiguration();
if (rsmd.getColumnCount() < keyProperties.length) {
// Error?
// 主键数目比结果的总字段数目还多,则发生了错误。
// 但因为此处是获取主键这样的附属操作,因此忽略错误,不影响主流程
} else {
// 调用子方法,将主键值赋给实参
assignKeys(configuration, rs, rsmd, keyProperties, parameter);
}
} catch (Exception e) {
throw new ExecutorException("Error getting generated key or setting result to parameter object. Cause: " + e, e);
}
}

/**
* 根据 {@code parameter} 的类型构建AssignKey对象,然后将 {@code rs} 的结果赋值到 {@code parameter} 的元素中
* @param configuration mybatis全局配置新
* @param rs 结果集
* @param rsmd 结果集元信息
* @param keyProperties 属性名数组
* @param parameter 参数对象
*/
@SuppressWarnings("unchecked")
private void assignKeys(Configuration configuration, ResultSet rs, ResultSetMetaData rsmd, String[] keyProperties,
Object parameter) throws SQLException {
// StrictMap,ParamMap:其功能甚至连代码都是一致的,都是HashMap的子类,都是对获取集合没有元素时会抛出异常。
// 如果参数对象是StrictMap,ParamMap的实例时
if (parameter instanceof ParamMap || parameter instanceof StrictMap) {
// Multi-param or single param with @Param
// 根据 parameter 构建KeyAssigner对象,然后将rs的对应数据赋值到 parameter 的对应的元素中
assignKeysToParamMap(configuration, rs, rsmd, keyProperties, (Map<String, ?>) parameter);
// 如果参数对象是ArrayList实例,且parameter是有元素的 且 获取parameter的第一个元素属于ParamMap实例
} else if (parameter instanceof ArrayList && !((ArrayList<?>) parameter).isEmpty()
&& ((ArrayList<?>) parameter).get(0) instanceof ParamMap) {
// Multi-param or single param with @Param in batch operation
// 构建AssignKey对象,将 rs 的结果赋值到 paramMapList 的元素中
assignKeysToParamMapList(configuration, rs, rsmd, keyProperties, (ArrayList<ParamMap<?>>) parameter);
} else {
// Single param without @Param
// 构建AssignKey对象,将 rs 的结果赋值到 parameter 的元素中,如果parameter不是集合,会自动将parameter转换成集合
assignKeysToParam(configuration, rs, rsmd, keyProperties, parameter);
}
}

/**
* 构建AssignKey对象,将 {@code rs} 的结果赋值到 {@code parameter} 的元素中,如果parameter不是集合,会自动将parameter转换成集合
* @param configuration mybatis全局配置信息
* @param rs 结果集
* @param rsmd 结果集元素
* @param keyProperties 属性名数组
* @param parameter 参数对象
* @throws SQLException
*/
private void assignKeysToParam(Configuration configuration, ResultSet rs, ResultSetMetaData rsmd,
String[] keyProperties, Object parameter) throws SQLException {
// 将parameter转换成Collection对象
Collection<?> params = collectionize(parameter);
// 如果params是空集合直接返回
if (params.isEmpty()) {
return;
}
// 定义一个分配者集合
List<KeyAssigner> assignerList = new ArrayList<>();
// 遍历属性数组
for (int i = 0; i < keyProperties.length; i++) {
// 构建分配者对象后添加到分配者集合
assignerList.add(new KeyAssigner(configuration, rsmd, i + 1, null, keyProperties[i]));
}
// 获取参数对象的迭代器
Iterator<?> iterator = params.iterator();
// 遍历结果集
while (rs.next()) {
// 如果iterator没有下一个元素,即结果集还有结果,但是参数对象集合已经没有元素可以接收结果了
if (!iterator.hasNext()) {
throw new ExecutorException(String.format(MSG_TOO_MANY_KEYS, params.size()));
}
// 获取下一个参数对象
Object param = iterator.next();
// 变量分配者进行分配,将rs的对应columnPosition位置的列数据赋值到param对应的propertyName中
assignerList.forEach(x -> x.assign(rs, param));
}
}

/**
* 构建AssignKey对象,将 {@code rs} 的结果赋值到 {@code paramMapList} 的元素中
* @param configuration mybatis全局配置新
* @param rs 结果集
* @param rsmd 结果集元信息
* @param keyProperties 配置的属性名数组
* @param paramMapList ArrayList<ParamMap>类型的参数对象
* @throws SQLException
*/
private void assignKeysToParamMapList(Configuration configuration, ResultSet rs, ResultSetMetaData rsmd,
String[] keyProperties, ArrayList<ParamMap<?>> paramMapList) throws SQLException {
// 获取paramMapList的迭代器
Iterator<ParamMap<?>> iterator = paramMapList.iterator();
// 初始化一个分配器集合
List<KeyAssigner> assignerList = new ArrayList<>();
// 计数器,表示已分配的结果数
long counter = 0;
// 遍历结果集
while (rs.next()) {
// 如果ParamMapList没有下一个元素,即结果集还有结果,但是参数对象集合已经没有元素可以接收结果了
if (!iterator.hasNext()) {
throw new ExecutorException(String.format(MSG_TOO_MANY_KEYS, counter));
}
// 获取参数对象的元素
ParamMap<?> paramMap = iterator.next();
// 如果分配器集合为空
if (assignerList.isEmpty()) {
// 遍历配置的属性数组
for (int i = 0; i < keyProperties.length; i++) {
// 从ParamMap中构建KeyAssigner并赋值到新的entry中,然后将entry的值添加到分配器集合里
assignerList
.add(getAssignerForParamMap(configuration, rsmd, i + 1, paramMap, keyProperties[i], keyProperties, false)
.getValue());
}
}
// 遍历分配器集合,将rs的对应columnPosition位置的列数据赋值到paramMap对应的propertyName中
assignerList.forEach(x -> x.assign(rs, paramMap));
counter++;
}
}

/**
* 根据 {@code paramMap} 构建KeyAssigner对象,然后将 {@code rs} 的对应数据赋值到 {@code paramMap} 的对应的元素中
* @param configuration Mybatis的全局配置信息
* @param rs 结果集
* @param rsmd 结果集元信息
* @param keyProperties 配置的属性名数组
* @param paramMap ParamMap类型或者StrictMap类型的参数对象
*/
private void assignKeysToParamMap(Configuration configuration, ResultSet rs, ResultSetMetaData rsmd,
String[] keyProperties, Map<String, ?> paramMap) throws SQLException {
// 如果参数对象没有元素直接返回
if (paramMap.isEmpty()) {
return;
}
// 新建一个分配映射集合
Map<String, Entry<Iterator<?>, List<KeyAssigner>>> assignerMap = new HashMap<>();
// 遍历属性名数组
for (int i = 0; i < keyProperties.length; i++) {
// 从ParamMap中构建KeyAssigner并赋值到新的entry中
Entry<String, KeyAssigner> entry = getAssignerForParamMap(configuration, rsmd, i + 1, paramMap, keyProperties[i],
keyProperties, true);
// 分配映射集合中存在entry key则直接返回 不存在则创建返回
Entry<Iterator<?>, List<KeyAssigner>> iteratorPair = MapUtil.computeIfAbsent(assignerMap, entry.getKey(),
k -> MapUtil.entry(collectionize(paramMap.get(k)).iterator(), new ArrayList<>()));
// 将entry存储的keyAssigner存放到iteratorPair的集合里
iteratorPair.getValue().add(entry.getValue());
}
// 计数器,表示已分配的结果数
long counter = 0;
// 遍历结果集元素
while (rs.next()) {
// 遍历assignerMap的值集合
for (Entry<Iterator<?>, List<KeyAssigner>> pair : assignerMap.values()) {
// 如果参数对象的键对象已经没有下一个了,这里的应该只是取iterator的第一个元素而已,而这里判断他是否存在第一个元素,不存在就抛出异常
if (!pair.getKey().hasNext()) {
throw new ExecutorException(String.format(MSG_TOO_MANY_KEYS, counter));
}
// 获取下一个参数对象的健对象
Object param = pair.getKey().next();
// 分配,将rs的对应columnPosition位置的列数据赋值到param对应的propertyName中
pair.getValue().forEach(x -> x.assign(rs, param));
}
counter++;
}
}

/**
* 从ParamMap中构建KeyAssigner并赋值到新的entry中
* @param config Mybatis全局配置信息
* @param rsmd 结果集元信息
* @param columnPosition 列名位置
* @param paramMap ParamMap类型或者StrictMap类型的参数对象
* @param keyProperty 配置的属性名
* @param keyProperties 配置的属性名数组
* @param omitParamName 是否忽略参数名称
*/
private Entry<String, KeyAssigner> getAssignerForParamMap(Configuration config, ResultSetMetaData rsmd,
int columnPosition, Map<String, ?> paramMap, String keyProperty, String[] keyProperties, boolean omitParamName) {
Set<String> keySet = paramMap.keySet();
// A caveat : if the only parameter has {@code @Param("param2")} on it,
// it must be referenced with param name e.g. 'param2.x'.
// 只有一个参数
boolean singleParam = !keySet.contains(SECOND_GENERIC_PARAM_NAME);
int firstDot = keyProperty.indexOf('.');
// 如果没有点
if (firstDot == -1) {
// 如果只有一个参数
if (singleParam) {
// 从单一的{@code paramMap}中构建KeyAssigner并保存到新的Entry中
return getAssignerForSingleParam(config, rsmd, columnPosition, paramMap, keyProperty, omitParamName);
}
// 如果不是只有一个参数值则抛出执行异常
throw new ExecutorException("Could not determine which parameter to assign generated keys to. "
+ "Note that when there are multiple parameters, 'keyProperty' must include the parameter name (e.g. 'param.id'). "
+ "Specified key properties are " + ArrayUtil.toString(keyProperties) + " and available parameters are "
+ keySet);
}
// 截取前面的字符串为参数名
String paramName = keyProperty.substring(0, firstDot);
// 如果参数对象中有这个参数名
if (keySet.contains(paramName)) {
// 如果忽略参数名,argParamName为null;否则argParamName为singleParamName
String argParamName = omitParamName ? null : paramName;
// 截取属性名点后面的字符串为参数键属性名
String argKeyProperty = keyProperty.substring(firstDot + 1);
// 构建KeyAssigner并赋值到新的entry中
return MapUtil.entry(paramName, new KeyAssigner(config, rsmd, columnPosition, argParamName, argKeyProperty));
// 如果只有一个参数值
} else if (singleParam) {
// 从单一的{@code paramMap}中构建KeyAssigner并保存到新的Entry中
return getAssignerForSingleParam(config, rsmd, columnPosition, paramMap, keyProperty, omitParamName);
} else {
// 如果参数对象中没有这个参数名且不只有一个参数值时抛异常
throw new ExecutorException("Could not find parameter '" + paramName + "'. "
+ "Note that when there are multiple parameters, 'keyProperty' must include the parameter name (e.g. 'param.id'). "
+ "Specified key properties are " + ArrayUtil.toString(keyProperties) + " and available parameters are "
+ keySet);
}
}

/**
* 从单一的{@code paramMap}中构建KeyAssigner并保存到新的Entry中
* @param config Mybatis全局配置信息
* @param rsmd 结果集元信息
* @param columnPosition 列名位置
* @param paramMap ParamMap类型或者StrictMap类型的参数对象
* @param keyProperty 配置的属性名
* @param omitParamName 是否忽略参数名称
*/
private Entry<String, KeyAssigner> getAssignerForSingleParam(Configuration config, ResultSetMetaData rsmd,
int columnPosition, Map<String, ?> paramMap, String keyProperty, boolean omitParamName) {
// Assume 'keyProperty' to be a property of the single param.
// 获取paramMap唯一的键名
String singleParamName = nameOfSingleParam(paramMap);
// 如果忽略参数名,argParamName为null;否则argParamName为singleParamName
String argParamName = omitParamName ? null : singleParamName;
// 构建KeyAssigner并赋值到新的entry中
return MapUtil.entry(singleParamName, new KeyAssigner(config, rsmd, columnPosition, argParamName, keyProperty));
}

/**
* 获取参数映射唯一健名
* @param paramMap 参数映射
* @return 参数映射唯一健名
*/
private static String nameOfSingleParam(Map<String, ?> paramMap) {
// There is virtually one parameter, so any key works.
// 获取paramMap的键名Set,通过迭代器,获取第一个键名并返回
return paramMap.keySet().iterator().next();
}

/**
* 将 {@code param} 转换成 Collection对象
* @param param 参数对象
* @return 如果 {@code param} 不是Collection对象,都会转换成ArrayList对象;否则直接返回 {@code param} ;
*/
private static Collection<?> collectionize(Object param) {
// 如果param本来就是Collection的实现类
if (param instanceof Collection) {
// 不需要转换,直接返回
return (Collection<?>) param;
// 如果param是Object数组的实现了
} else if (param instanceof Object[]) {
// 将param转换成ArrayList对象
return Arrays.asList((Object[]) param);
} else {
// 如果是普通java类,构建成ArrayList对象
return Arrays.asList(param);
}
}

/**
* 键名分配者
*/
private class KeyAssigner {
/** mybatis全局配置信息 */
private final Configuration configuration;
/** 结果集元信息 */
private final ResultSetMetaData rsmd;
/** TypeHandler注册器 */
private final TypeHandlerRegistry typeHandlerRegistry;
/** 列名位置 */
private final int columnPosition;
/** 参数名 */
private final String paramName;
/** 属性名 */
private final String propertyName;
/** 类型处理器 */
private TypeHandler<?> typeHandler;

protected KeyAssigner(Configuration configuration, ResultSetMetaData rsmd, int columnPosition, String paramName,
String propertyName) {
super();
this.configuration = configuration;
this.rsmd = rsmd;
this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
this.columnPosition = columnPosition;
this.paramName = paramName;
this.propertyName = propertyName;
}

/**
* 分配,将rs的对应columnPosition位置的列数据赋值到param对应的propertyName中
* @param rs 结果集
* @param param 参数对象
*/
protected void assign(ResultSet rs, Object param) {
// 如果参数名不为null
if (paramName != null) {
// If paramName is set, param is ParamMap 如果设置了参数名称,参数是参数映射;
// 从param获取paramName的值重新赋值给param
param = ((ParamMap<?>) param).get(paramName);
}
// 构建param的元对象
MetaObject metaParam = configuration.newMetaObject(param);
try {
// 如果typeHandler不为null
if (typeHandler == null) {
// 如果param元对象存在propertyName的setter方法
if (metaParam.hasSetter(propertyName)) {
// 获取propertyName的setter方法的属性类型
Class<?> propertyType = metaParam.getSetterType(propertyName);
// 根据属性类型,当前列名位置的jdbc类型取得对应的TypeHandler对象并赋值给typeHandler
typeHandler = typeHandlerRegistry.getTypeHandler(propertyType,
JdbcType.forCode(rsmd.getColumnType(columnPosition)));
} else {
// 如果param元对象不存在propertyName的setter方法抛异常
throw new ExecutorException("No setter found for the keyProperty '" + propertyName + "' in '"
+ metaParam.getOriginalObject().getClass().getName() + "'.");
}
}
// 如果typeHandler还是为null
if (typeHandler == null) {
// Error? 忽略
} else {
// 获取结果对象
Object value = typeHandler.getResult(rs, columnPosition);
// 将结果对赋值到param对应的propertyName中
metaParam.setValue(propertyName, value);
}
} catch (SQLException e) {
throw new ExecutorException("Error getting generated key or setting result to parameter object. Cause: " + e,
e);
}
}
}
}

SelectKeyGenerator实现源码解读如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/**
* 主键生成器 (在mapper里面配置的 selectKey生成方式)
* @author Clinton Begin
* @author Jeff Butler
*/
public class SelectKeyGenerator implements KeyGenerator {

/** 用户生成主键的SQL语句的特有标志,该标志会追加在用于生成主键的SQL语句的id的后方 */
public static final String SELECT_KEY_SUFFIX = "!selectKey";
/** 插入前执行还是插入后执行 */
private final boolean executeBefore;
/** 用户生成主键的SQL语句 */
private final MappedStatement keyStatement;

public SelectKeyGenerator(MappedStatement keyStatement, boolean executeBefore) {
this.executeBefore = executeBefore;
this.keyStatement = keyStatement;
}

/**
* 数据插入前进行的操作
* @param executor 执行器
* @param ms 映射语句对象
* @param stmt Statement对象
* @param parameter SQL语句实参对象
*/
@Override
public void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
if (executeBefore) {
processGeneratedKeys(executor, ms, parameter);
}
}

/**
* 数据插入后进行的操作
* @param executor 执行器
* @param ms 映射语句对象
* @param stmt Statement对象
* @param parameter SQL语句实参对象
*/
@Override
public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
if (!executeBefore) {
processGeneratedKeys(executor, ms, parameter);
}
}

/**
* 执行一段SQL语句后获取一个值,然后将该值赋给Java对象的自增属性
*
* @param executor 执行器
* @param ms 插入操作的SQL语句(不是生成主键的SQL语句)
* @param parameter 插入操作的对象
*/
private void processGeneratedKeys(Executor executor, MappedStatement ms, Object parameter) {
try {
// keyStatement为生成主键的SQL语句;keyStatement.getKeyProperties()拿到的是要自增的属性
if (parameter != null && keyStatement != null && keyStatement.getKeyProperties() != null) {
String[] keyProperties = keyStatement.getKeyProperties();
final Configuration configuration = ms.getConfiguration();
final MetaObject metaParam = configuration.newMetaObject(parameter);
// 为生成主键的SQL语句创建执行器keyExecutor。
// 不要关闭keyExecutor,因为它会被父级的执行器关闭
// Do not close keyExecutor.
// The transaction will be closed by parent executor.
Executor keyExecutor = configuration.newExecutor(executor.getTransaction(), ExecutorType.SIMPLE);
// 执行SQL语句,得到主键值
List<Object> values = keyExecutor.query(keyStatement, parameter, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
// 主键值必须唯一
if (values.size() == 0) {
throw new ExecutorException("SelectKey returned no data.");
} else if (values.size() > 1) {
throw new ExecutorException("SelectKey returned more than one value.");
} else {
MetaObject metaResult = configuration.newMetaObject(values.get(0));
if (keyProperties.length == 1) {
// 要自增的主键只有一个,为其赋值
if (metaResult.hasGetter(keyProperties[0])) {
// 从metaResult中用getter得到主键值
setValue(metaParam, keyProperties[0], metaResult.getValue(keyProperties[0]));
} else {
// 可能返回的直接就是主键值本身
// no getter for the property - maybe just a single value object
// so try that
setValue(metaParam, keyProperties[0], values.get(0));
}
} else {
// 要把执行SQL得到的值赋给多个属性
handleMultipleProperties(keyProperties, metaParam, metaResult);
}
}
}
} catch (ExecutorException e) {
throw e;
} catch (Exception e) {
throw new ExecutorException("Error selecting key or setting result to parameter object. Cause: " + e, e);
}
}

/**
* 处理多个属性的情况,将结果对象对配置的列名属性值赋值到参数对象对应配置的属性属性值里
* @param keyProperties 属性集合
* @param metaParam 参数元对象
* @param metaResult 结果元对象
*/
private void handleMultipleProperties(String[] keyProperties,
MetaObject metaParam, MetaObject metaResult) {
// 获取配置的列名数组
String[] keyColumns = keyStatement.getKeyColumns();
// 没有配置列名数组或者列名数组是空数组
if (keyColumns == null || keyColumns.length == 0) {
// no key columns specified, just use the property names 没有列名被指定是,只能使用属性名
// 遍历属性数组
for (String keyProperty : keyProperties) {
// 将结果对象keyProperties的属性值赋值到参数对象keyProperties属性值里
setValue(metaParam, keyProperty, metaResult.getValue(keyProperty));
}
// 如果有配置列名数组且列名数组不是空数组时
} else {
// 如果配置的列名数组长度跟配置的属性数组长度不一致时
if (keyColumns.length != keyProperties.length) {
// 抛出异常
throw new ExecutorException("If SelectKey has key columns, the number must match the number of key properties.");
}
// 遍历属性数组
for (int i = 0; i < keyProperties.length; i++) {
/*
* 注意这里由于i是同时当作列名数组的游标和属性数组的游标,直接取出相应位置元素进行赋值,并有判断它们是否对应,所以这里在mapper.xml
* 的列名数组和属性数组时顺序一定要一致,否则会出现属性和列名不对应而导致赋值错误
*/
//将结果对象keyProperties[i]的属性值赋值到参数对象keyProperties[i]属性值里
setValue(metaParam, keyProperties[i], metaResult.getValue(keyColumns[i]));
}
}
}

/**
* 将 {@code value} 赋值到 {@code metaParam} 的 {@code property} 里
* @param metaParam 参数元对象
* @param property 属性名
* @param value 属性值
*/
private void setValue(MetaObject metaParam, String property, Object value) {
// 如果参数元对象存在property的setter方法
if (metaParam.hasSetter(property)) {
// 将 value 赋值到 metaParam 的 property 里
metaParam.setValue(property, value);
// 如果不存setter方法
} else {
throw new ExecutorException("No setter found for the keyProperty '" + property + "' in " + metaParam.getOriginalObject().getClass().getName() + ".");
}
}
}