解讀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)鍵字BEGIN
和END;
: - 其他的實現(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 Hibernate使用SessionFactory創(chuàng)建Session案例詳解
這篇文章主要介紹了Java Hibernate使用SessionFactory創(chuàng)建Session案例詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08Springboot項目使用html5的video標(biāo)簽完成視頻播放功能
這篇文章主要介紹了Springboot項目使用html5的video標(biāo)簽完成視頻播放功能,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-12-12