src/main/java/com/itfsw/mybatis/generator/plugins/UpsertPlugin.java
private void generateBatchXmlElement(Document document, IntrospectedTable introspectedTable, boolean withBLOBs) {
        List<IntrospectedColumn> columns = ListUtilities.removeGeneratedAlwaysColumns(withBLOBs ? introspectedTable.getAllColumns() : introspectedTable.getNonBLOBColumns());
        XmlElement insertEle = new XmlElement("insert");
        insertEle.addAttribute(new Attribute("id", withBLOBs ? METHOD_BATCH_UPSERT_WITH_BLOBS : METHOD_BATCH_UPSERT));
        // 添加注释(!!!必须添加注释，overwrite覆盖生成时，@see XmlFileMergerJaxp.isGeneratedNode会去判断注释中是否存在OLD_ELEMENT_TAGS中的一点，例子：@mbg.generated)
        commentGenerator.addComment(insertEle);

        // 参数类型
        insertEle.addAttribute(new Attribute("parameterType", "map"));

        // 使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域模型属性中。所以只支持MYSQL和SQLServer
        // XmlElementGeneratorTools.useGeneratedKeys(insertEle, introspectedTable);

        // insert
        insertEle.addElement(new TextElement("insert into " + introspectedTable.getFullyQualifiedTableNameAtRuntime()));
        for (Element element : XmlElementGeneratorTools.generateKeys(columns, true)) {
            insertEle.addElement(element);
        }
        insertEle.addElement(new TextElement("values"));

        // values
        XmlElement foreachEle = new XmlElement("foreach");
        insertEle.addElement(foreachEle);
        foreachEle.addAttribute(new Attribute("collection", "list"));
        foreachEle.addAttribute(new Attribute("item", "item"));
        foreachEle.addAttribute(new Attribute("separator", ","));

        for (Element element : XmlElementGeneratorTools.generateValues(columns, "item.", true)) {
            foreachEle.addElement(element);
        }
        insertEle.addElement(new TextElement("on duplicate key update "));
        // set
        Iterator<IntrospectedColumn> columnIterator = columns.iterator();
        while (columnIterator.hasNext()) {
            IntrospectedColumn column = columnIterator.next();
            insertEle.addElement(new TextElement(
                    MyBatis3FormattingUtilities.getEscapedColumnName(column)
                            + " = values(" + MyBatis3FormattingUtilities.getEscapedColumnName(column)
                            + ")"
                            + (columnIterator.hasNext() ? "," : "")
            ));
        }

        document.getRootElement().addElement(insertEle);
        logger.debug("itfsw(存在即更新插件):" + introspectedTable.getMyBatis3XmlMapperFileName() + "增加" + (withBLOBs ? "batchUpsertWithBLOBs" : "batchUpsert") + "实现方法。");
    }
private void generateBatchXmlElement(Document document, IntrospectedTable introspectedTable, boolean withBLOBs) {
        List<IntrospectedColumn> columns = ListUtilities.removeGeneratedAlwaysColumns(withBLOBs ? introspectedTable.getAllColumns() : introspectedTable.getNonBLOBColumns());
        XmlElement insertEle = new XmlElement("insert");
        insertEle.addAttribute(new Attribute("id", withBLOBs ? METHOD_BATCH_UPSERT_WITH_BLOBS : METHOD_BATCH_UPSERT));
        // 添加注释(!!!必须添加注释，overwrite覆盖生成时，@see XmlFileMergerJaxp.isGeneratedNode会去判断注释中是否存在OLD_ELEMENT_TAGS中的一点，例子：@mbg.generated)
        commentGenerator.addComment(insertEle);

        // 参数类型
        insertEle.addAttribute(new Attribute("parameterType", "map"));

        // 使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域模型属性中。所以只支持MYSQL和SQLServer
        // XmlElementGeneratorTools.useGeneratedKeys(insertEle, introspectedTable);

        // insert
        insertEle.addElement(new TextElement("insert into " + introspectedTable.getFullyQualifiedTableNameAtRuntime()));
        for (Element element : XmlElementGeneratorTools.generateKeys(columns, true)) {
            insertEle.addElement(element);
        }
        insertEle.addElement(new TextElement("values"));

        // values
        XmlElement foreachEle = new XmlElement("foreach");
        insertEle.addElement(foreachEle);
        foreachEle.addAttribute(new Attribute("collection", "list"));
        foreachEle.addAttribute(new Attribute("item", "item"));
        foreachEle.addAttribute(new Attribute("separator", ","));

        for (Element element : XmlElementGeneratorTools.generateValues(columns, "item.", true)) {
            foreachEle.addElement(element);
        }
        insertEle.addElement(new TextElement("on duplicate key update "));
        // set
        Iterator<IntrospectedColumn> columnIterator = columns.iterator();
        while (columnIterator.hasNext()) {
            IntrospectedColumn column = columnIterator.next();
            insertEle.addElement(new TextElement(
                    MyBatis3FormattingUtilities.getEscapedColumnName(column)
                            + " = values(" + MyBatis3FormattingUtilities.getEscapedColumnName(column)
                            + ")"
                            + (columnIterator.hasNext() ? "," : "")
            ));
        }

        document.getRootElement().addElement(insertEle);
        logger.debug("itfsw(存在即更新插件):" + introspectedTable.getMyBatis3XmlMapperFileName() + "增加" + (withBLOBs ? "batchUpsertWithBLOBs" : "batchUpsert") + "实现方法。");
    }
批量
@param document
@param introspectedTable
@param withBLOBs