具体的 SQL 模板实现如下所示:

import org.apache.ibatis.mapping.MappedStatement;
import tk.mybatis.mapper.MapperException;
import tk.mybatis.mapper.entity.EntityColumn;
import tk.mybatis.mapper.mapperhelper.EntityHelper;
import tk.mybatis.mapper.mapperhelper.MapperHelper;
import tk.mybatis.mapper.mapperhelper.SelectKeyHelper;
import tk.mybatis.mapper.mapperhelper.SqlHelper;
import tk.mybatis.mapper.provider.base.BaseInsertProvider; import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern; /**
* @author lxh
*/
public class GoodsInsertProvider extends BaseInsertProvider { public GoodsInsertProvider(Class<?> mapperClass, MapperHelper mapperHelper) {
super(mapperClass, mapperHelper);
} protected final static String VAR_REGEX = "#\\{(.+)}"; public String saveAll(MappedStatement ms) {
Class<?> entityClass = getEntityClass(ms);
StringBuilder sql = new StringBuilder();
//获取全部列
Set<EntityColumn> columnList = EntityHelper.getColumns(entityClass);
EntityColumn logicDeleteColumn = SqlHelper.getLogicDeleteColumn(entityClass);
sql.append(SqlHelper.insertIntoTable(entityClass, tableName(entityClass)));
sql.append(SqlHelper.insertColumns(entityClass, false, false, false));
sql.append("<trim prefix=\"VALUES \" suffixOverrides=\",\">");
sql.append("<foreach collection=\"collection\" item=\"item\" separator=\",\" >");
processKey(sql, entityClass, ms, columnList);
sql.append("<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">");
for (EntityColumn column : columnList) {
if (!column.isInsertable()) {
continue;
}
if (logicDeleteColumn != null && logicDeleteColumn == column) {
sql.append(SqlHelper.getLogicDeletedValue(column, false)).append(",");
continue;
}
String tmp;
//优先使用传入的属性值,当原属性property!=null时,用原属性
//自增的情况下,如果默认有值,就会备份到property_cache中,所以这里需要先判断备份的值是否存在
//其他情况值仍然存在原property中
if (column.isIdentity()) {
tmp = SqlHelper.getIfCacheNotNull(column,
column.getColumnHolder(null, "_cache", ","));
sql.append(tmp);
} else {
//其他情况值仍然存在原property中
tmp = SqlHelper.getIfNotNull(column,
column.getColumnHolder(null, null, ","), isNotEmpty());
sql.append(replaceByRegex(tmp, VAR_REGEX, "item.", true));
}
// tmp = SqlHelper.getIfNotNull(column,
// column.getColumnHolder(null, null, ","), isNotEmpty()); //当属性为null时,如果存在主键策略,会自动获取值,如果不存在,则使用null
//当null的时候,如果不指定jdbcType,oracle可能会报异常,指定VARCHAR不影响其他
if (column.isIdentity()) {
tmp = SqlHelper.getIfCacheIsNull(column, column.getColumnHolder() + ",");
sql.append(replaceByRegex(tmp, "#\\{(.+})", "item.", true));
} else {
//当null的时候,如果不指定jdbcType,oracle可能会报异常,指定VARCHAR不影响其他
tmp = SqlHelper.getIfIsNull(column,
column.getColumnHolder(null, null, ","), isNotEmpty());
sql.append(replaceByRegex(tmp, VAR_REGEX, "item.", true));
}
// tmp = SqlHelper.getIfIsNull(column,
// column.getColumnHolder(null, null, ","), isNotEmpty());
}
sql.append("</trim>");
sql.append("</foreach>");
sql.append("</trim>");
return sql.toString();
} protected void processKey(StringBuilder sql, Class<?> entityClass,
MappedStatement ms, Set<EntityColumn> columnList) {
//Identity列只能有一个
boolean hasIdentityKey = false;
//先处理cache或bind节点
for (EntityColumn column : columnList) {
if (column.isIdentity()) {
//这种情况下,如果原先的字段有值,需要先缓存起来,否则就一定会使用自动增长
//这是一个bind节点
String tmp = SqlHelper.getBindCache(column);
sql.append(replaceByRegex(tmp, "value=\"(.+\")", "item.", true));
//如果是Identity列,就需要插入selectKey
//如果已经存在Identity列,抛出异常
if (hasIdentityKey) {
//jdbc类型只需要添加一次
if (column.getGenerator() != null && "JDBC".equals(column.getGenerator())) {
continue;
}
throw new MapperException(ms.getId() + "对应的实体类"
+ entityClass.getName() + "中包含多个MySql的自动增长列,最多只能有一个!");
}
//插入selectKey
SelectKeyHelper.newSelectKeyMappedStatement(ms, column, entityClass, isBEFORE(), getIDENTITY(column));
hasIdentityKey = true;
} else if (column.getGenIdClass() != null) {
sql.append("<bind name=\"").append(column.getColumn())
.append("GenIdBind\" value=\"@tk.mybatis.mapper.genid.GenIdUtil@genId(");
sql.append("item").append(", '").append(column.getProperty()).append("'");
sql.append(", @").append(column.getGenIdClass().getName()).append("@class");
sql.append(", '").append(tableName(entityClass)).append("'");
sql.append(", '").append(column.getColumn()).append("')");
sql.append("\"/>");
}
}
} public static String replaceByRegex(String rawStr, String regex,
String content, boolean et) {
if (rawStr == null || rawStr.isEmpty()) {
return rawStr;
}
if (!et) {
return rawStr.replaceAll(regex, content);
} Pattern pat = Pattern.compile(regex);
Matcher matcher = pat.matcher(rawStr);
while (matcher.find()) {
if (matcher.groupCount() >= 1) {
String group = matcher.group(1);
rawStr = rawStr.replace(group, content + group);
}
}
return rawStr;
}
}

通用 Mapper 的批量插入实现的更多相关文章

