开发者

解读tk.mybatis的通用批量更新方式

开发者 https://www.devze.com 2024-08-19 10:23 出处:网络 作者: Zephyr丶Syn
目录背景介绍实现原理实现代码总结背景介绍 myBATis没有提编程客栈供批量更新的方法,通过代码中循环调用单个更新方法太消耗资源影响性能,
目录
  • 背景介绍
  • 实现原理
  • 实现代码
  • 总结

背景介绍

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数据库需要在语句的前后添加关键字BEGINEND;
  • 其他的实现方式都无法在多种数据库中使用;
  • 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(Mahttp://www.devze.comppedStatement 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
	 */
	@UpdateProvidehttp://www.devze.comr(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 .mhttp://www.devze.comapper.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就可以调用updateLisandroidtByPrimaryKeySelective()updateListByPrimaryKey()方法进行批量更新了,并且同时支持联合主键单一主键,兼容MySQL、Oracle、DM、OB等数据库。

这些仅为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号