写完才在群里有人告知本来tk mybatis就提供了批量insert的功能,那就放上来做个纪念吧.

   先写个数据字典(其实tk mybatis自身也有相应的功能)。


/**
 * Mybatis 带缓冲功能的数据字典
 * Created by rocklee on 2019/8/10 23:27
 */
public class MybatisDictionary {
  private static ConcurrentHashMap<Class<?>, String> entityClass2TableName=new ConcurrentHashMap<>();
  private static ConcurrentHashMap<Class<?>, String> entityClass2Columns=new ConcurrentHashMap<>();
  private static ConcurrentHashMap<Class<?>, List<String>> entityClass2FieldsList=new ConcurrentHashMap<>();
  private static ConcurrentHashMap<Class<?>, Hashtable<Field,String>> entityClass2Fields=new ConcurrentHashMap<>();

  public static String getTableName(Class<?> pvEntityClass){
    String lvsRet=entityClass2TableName.get(pvEntityClass);
    if (lvsRet!=null)return lvsRet;
    Table lvTable= pvEntityClass.getAnnotation(Table.class);
    if (lvTable==null){
      throw new RuntimeException(pvEntityClass.getName()+"不是有效的Entity类,缺少@Table标识");
    }
    lvsRet=lvTable.name();
    entityClass2TableName.put(pvEntityClass,lvsRet);
    return lvsRet;
  }
  public static String getColumns(Class<?> pvEntityClass){
    String lvsRet=entityClass2Columns.get(pvEntityClass);
    if (lvsRet!=null)return lvsRet;
    List<String> lvItems=new ArrayList<>();
    for (Field field:pvEntityClass.getDeclaredFields()){
      Column lvColumn=field.getAnnotation(Column.class);
      if (lvColumn==null)continue;
      lvItems.add(lvColumn.name());
    }
    lvsRet= Util.toString(lvItems,",");
    entityClass2Columns.put(pvEntityClass,lvsRet);
    return lvsRet;
  }
  public static List<String> getFieldsList(Class<?> pvEntityClass){
    List<String> lvRet=entityClass2FieldsList.get(pvEntityClass);
    if (lvRet!=null)return lvRet;
    lvRet=new ArrayList<>();
    for (Field field:pvEntityClass.getDeclaredFields()){
      Column lvColumn=field.getAnnotation(Column.class);
      if (lvColumn==null)continue;
      lvRet.add(field.getName());
    }
    entityClass2FieldsList.put(pvEntityClass,lvRet);
    return lvRet;
  }
  public static Hashtable<Field,String>getFields(Class<?> pvEntityClass){
    Hashtable<Field,String> lvRet=entityClass2Fields.get(pvEntityClass);
    if (lvRet!=null)return lvRet;
    lvRet=new Hashtable<Field,String>();
    for (Field field:pvEntityClass.getDeclaredFields()){
      Column lvColumn=field.getAnnotation(Column.class);
      if (lvColumn==null)continue;
      lvRet.put(field,lvColumn.name());
    }
    entityClass2Fields.put(pvEntityClass,lvRet);
    return lvRet;
  }
}

 

再写SqlProvider:

/** 批处理SQL处理器
 * Created by rocklee on 2019/8/10 23:11
 */
public class BatchSqlProvider  extends MapperTemplate {
  public BatchSqlProvider(Class<?> mapperClass, MapperHelper mapperHelper) {
    super(mapperClass, mapperHelper);
  }
 
  public String batchInsert(MappedStatement ms) {
    final Class<?> entityClass = getEntityClass(ms);
    StringBuilder sb=new StringBuilder();
    sb.append("INSERT INTO "+MybatisDictionary.getTableName(entityClass));
    sb.append("\n<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n");
    sb.append(MybatisDictionary.getColumns(entityClass));
    sb.append("</trim> \n");
    sb.append("\nVALUES\n");
    sb.append("<foreach collection=\"list\" item=\"record\" separator=\",\">");
    sb.append("\n");
    sb.append("<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n");
    String lvsValFields="#{record."+ Util.toString(MybatisDictionary.getFieldsList(entityClass),"},#{record.")
            +"}";
    sb.append(lvsValFields);
    sb.append("\n</trim>\n</foreach>");
    return sb.toString() ;
  }

}

Mapper:


/**
 * Created by rocklee on 2019/8/11 0:24
 */
@RegisterMapper
public interface BatchMapper<T> {
  /***
   * 批量插入
   * @param pvToInsertList
   * @return
   */
  @InsertProvider(type = BatchSqlProvider.class,  method = "dynamicSQL")
  int batchInsert(List<? extends T> pvToInsertList);
}

这是基于tk的MapperTemplate 写的sqlprovider,传入的是MappedStatement,这时候返回的SQL不是raw SQL,还能支持<if>,<foreach>这些mybatis表达式, 而如果用与mapper接口相同的参数方式返回sql,那这些表达式则不会被mybatis解释,而直接传到database服务器那边, 导致异常。

==============================

最后要提一下, tkmybatis带自了一个insertListMapper,我们extends它就可以实现批量insert了:

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