  1. IBatis批量插入数据

    IBatis插入注意,数据量比较多的花,需要分批插入,策略是dao里面控制插入批次,mapper里面批量插入即可 @Override public Long insertBatch(List<W ...

  2. MyBatis 使用 foreach 批量插入

    MyBatis 使用 foreach 批量插入 参考博文 老司机学习MyBatis之动态SQL使用foreach在MySQL中批量插入 使用MyBatis一次性插入多条数据时候可以使用 <for ...

  3. (通用Mapper、分页,批量插入,一分钟接入)spring mvc+mybatis+maven集成tkmapper+pagehelper

    <!-- maven tkmapper引入--> <dependency> <groupId>tk.mybatis</groupId> <arti ...

  4. spring boot之使用通用Mapper批量添加数据

    通用Mapper是一款针对mybatis进行扩展的轻量级组件,使用起来非常方便.当调用其针对mysql进行批量添加数据的方法时,发现报错,仔细研究了一番,发现是在使用通用Mapper上出现了问题.下面 ...

  5. MyBatis动态批量插入、更新Mysql数据库的通用实现方案

    一.业务背景 由于需要从A数据库提取大量数据同步到B系统,采用了tomikos+jta进行分布式事务管理,先将系统数据源切换到数据提供方,将需要同步的数据查询出来,然后再将系统数据源切换到数据接收方, ...

  6. MySQL、Oracle批量插入SQL的通用写法

    举个例子: 现在要批量新增User对象到数据库USER表中 public class User{ //姓名 private String name; //年龄 private Integer age; ...

  7. mapper mysl实现批量插入 更新

    1.批量插入 <insert id="insertConfirm" parameterType="java.util.List"> insert i ...

  8. MyBatis魔法堂:Insert操作详解(返回主键、批量插入)

    一.前言    数据库操作怎能少了INSERT操作呢?下面记录MyBatis关于INSERT操作的笔记,以便日后查阅. 二. insert元素 属性详解   其属性如下: parameterType  ...

  9. 通用mapper认识和用法

    目录 0. 认识 1. 导包 2. mybatis的config文件:mybatis-mapper-config.xml 3. spring与mybatis整合配置文件:mybatis.xml 4. ...

  10. 通用Mapper的各个方法描述,参考官方

    下面是通用Mapper的各个方法描述,主要还是看官方的描述https://mapperhelper.github.io/all/. 基础接口 Select 接口:SelectMapper<T&g ...

随机推荐

  1. vi命令使用详解

    vi命令使用详解 1. 三种工作模式 命令模式:通过命令对文件进行常规操作 打开文件时进入命令模式 (vi的入口) 通过命令对文件进行常规操作,如定位.翻页.复制.粘贴.删除等在图形界面下通过鼠标或快 ...

  2. MySQL实战实战系列 06 全局锁和表锁 :给表加个字段怎么有这么多阻碍?

    今天我要跟你聊聊 MySQL 的锁.数据库锁设计的初衷是处理并发问题.作为多用户共享的资源,当出现并发访问的时候,数据库需要合理地控制资源的访问规则.而锁就是用来实现这些访问规则的重要数据结构. 根据 ...

  3. C++ bitset 用法和应用

    C++的 bitset 在 bitset 头文件中,它是一种类似数组的结构,它的每一个元素只能是0或1,每个元素仅用1bit空间. 下面是具体用法 构造函数 bitset常用构造函数有四种,如下 bi ...

  4. python第6章code

    01条件判断语句 # 条件判断语句(if语句)# 语法:if 条件表达式 : # 代码块# 执行的流程:if语句在执行时,会先对条件表达式进行求值判断,# 如果为True,则执行if后的语句# 如果为 ...

  5. 高效数据传输:Java通过绑定快速将数据导出至Excel

    摘要:本文由葡萄城技术团队于博客园原创并首发.转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 前言 把数据导出至 Excel 是很常见的需求,而数据的持久化 ...

  6. Gossip in Hyperledger Fabric

    1. Gossip协议基础 1.1 什么是分布式系统 分布式系统(Distributed System)是由多台计算机或计算节点组成的计算机系统,这些计算节点通过网络连接在一起,并协同工作以完成共同的 ...

  7. linux知识点 ROM,RAM,SRAM,DRAM,Flash

    参考视频:https://www.bilibili.com/video/BV13L4y1b7So?spm_id_from=333.337.search-card.all.click SRAM,DRAM ...

  8. 多线程指南:探究多线程在Node.js中的广泛应用

    前言 最初,JavaScript是用于设计执行简单的web任务的,比如表单验证.直到2009年,Node.js的创建者Ryan Dahl让开发人员认识到了通过JavaScript 进行后端开发已成为可 ...

  9. Nginx-多功能脚本

    #!/bin/bash #2020年2月16日 #auto_install_nginx_web.v3 #by fly ################################ #NGX_VER ...

  10. CF1295D Same GCDs

    前置知识: 辗转相除法 欧拉函数 首先,根据辗转相除法求 \(\gcd\) 的公式,可得 \(\gcd(a+x,m)=\gcd((a+x)\mod m,m)\). 则题目可以转化为:求有多少 \(x\ ...