自己手寫Mybatis通用batchInsert問題
自己手寫Mybatis通用batchInsert
寫完才在群里有人告知本來tk mybatis就提供了批量insert的功能,那就放上來做個(gè)紀(jì)念吧.
先寫個(gè)數(shù)據(jù)字典(其實(shí)tk mybatis自身也有相應(yīng)的功能)。
/** ?* Mybatis 帶緩沖功能的數(shù)據(jù)字典 ?* Created by rocklee on 2019/8/10 23:27 ?*/ public class MybatisDictionary { ? private static ConcurrentHashMap<Class<?>, String> entityClass2TableName=new ConcurrentHashMap<>(); ? private static ConcurrentHashMap<Class<?>, String> entityClass2Columns=new ConcurrentHashMap<>(); ? private static ConcurrentHashMap<Class<?>, List<String>> entityClass2FieldsList=new ConcurrentHashMap<>(); ? private static ConcurrentHashMap<Class<?>, Hashtable<Field,String>> entityClass2Fields=new ConcurrentHashMap<>(); ? ? public static String getTableName(Class<?> pvEntityClass){ ? ? String lvsRet=entityClass2TableName.get(pvEntityClass); ? ? if (lvsRet!=null)return lvsRet; ? ? Table lvTable= pvEntityClass.getAnnotation(Table.class); ? ? if (lvTable==null){ ? ? ? throw new RuntimeException(pvEntityClass.getName()+"不是有效的Entity類,缺少@Table標(biāo)識(shí)"); ? ? } ? ? lvsRet=lvTable.name(); ? ? entityClass2TableName.put(pvEntityClass,lvsRet); ? ? return lvsRet; ? } ? public static String getColumns(Class<?> pvEntityClass){ ? ? String lvsRet=entityClass2Columns.get(pvEntityClass); ? ? if (lvsRet!=null)return lvsRet; ? ? List<String> lvItems=new ArrayList<>(); ? ? for (Field field:pvEntityClass.getDeclaredFields()){ ? ? ? Column lvColumn=field.getAnnotation(Column.class); ? ? ? if (lvColumn==null)continue; ? ? ? lvItems.add(lvColumn.name()); ? ? } ? ? lvsRet= Util.toString(lvItems,","); ? ? entityClass2Columns.put(pvEntityClass,lvsRet); ? ? return lvsRet; ? } ? public static List<String> getFieldsList(Class<?> pvEntityClass){ ? ? List<String> lvRet=entityClass2FieldsList.get(pvEntityClass); ? ? if (lvRet!=null)return lvRet; ? ? lvRet=new ArrayList<>(); ? ? for (Field field:pvEntityClass.getDeclaredFields()){ ? ? ? Column lvColumn=field.getAnnotation(Column.class); ? ? ? if (lvColumn==null)continue; ? ? ? lvRet.add(field.getName()); ? ? } ? ? entityClass2FieldsList.put(pvEntityClass,lvRet); ? ? return lvRet; ? } ? public static Hashtable<Field,String>getFields(Class<?> pvEntityClass){ ? ? Hashtable<Field,String> lvRet=entityClass2Fields.get(pvEntityClass); ? ? if (lvRet!=null)return lvRet; ? ? lvRet=new Hashtable<Field,String>(); ? ? for (Field field:pvEntityClass.getDeclaredFields()){ ? ? ? Column lvColumn=field.getAnnotation(Column.class); ? ? ? if (lvColumn==null)continue; ? ? ? lvRet.put(field,lvColumn.name()); ? ? } ? ? entityClass2Fields.put(pvEntityClass,lvRet); ? ? return lvRet; ? } }
再寫SqlProvider:
/** 批處理SQL處理器 ?* Created by rocklee on 2019/8/10 23:11 ?*/ public class BatchSqlProvider ?extends MapperTemplate { ? public BatchSqlProvider(Class<?> mapperClass, MapperHelper mapperHelper) { ? ? super(mapperClass, mapperHelper); ? } ? ? public String batchInsert(MappedStatement ms) { ? ? final Class<?> entityClass = getEntityClass(ms); ? ? StringBuilder sb=new StringBuilder(); ? ? sb.append("INSERT INTO "+MybatisDictionary.getTableName(entityClass)); ? ? sb.append("\n<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n"); ? ? sb.append(MybatisDictionary.getColumns(entityClass)); ? ? sb.append("</trim> \n"); ? ? sb.append("\nVALUES\n"); ? ? sb.append("<foreach collection=\"list\" item=\"record\" separator=\",\">"); ? ? sb.append("\n"); ? ? sb.append("<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">\n"); ? ? String lvsValFields="#{record."+ Util.toString(MybatisDictionary.getFieldsList(entityClass),"},#{record.") ? ? ? ? ? ? +"}"; ? ? sb.append(lvsValFields); ? ? sb.append("\n</trim>\n</foreach>"); ? ? return sb.toString() ; ? } ? }
Mapper:
/** ?* Created by rocklee on 2019/8/11 0:24 ?*/ @RegisterMapper public interface BatchMapper<T> { ? /*** ? ?* 批量插入 ? ?* @param pvToInsertList ? ?* @return ? ?*/ ? @InsertProvider(type = BatchSqlProvider.class, ?method = "dynamicSQL") ? int batchInsert(List<? extends T> pvToInsertList); }
這是基于tk的MapperTemplate 寫的sqlprovider,傳入的是MappedStatement,這時(shí)候返回的SQL不是raw SQL,還能支持<if>,<foreach>這些mybatis表達(dá)式, 而如果用與mapper接口相同的參數(shù)方式返回sql,那這些表達(dá)式則不會(huì)被mybatis解釋,而直接傳到database服務(wù)器那邊, 導(dǎo)致異常。
最后要提一下, tkmybatis帶自了一個(gè)insertListMapper,我們extends它就可以實(shí)現(xiàn)批量insert了:
使用Mapper通用insert方法遇到的問題
環(huán)境
- spingboot
- sqlserver
- mybatis
- Mapper
insert拋出不能為標(biāo)識(shí)列插入顯式值的異常
原因:表的自增主鍵,通常情況下不需要直接在insert語句中指定設(shè)值。查看控制臺(tái)打印語句,發(fā)現(xiàn)是對(duì)該字段做了插入。
解決方法:該表對(duì)應(yīng)實(shí)體中,在不需要做插入的字段上增加@Column(insertable = false)。
延伸:@Column還有一些值可供設(shè)值,
name
被標(biāo)注字段在數(shù)據(jù)庫表中所對(duì)應(yīng)字段的名稱;unique
表示該字段是否為唯一標(biāo)識(shí),默認(rèn)為false;nullable
表示該字段是否可以為null值,默認(rèn)為true;insertable
表示在使用“INSERT”腳本插入數(shù)據(jù)時(shí),是否需要插入該字段的值。updatable
表示在使用“UPDATE”腳本插入數(shù)據(jù)時(shí),是否需要更新該字段的值。columnDefinition
表示創(chuàng)建表時(shí),該字段創(chuàng)建的SQL語句,一般用于通過Entity生成表定義時(shí)使用。table
定義了包含當(dāng)前字段的表名。length
表示字段的長(zhǎng)度,當(dāng)字段的類型為varchar時(shí),該屬性才有效,默認(rèn)為255個(gè)字符。precision
屬性和scale屬性表示精度,當(dāng)字段類型為double時(shí),precision表示數(shù)值的總長(zhǎng)度,scale表示小數(shù)點(diǎn)所占的位數(shù)。insert
不能返回自增id的問題
這個(gè)問題,用過給自增id加 @GeneratedValue(generator =’“JDBC”)等,無效;
只能先不用Mapper通用的方法,自己定義一個(gè)insert接口,在xml中設(shè)置usergeneratedkeys=true ,keyProperty=“id” 這樣會(huì)把自增得到的id值注入到實(shí)體id參數(shù)中。
(該問題待解決,有知道的朋友指點(diǎn)下,注意數(shù)據(jù)庫是SqlServer)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot添加Email發(fā)送功能及常見異常詳解
本篇文章主要介紹了SpringBoot添加Email發(fā)送功能及常見異常詳解,具有一定的參考價(jià)值,有興趣的可以了解一下。2017-04-04Java POI實(shí)現(xiàn)將導(dǎo)入Excel文件的示例代碼
這篇文章主要介紹了Java POI實(shí)現(xiàn)將導(dǎo)入Excel文件的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-02-02Mybatis foreach標(biāo)簽使用不當(dāng)導(dǎo)致異常的原因淺析
這篇文章主要介紹了Mybatis foreach標(biāo)簽使用不當(dāng)導(dǎo)致異常的原因探究,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-12-12詳解mybatis plus使用insert沒有返回主鍵的處理
這篇文章主要介紹了詳解mybatis plus使用insert沒有返回主鍵的處理,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09spring,mybatis事務(wù)管理配置與@Transactional注解使用詳解
這篇文章主要介紹了spring,mybatis事務(wù)管理配置與@Transactional注解使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07Java Set簡(jiǎn)介_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
Set最大的特性就是不允許在其中存放的元素是重復(fù)的。接下來通過本文給大家分享java set常用方法和原理分析,需要的的朋友參考下吧2017-05-05Nacos?動(dòng)態(tài)服務(wù)發(fā)現(xiàn)、配置和服務(wù)管理平臺(tái)初體驗(yàn)
這篇文章主要介紹了Nacos?動(dòng)態(tài)服務(wù)發(fā)現(xiàn)、配置和服務(wù)管理平臺(tái)初體驗(yàn)的相關(guān)資料,需要的朋友可以參考下2022-09-09關(guān)于pytorch相關(guān)部分矩陣變換函數(shù)的問題分析
這篇文章主要介紹了pytorch相關(guān)部分矩陣變換函數(shù),包括tensor維度順序變換BCHW順序的調(diào)整,矩陣乘法相關(guān)函數(shù),矩陣乘,點(diǎn)乘,求取矩陣對(duì)角線元素或非對(duì)角線元素的問題,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-03-03示例解析java重載Overloading與覆蓋Overriding
這篇文章主要介紹了java重載Overloading與覆蓋Overriding的示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05