引用了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怎么够用啊,暂时还没搞灵清。由于代码是改过的,所以无法跟踪查看原来的实现了,悲催