" />

欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時間:2024年08月17日 12:15:39   作者:Zephyr丶Syn  
這篇文章主要介紹了關(guān)于tk.mybatis的通用批量更新方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

背景介紹

mybatis沒有提供批量更新的方法,通過代碼中循環(huán)調(diào)用單個更新方法太消耗資源影響性能,

在xml中寫批量更新SQL又太繁瑣并且無法復(fù)用,并且項目中需要兼容多種類型數(shù)據(jù)庫,

因此在tk.mybatis的基礎(chǔ)上擴展一個通用批量更新Provider和Mapper;

實現(xiàn)原理

可選批量更新實現(xiàn)的方式:

  • on duplicate key update語法,存在則更新,不存在則插入,能同時實現(xiàn)插入和更新,但on duplicate key update是MySQL特有語法,切換成其他類型數(shù)據(jù)庫就無法使用了。
  • foreach成多條SQL去執(zhí)行,但Mybatis映射文件中的sql語句默認(rèn)是不支持以" ; " 結(jié)尾的,也就是不支持多條sql語句的執(zhí)行,為了支持這種方式,不同數(shù)據(jù)庫的處理方式也不同,MySQL數(shù)據(jù)庫需要在URL上設(shè)置&allowMultiQueries=true,Oracle數(shù)據(jù)庫需要在語句的前后添加關(guān)鍵字BEGINEND;
  • 其他的實現(xiàn)方式都無法在多種數(shù)據(jù)庫中使用;
  • case when語法,該語法在常用的數(shù)據(jù)庫(MySQL、Oracle、DM、OB等)中都是支持的。

最終選定通過case when語法來實現(xiàn),并擴展一個通用批量更新Provider和Mapper;

實現(xiàn)代碼

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);
	}
	
	/**
	* 根據(jù)主鍵批量更新實體所有屬性值,使用case when 方式,支持聯(lián)合主鍵
	* 
	* @param ms MappedStatement
	* @return sql
	*/
	public String updateListByPrimaryKey(MappedStatement ms) {
		return this.sglHelper(ms, false);
	}

	/**
	*根據(jù)主鍵批量更新實體中不是null的屬性值,使用case when方式,支持聯(lián)合主鍵
	*
	* @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> {

	/**
	 * 根據(jù)主鍵批量更新實體中所有屬性值,支持聯(lián)合主鍵
	 * 
	 * @param updateList 參數(shù)
	 * @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> {

	/** 根據(jù)主鍵批量更新實體中不是null的屬性值,支持聯(lián)合主鍵
	 *
	 * @param updateList 參數(shù)
	 * @return int
	 */
	@UpdateProvider(type = UpdateListProvider.class,method = "dynamicSQL")
	int updateListByPrimaryKeySelective(List<T> updateList);
}

總結(jié)

以上,根據(jù)主鍵批量更新數(shù)據(jù)的方法就實現(xiàn)了,只需要自己的Mapper繼承這兩個通用擴展Mapper就可以調(diào)用updateListByPrimaryKeySelective()updateListByPrimaryKey()方法進(jìn)行批量更新了,并且同時支持聯(lián)合主鍵單一主鍵,兼容MySQL、Oracle、DM、OB等數(shù)據(jù)庫。

這些僅為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • java的線程池框架及線程池的原理

    java的線程池框架及線程池的原理

    這篇文章主要介紹了java的線程池框架及線程池的原理的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • Java內(nèi)存溢出案例模擬和原理分析過程

    Java內(nèi)存溢出案例模擬和原理分析過程

    這篇文章主要介紹了Java內(nèi)存溢出案例模擬和原理分析過程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-04-04
  • Java Hibernate使用SessionFactory創(chuàng)建Session案例詳解

    Java Hibernate使用SessionFactory創(chuàng)建Session案例詳解

    這篇文章主要介紹了Java Hibernate使用SessionFactory創(chuàng)建Session案例詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • JDK?8和JDK?17的區(qū)別和新特性大全

    JDK?8和JDK?17的區(qū)別和新特性大全

    這篇文章主要給大家介紹了關(guān)于JDK?8和JDK?17的區(qū)別和新特性的相關(guān)資料,文中總結(jié)一些Jdk8到Jdk17的一些新特性,給大家選擇jdk版本的時候有些參考性,需要的朋友可以參考下
    2023-06-06
  • Spring實戰(zhàn)之容器后處理器操作示例

    Spring實戰(zhàn)之容器后處理器操作示例

    這篇文章主要介紹了Spring實戰(zhàn)之容器后處理器操作,結(jié)合實例形式分析了spring容器后處理器配置、使用操作技巧與相關(guān)注意事項,需要的朋友可以參考下
    2019-12-12
  • Springboot項目使用html5的video標(biāo)簽完成視頻播放功能

    Springboot項目使用html5的video標(biāo)簽完成視頻播放功能

    這篇文章主要介紹了Springboot項目使用html5的video標(biāo)簽完成視頻播放功能,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-12-12
  • springboot默認(rèn)掃描的路徑方式

    springboot默認(rèn)掃描的路徑方式

    這篇文章主要介紹了springboot默認(rèn)掃描的路徑方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • Java關(guān)鍵字this與super詳解用法

    Java關(guān)鍵字this與super詳解用法

    這篇文章主要介紹了Java關(guān)鍵字this與super的用法,this與super是類實例化時通往Object類通道的打通者;this和super在程序中由于其經(jīng)常被隱式的使用而被我們忽略,但是理解其作用和使用規(guī)范肯定是必須的。接下來將詳述this與super各自的的作用,需要的朋友可以參考一下
    2022-04-04
  • SpringBoot項目中的視圖解析器問題(兩種)

    SpringBoot項目中的視圖解析器問題(兩種)

    SpringBoot官網(wǎng)推薦使用HTML視圖解析器,但是根據(jù)個人的具體業(yè)務(wù)也有可能使用到JSP視圖解析器,所以本文介紹了兩種視圖解析器,感興趣的可以了解下
    2020-06-06
  • 新聞列表的分頁查詢java代碼實現(xiàn)

    新聞列表的分頁查詢java代碼實現(xiàn)

    這篇文章主要為大家詳細(xì)介紹了新聞列表的分頁查詢java代碼實現(xiàn),感興趣的小伙伴們可以參考一下
    2016-08-08

最新評論