一种基于tk.mybatis的通用批量更新方法

文章介绍了如何在tk.mybatis基础上扩展一个通用的批量更新功能,以解决mybatis原生不支持批量更新的问题。通过使用casewhen语法,实现了在多种数据库(如MySQL、Oracle等)中兼容的批量更新操作,包括根据主键批量更新所有或非null属性。扩展的UpdateListProvider和相应的Mapper接口使得批量更新操作更加便捷。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 背景介绍:

mybatis没有提供批量更新的方法,通过代码中循环调用单个更新方法太消耗资源影响性能,在xml中写批量更新SQL又太繁琐并且无法复用,并且项目中需要兼容多种类型数据库,因此在tk.mybatis的基础上扩展一个通用批量更新Provider和Mapper;

  • 实现原理:

可选批量更新实现的方式:

  1. on duplicate key update语法,存在则更新,不存在则插入,能同时实现插入和更新,但on duplicate key update是MySQL特有语法,切换成其他类型数据库就无法使用了。
  2. foreach成多条SQL去执行,但Mybatis映射文件中的sql语句默认是不支持以" ; " 结尾的,也就是不支持多条sql语句的执行,为了支持这种方式,不同数据库的处理方式也不同,MySQL数据库需要在URL上设置&allowMultiQueries=true,Oracle数据库需要在语句的前后添加关键字BEGINEND;
  3. 其他的实现方式都无法在多种数据库中使用;
  4. 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等数据库。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值