关于mybatis批量插入

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

猜你喜欢

转载自a14.iteye.com/blog/2117826