引用了http://topmanopensource.iteye.com/blog/1833001这篇博客上的方法,可是怎么也取不到,说主键为空,无奈自己断点看源代码:
private void processGeneratedKeys(Executor executor, MappedStatement ms, Object parameter) {
try {
//parameter就是要插入的对象
if (parameter != null && keyStatement != null && keyStatement.getKeyProperties() != null) {
//只能一个主键
String keyProperty = keyStatement.getKeyProperties()[0]; // just one key property is supported
final Configuration configuration = ms.getConfiguration();
//这个东西是关键,下面看这个东西有没有主键对应的属性的set方法的,稍后看里面的东西
final MetaObject metaParam = configuration.newMetaObject(parameter);
//有set方法就执行选择key的部分
if (keyProperty != null && metaParam.hasSetter(keyProperty)) {
// Do not close keyExecutor.
// The transaction will be closed by parent executor.
Executor keyExecutor = configuration.newExecutor(executor.getTransaction(), ExecutorType.SIMPLE);
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 {
metaParam.setValue(keyProperty, values.get(0));
}
}
}
} catch (ExecutorException e) {
throw e;
} catch (Exception e) {
throw new ExecutorException("Error selecting key or setting result to parameter object. Cause: " + e, e);
}
再来看看们如果我们的参数是一个List,批量插入么,当然是List之流,看看构造
MetaObject metaParam
private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory) {
this.originalObject = object;
this.objectFactory = objectFactory;
this.objectWrapperFactory = objectWrapperFactory;
if (object instanceof ObjectWrapper) {
this.objectWrapper = (ObjectWrapper) object;
} else if (objectWrapperFactory.hasWrapperFor(object)) {
this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
} else if (object instanceof Map) {
this.objectWrapper = new MapWrapper(this, (Map) object);
} else if (object instanceof Collection) {
this.objectWrapper = new CollectionWrapper(this, (Collection) object);
} else {
this.objectWrapper = new BeanWrapper(this, object);
}
}
很清楚,如果是List,那么objectWapper就是CollectionWrapper的对象,然后这个CollectionWrapper的hasSetter方法直接抛了异常
public boolean hasSetter(String name) {
throw new UnsupportedOperationException();
}
然后就没有然后了,这个是我看到的内容,不知道前面博客中的是怎么实现的,或者我的理解有误也请了解的大虾帮着解释下,然后说说我自己的实现:
首先是mapper文件
<insert id="batchInsertOrderItem" >
insert into amg_order_item
<foreach collection="snames" item="item" open="(" separator="," close=")">
${item}
</foreach>
values
<foreach collection="entities" separator="," item="entity">
<foreach collection="snames" item="item" open="(" separator="," close=")">
<if test="item=='order_item_id'">
(SELECT UUID_SHORT())
</if>
<if test="item!='order_item_id'">
#{entity.${s_l_name_update_map[item]}}
</if>
</foreach>
</foreach>
</insert>
由于mybatis被团队改造过了,所以跟原生的估计有些不一样,我这里是拼装值的时候直接判断如果是id的那个属性的值,就直接加上(SELECT UUID_SHORT())这个了。
好吧,又看了下,我迷茫了原来如果批量插入参数是List,在某一步会包装成map,DefaultSqlSession [line: 148] - update(String, Object) 在这里,
public int update(String statement, Object parameter) {
try {
dirty = true;
MappedStatement ms = configuration.getMappedStatement(statement);
//包装成map
return executor.update(ms, wrapCollection(parameter));
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
private Object wrapCollection(final Object object) {
if (object instanceof List) {
StrictMap<Object> map = new StrictMap<Object>();
map.put("list", object);
return map;
} else if (object != null && object.getClass().isArray()) {
StrictMap<Object> map = new StrictMap<Object>();
map.put("array", object);
return map;
}
return object;
}
public static class StrictMap<V> extends HashMap<String, V> {
private static final long serialVersionUID = -5741767162221585340L;
@Override
public V get(Object key) {
if (!super.containsKey(key)) {
throw new BindingException("Parameter '" + key + "' not found. Available parameters are " + this.keySet());
}
return super.get(key);
}
}
那所以在后面进行判断主键是否有set方法的时候就是用的MapWrapper的实例,直接返回了true;
public boolean hasSetter(String name) {
return true;
}
那然后就是往这个map中放了一个键值对,即主键与对应的值,可是疑问又来了,这个map中包装的是List啊,是批量插入啊,一个key怎么够用啊,暂时还没搞灵清。由于代码是改过的,所以无法跟踪查看原来的实现了,悲催