背景介绍
mybatis没有提供批量更新的方法,通过代码中循环调用单个更新方法太消耗资源影响性能,
在xml中写批量更新sql又太繁琐并且无法复用,并且项目中需要兼容多种类型数据库,
因此在tk.mybatis的基础上扩展一个通用批量更新provider和mapper;
实现原理
可选批量更新实现的方式:
on duplicate key update语法,存在则更新,不存在则插入,能同时实现插入和更新,但on duplicate key update是mysql特有语法,切换成其他类型数据库就无法使用了。- foreach成多条sql去执行,但mybatis映射文件中的sql语句默认是不支持以" ; " 结尾的,也就是不支持多条sql语句的执行,为了支持这种方式,不同数据库的处理方式也不同,mysql数据库需要在url上设置
&allowmultiqueries=true,oracle数据库需要在语句的前后添加关键字begin和end;: - 其他的实现方式都无法在多种数据库中使用;
case when语法,该语法在常用的数据库(mysql、oracle、dm、ob等)中都是支持的。
最终选定通过case when语法来实现,并扩展一个通用批量更新provider和mapper;
实现代码
tk.mybatis的maven依赖: <dependency> <groupid>tk.mybatis</groupid> <artifactid>mapper-spring-boot-starter</artifactid> <version>2.2.4.4</version> </dependency>
updatelistprovider类:
package com.demo.ibatis.provider;
import org.apache.ibatis.mapping.mappedstatement;
import tk.mybatis.mapper.entity.entitycolumn;
import tk.mybatis .mapper.mapperhelper.entityhelper;
import tk.mybatis.mapper.mapperhelper.mapperhelper;
import tk.mybatis.mapper.mapperhelper.mappertemplate;
import tk.mybatis.mapper.mapperhelper.sglhetper;
import tk.mybatis.mapper.util.stringutil;
import java.util.set;
public class updatelistprovider extends mappertemplate {
public updatelistprovider(class<?> mapperclass, mapperhelper mapperhelper) {
super(mapperclass, mapperhelper);
}
/**
* 根据主键批量更新实体所有属性值,使用case when 方式,支持联合主键
*
* @param ms mappedstatement
* @return sql
*/
public string updatelistbyprimarykey(mappedstatement ms) {
return this.sglhelper(ms, false);
}
/**
*根据主键批量更新实体中不是null的属性值,使用case when方式,支持联合主键
*
* @param ms mappedstatement
* @return sql
*/
public string updatelistbyprimarykeyselective(mappedstatement ms) {
return this.sglhelper(ms, true);
}
private string sqlhelper(mappedstatement ms, boolean notnull) {
final class<?> entityclass = getentityclass(ms);
// 开始拼sql
stringbuilder sgl = new stringbuilder();
sql.append(sqlhelper.updatetable(entityclass,tablename(entityclass)));
sql.append("<trim prefix=\"set\" suffixoverrides= \",\">");
// 获取全部列
set<entitycolumn> allcolumns = entityhelper.getcolumns(entityclass);
// 找到主键列
set<entitycolumn> pkcolumns = entityhelper.getpkcolumns(entityclass);
for (entitycolumn column : allcolumns) {
if (!column.isid() && column.isupdatable()) {
sql.append(" <trim prefix=\"").append(column.getcolumn()).append(" = case\" suffix= \"end,\">");
sgl.append(" <foreach collection= \"list\" item= \"i\" index= \"index\">");
if (notnull) {
sql.append(this.getifnotnull("i", column, isnotempty()));
}
sql.append(" when ");
int count = 0;
for (entitycolumn pk : pkcolumns) {
if (count != 0) {
sql.append("and ");
}
sql.append(pk.getcolumn()).append("=#{i.").append(pk.getproperty()).append("} ");
count++;
}
sql.append("then ").append(column.getcolumnholder("i"));
if (notnull) {
sql.append(" </if>");
}
sql.append(" </foreach>");
sql.append(" </trim>");
}
}
sql.append("</trim>");
sql.append("where (");
int count = 0;
for (entitycolumn pk : pkcolumns) {
sql.append(pk.getcotumn());
if (count < pkcolumns.size() - 1) {
sql.append(", ");
}
count++;
}
sql.append(") in");
sql.append("<trim prefix= \"(\" suffix= \")\">");
sql.append("<foreach collection=\"list\" separator=\"), (\" item=\"i\" index=\"index\" open=\"(\" close=\")\" >");
count = 0;
for (entitycolumn pk : pkcolumns) {
sql.append("#{i.").append(pk.getproperty()).append("}");
if (count < pkcolumns.size() - 1) {
sg.append(", ");
}
count++;
}
sql.append("</foreach>");
sql.append("</trim>");
return sql.tostring();
}
private string getifnotnull(string entitynameentitycolumn column, boolean empty) {
stringbuilder sql = new stringbuilder();
sql.append(" <if test=\"");
if (stringutil.isnotempty(entityname)) {
sql.append(entityname).append(".");
}
sql.append(column.getproperty()).append(" != null");
if (empty && column.getjavatype().equals(string.class)) {
sql.append(" and ");
if (stringutil.isnotempty(entityname)) {
sql.append(entityname).append(".");
}
sql.append(column.getproperty()).append(" != '' ");
}
sql.append("\">");
return sql.tostring();
}
}updatelistbyprimarykeymapper类:
package com.demo.ibatis.mapper;
import com.demo.ibatis.provider.updatelistprovider;
import org.apache.ibatis.annotations.updateprovider;
import tk.mybatis .mapper.annotation.registermapper;
import java.util.list;
@registermapper
public interface updatelistbyprimarykeymapper<t> {
/**
* 根据主键批量更新实体中所有属性值,支持联合主键
*
* @param updatelist 参数
* @return int
*/
@updateprovider(type = updatelistprovider.class,method = "dynamicsql")
int updatelistbyprimarykey(list<t> updatelist);
}updatelistbyprimarykeyselectivemapper类:
package com.demo.ibatis.mapper;
import com.demo.ibatis.provider.updatelistprovider;
import org.apache.ibatis.annotations.updateprovider;
import tk.mybatis .mapper.annotation.registermapper;
import java.util.list;
@registermapper
public interface updatelistbyprimarykeyselectivemapper<t> {
/** 根据主键批量更新实体中不是null的属性值,支持联合主键
*
* @param updatelist 参数
* @return int
*/
@updateprovider(type = updatelistprovider.class,method = "dynamicsql")
int updatelistbyprimarykeyselective(list<t> updatelist);
}总结
以上,根据主键批量更新数据的方法就实现了,只需要自己的mapper继承这两个通用扩展mapper就可以调用updatelistbyprimarykeyselective()和updatelistbyprimarykey()方法进行批量更新了,并且同时支持联合主键和单一主键,兼容mysql、oracle、dm、ob等数据库。
这些仅为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论