通用 Mapper 的批量插入实现
具体的 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 的批量插入实现的更多相关文章
- IBatis批量插入数据
IBatis插入注意,数据量比较多的花,需要分批插入,策略是dao里面控制插入批次,mapper里面批量插入即可 @Override public Long insertBatch(List<W ...
- MyBatis 使用 foreach 批量插入
MyBatis 使用 foreach 批量插入 参考博文 老司机学习MyBatis之动态SQL使用foreach在MySQL中批量插入 使用MyBatis一次性插入多条数据时候可以使用 <for ...
- (通用Mapper、分页,批量插入,一分钟接入)spring mvc+mybatis+maven集成tkmapper+pagehelper
<!-- maven tkmapper引入--> <dependency> <groupId>tk.mybatis</groupId> <arti ...
- spring boot之使用通用Mapper批量添加数据
通用Mapper是一款针对mybatis进行扩展的轻量级组件,使用起来非常方便.当调用其针对mysql进行批量添加数据的方法时,发现报错,仔细研究了一番,发现是在使用通用Mapper上出现了问题.下面 ...
- MyBatis动态批量插入、更新Mysql数据库的通用实现方案
一.业务背景 由于需要从A数据库提取大量数据同步到B系统,采用了tomikos+jta进行分布式事务管理,先将系统数据源切换到数据提供方,将需要同步的数据查询出来,然后再将系统数据源切换到数据接收方, ...
- MySQL、Oracle批量插入SQL的通用写法
举个例子: 现在要批量新增User对象到数据库USER表中 public class User{ //姓名 private String name; //年龄 private Integer age; ...
- mapper mysl实现批量插入 更新
1.批量插入 <insert id="insertConfirm" parameterType="java.util.List"> insert i ...
- MyBatis魔法堂:Insert操作详解(返回主键、批量插入)
一.前言 数据库操作怎能少了INSERT操作呢?下面记录MyBatis关于INSERT操作的笔记,以便日后查阅. 二. insert元素 属性详解 其属性如下: parameterType ...
- 通用mapper认识和用法
目录 0. 认识 1. 导包 2. mybatis的config文件:mybatis-mapper-config.xml 3. spring与mybatis整合配置文件:mybatis.xml 4. ...
- 通用Mapper的各个方法描述,参考官方
下面是通用Mapper的各个方法描述,主要还是看官方的描述https://mapperhelper.github.io/all/. 基础接口 Select 接口:SelectMapper<T&g ...
随机推荐
- Linux系列教程——Linux文件查找、Linux压缩打包、Linux软件管理
@ 目录 1 Linux文件查找 1.find查找概述 2.find查找示例 1.find名称查找 2.find大小查找 3.find类型查找 4.find时间查找 5.find用户查找 6.find ...
- 【ZT】关于字符集
utf8 全包容了gbk ,并不是说超集和子集:8i 的数据库 的 utf8 是 4位定长的字符编码:9i 和以上数据库的utf8 有4位定长AL32UTF8和 不定长的 UTF8 ,都是 ...
- Amazon MSK 可靠性最佳实践
1. Amazon MSK介绍 Kafka作为老牌的开源分布式事件流平台,已经广泛用于如数据集成,流处理,数据管道等各种应用中. 亚马逊云科技也于2019年2月推出了Apache Kafka的云托管版 ...
- [glibc] 带着问题看源码 —— exit 如何调用 atexit 处理器
前言 之前在写 apue 系列的时候,曾经对系统接口的很多行为产生过好奇,当时就想研究下对应的源码,但是苦于 linux 源码过于庞杂,千头万绪不知从何开启,就一直拖了下来. 最近在查一个问题时无意间 ...
- 码编译安装nginx
1.解释源码安装nginx软件的预编译,编译以及安装,分别是在做什么,需要注意什么? 预编译(configure): ./configure 00prefix=/usr/local/nginx --u ...
- Linux运维技能图谱
前言 该技能图谱依个人经验绘制,不适用于所有运维岗位.对于刚入行的从业者,也不需要按照图谱全学一遍,应该根据岗位工作内容来学习.有些技术我也不会,但作为一个选项我也写进去了,比如容器运行时有Docke ...
- 字符串小记 II:字符串自动机
OI 中的自动机指的是"有限状态自动机",它是对一串信号进行处理的数学模型,一般由以下三部分构成: 字符集(\(\Sigma\)),能够输入进自动机的字符集合. 状态集合(\(Q\ ...
- [Python急救站]草莓熊的绘制
草莓熊也是一个热门的图案,今天就用Python绘制一下 import turtle as t # 设置背景颜色,窗口位置以及大小 t.colormode(255) # 颜色模式 t.speed(0) ...
- [Python急救站课程]叠加等边三角形的绘制
叠加等边三角形的绘制 from turtle import * penup() fd(-100) pendown() pensize(10) seth(60) fd(200) seth(-60) fd ...
- zookeeper源码(04)leader选举流程
在"zookeeper源码(03)集群启动流程"中介绍了leader选举的入口,本文将详细分析leader选举组件和流程. leader选举流程(重要) quorumPeer的st ...