MyBatis-Plus3.x版本使用入門和踩過的坑
個人認為呢,Mybatis-Plus是Mybatis的增強版,他只是在Mybatis的基礎上增加了功能,且并未對原有功能進行任何的改動??芍^是非常良心的一款開源產品,今天我就來給大家簡單的說一下以下幾個功能和踩過的坑。
前言
對于看官網看不太懂的朋友,可以看下這個視頻,2.0倍速也可哦,https://www.imooc.com/learn/1171 慕課上的mybatis-plus的視頻。
2020/9/28 MybatisX 插件重新開始更新并維護
MybatisX plugin Features:
- mapper and xml can jump back and forth
- mybatis.xml,mapper.xml prompt
- mapper and xml support auto prompt like jpa (reference MybatisCodeHelperPro)
- integrate mybatis generator Gui (copy from free mybatis plugin)
新版的MybatisX支持類似JPA的Defining Query Methods 寫法
2021/1/13 Mybatis-Plus 3.X版本代碼生成器模板
解決代碼生成器中Mybatis的xml文件生成兩遍的問題,糾正之前的錯誤寫法。
mybatis-plus提供了非常強大的代碼生成器,可以一鍵生成controller、service、mapper、mapping文件,省去了很多重復的動作,這里提供我簡單封裝之后的代碼生成器的代碼
package edu.changda.milk.tea.order.service; import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException; import com.baomidou.mybatisplus.core.toolkit.StringPool; import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.baomidou.mybatisplus.generator.AutoGenerator; import com.baomidou.mybatisplus.generator.InjectionConfig; import com.baomidou.mybatisplus.generator.config.*; import com.baomidou.mybatisplus.generator.config.po.TableInfo; import com.baomidou.mybatisplus.generator.config.rules.DateType; import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Scanner; /** * @classname: CodeGenerator * @description: mybatisplus代碼生成器 * @author: Linn-cn@126.com **/ public class CodeGenerator { /** * 代碼生成器的配置常量 */ private static final String outPutDir = "輸出目錄"; private static final String dataName = "root"; private static final String dataPwd = "root"; private static final String dataUrl = "jdbc:mysql://localhost:3306/數(shù)據庫名?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&characterSetResults=utf8"; private static final String driverName = "com.mysql.cj.jdbc.Driver"; private static final String parentPackage = "包名"; private static final String mapperName = "dao"; private static final String serviceName = "service"; private static final String implName = "service.impl"; private static final String pojoName = "entity"; private static final String controllerName = "controller"; private static final String projectPath = "項目主路徑"; public static void main(String[] args) { // 代碼生成器 AutoGenerator mpg = new AutoGenerator(); // 全局配置 GlobalConfig gc = getGlobalConfig(); mpg.setGlobalConfig(gc); // 數(shù)據源配置 DataSourceConfig dsc = getDataSourceConfig(); mpg.setDataSource(dsc); // 包配置 PackageConfig pc = getPackageConfig(); mpg.setPackageInfo(pc); // 去掉默認的mybatis的xml生成 // 不設置的話會生成兩份xml mpg.setTemplate(new TemplateConfig().setXml(null)); // 自定義xml生成路徑 InjectionConfig cfg = getInjectionConfig(); mpg.setCfg(cfg); // 策略配置 StrategyConfig strategy = getStrategyConfig(); mpg.setStrategy(strategy); mpg.execute(); } /** * 全局配置 * * @return */ public static GlobalConfig getGlobalConfig() { return new GlobalConfig() .setOutputDir(projectPath) .setDateType(DateType.TIME_PACK) .setAuthor("Linn-cn") .setOpen(false) .setBaseResultMap(true) .setBaseColumnList(true) // 覆蓋生成的文件 .setFileOverride(true) .setServiceName("%sService"); } /** * 數(shù)據源配置 * * @return */ public static DataSourceConfig getDataSourceConfig() { return new DataSourceConfig() .setUrl(dataUrl) .setDriverName(driverName) .setUsername(dataName) .setPassword(dataPwd); } /** * 包配置 * * @return */ public static PackageConfig getPackageConfig() { return new PackageConfig() .setParent(parentPackage) .setMapper(mapperName) .setEntity(pojoName) .setService(serviceName) .setController(controllerName) .setServiceImpl(implName) // 多模塊情況下,如果需要自定義生成路徑的話,案例如下,配置之后,上述配置全部失效 .setPathInfo(new HashMap<String, String>(){{ put(ConstVal.CONTROLLER_PATH, "絕對路徑"); put(ConstVal.ENTITY_PATH, "絕對路徑"); put(ConstVal.SERVICE_PATH, "絕對路徑"); put(ConstVal.SERVICE_IMPL_PATH, "絕對路徑"); put(ConstVal.MAPPER_PATH, "絕對路徑"); }}); } /** * 數(shù)據庫表配置 * * @return */ public static StrategyConfig getStrategyConfig() { return new StrategyConfig() .setNaming(NamingStrategy.underline_to_camel) .setColumnNaming(NamingStrategy.underline_to_camel) .setEntityTableFieldAnnotationEnable(true) .setEntityLombokModel(true) .setChainModel(true) .setEntityBooleanColumnRemoveIsPrefix(true) .setInclude(scanner("表名,多個英文逗號分割").split(",")) // 默認生成全部 //.setExclude(null) .setTablePrefix("milk_tea_") .setControllerMappingHyphenStyle(true); } /** * 自定義xml文件生成路徑 * 這里注意會生成兩個xml,一個是在你指定的下面,一個是在mapper包下的xml * 因為源碼中的判斷,判斷的是tableInfo和pathInfo的xml屬性是否為null,這兩個類都是默認生成屬性的 * 且對if (null != injectionConfig)自定義生成的判斷在默認的前面,所以會生成兩遍。 * 具體可見AbstractTemplateEngine batchOutput()的方法 * * @return */ public static InjectionConfig getInjectionConfig() { // 自定義配置 InjectionConfig cfg = new InjectionConfig() { @Override public void initMap() { } }; String templatePath = "/templates/mapper.xml.vm"; // 自定義輸出配置 List<FileOutConfig> focList = new ArrayList<>(); // 自定義配置會被優(yōu)先輸出 focList.add(new FileOutConfig(templatePath) { @Override public String outputFile(TableInfo tableInfo) { // 自定義輸出文件名 , 如果你 Entity 設置了前后綴、此處注意 xml 的名稱會跟著發(fā)生變化!! return projectPath + "/模塊路徑/src/main/resources/mapper/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML; } }); cfg.setFileOutConfigList(focList); return cfg; } /** * 讀取控制臺內容 */ public static String scanner(String tip) { Scanner scanner = new Scanner(System.in); System.out.println("請輸入" + tip + ":"); if (scanner.hasNext()) { String ipt = scanner.next(); if (StringUtils.isNotBlank(ipt)) { return ipt; } } throw new MybatisPlusException("請輸入正確的" + tip + "!"); } }
這里要注意,如上生成的實體類是開啟了lombox注解的,所以你如果用的idea的話,可能還要下載一個lombox插件和在pom.xml文件中導入lombox的包,不然木有效果,閑麻煩也可以關閉strategy.setEntityLombokModel(true);刪掉即可,默認為false;
關于mybtais-plus3.x的分頁
我們知道m(xù)ybtais-plus3.x版本之前是自帶一個內存分頁(在分頁的時候,是把所有的數(shù)據都查詢出來,然后通過RowBounds進行在內存分頁)的,也有分頁插件pagination。
但mybatis-plus3.x之前的分頁方法是這樣的,且返回的是List<T>集合,并且內存分頁并不需要配置分頁插件
/** * <p> * 根據 entity 條件,查詢全部記錄(并翻頁) * </p> * * @param rowBounds 分頁查詢條件(可以為 RowBounds.DEFAULT) * @param wrapper 實體對象封裝操作類(可以為 null) * @return List<T> */ List<T> selectPage(RowBounds rowBounds, @Param("ew") Wrapper<T> wrapper);
但我使用mybtais-plus3.x之后的分頁是這樣的
/** * 翻頁查詢 * * @param page 翻頁對象 * @param queryWrapper 實體對象封裝操作類 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper} */ IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);
可以看到返回的是IPage接口,其實這里返回的IPage跟傳進去的第一個參數(shù)page是一樣的,我們可以自己實現(xiàn)IPage接口也可以直接使用已經提供
但這里要注意,3.x版本要使用分頁,必須配置插件,否則會沒有效果,不像2.x沒配插件就是內存分頁。
package com.jianghaichao.infantmom.config; import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; import org.mybatis.spring.annotation.MapperScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.transaction.annotation.EnableTransactionManagement; /** * @program: infantmom * @classname: MybatisPlusConfig * @description: mybatis-plus配置 * @author: zhulin * @create: 2019-05-25 09:58 **/ //Spring boot方式 @EnableTransactionManagement @Configuration @MapperScan("com.jianghaichao.infantmom.mapper") public class MybatisPlusConfig { /** * 分頁插件 */ @Bean public PaginationInterceptor paginationInterceptor() { PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); // 設置請求的頁面大于最大頁后操作, true調回到首頁,false 繼續(xù)請求 默認false // paginationInterceptor.setOverflow(false); // 設置最大單頁限制數(shù)量,默認 500 條,-1 不受限制 // paginationInterceptor.setLimit(500); // 開啟 count 的 join 優(yōu)化,只針對部分 left join paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true)); return paginationInterceptor; } }
上面是springboot的配置形式
3.x版本的鏈式查詢
MyBatis-Plus還提供了一種鏈式查詢的方式,和上面的代碼效果一樣。
但是這種寫法偏向于炫技,可讀性沒有上面的代碼強,大家可以根據需要自行選擇方式。
List<BannerItem> bannerItems = new LambdaQueryChainWrapper<>(bannerItemMapper) .eq(BannerItem::getBannerId, id) .list();
如果只想查詢一條記錄,例如通過id查詢某條記錄的詳情,使用.one()
即可,例如
BannerItem bannerItem = new LambdaQueryChainWrapper<>(bannerItemMapper) .eq(BannerItem::getId, id) .one();
2019/7/31 踩坑補充,mybatis-plus有關于時間問題解決,例如查詢報錯問題
報錯如下
org.springframework.dao.InvalidDataAccessApiUsageException: Error attempting to get column 'created' from result set. Cause: java.sql.SQLFeatureNotSupportedException ; null; nested exception is java.sql.SQLFeatureNotSupportedException
解決方法:
在代碼生成器的全局策略中加上一行 gc.setDateType(DateType.ONLY_DATE);
設置生成的時間類型為Date即可解決問題,官網上也有這個問題的介紹
2020/1/6 踩坑補充,mp的自動填充
我們都知道,例如阿里開發(fā)規(guī)范里面要求,每張表都要有create_time和update_time字段,所以我們在插入數(shù)據和修改數(shù)據的時候往往需要自己set值進去,既然是一樣的操作,那么mp提供了自動注入,這里寫幾點自動填充時需要注意的點。
1. 自動注入在每次insert或update時都會觸發(fā),所以我們要考慮性能問題,那么就會有如下優(yōu)化寫法。這里只舉例insert的寫法,具體看官網更為詳細(官網自行百度)
這里需要注意的一點,這里的cretaeTime是實體類屬性而不是數(shù)據庫字段名
且填充有如下條件:
補充,在3.3.0版本之后官方建議使用strictInsertFill方法,這里需要注意一定區(qū)分開insert和update的區(qū)別
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推薦使用) this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); // 也可以使用(3.3.0 該方法有bug請升級到之后的版本如`3.3.1.8-SNAPSHOT`) /* 上面選其一使用,下面的已過時(注意 strictInsertFill 有多個方法,詳細查看源碼) */ //this.setFieldValByName("operator", "Jerry", metaObject); //this.setInsertFieldValByName("operator", "Jerry", metaObject);
2020/1/9 踩坑補充,Wrapper 自定義SQL
最近使用mybatis-plus3.2.0版本碰到一個問題,從官方文檔我們可看到3.0.7以后有了該功能
這里要提醒各位,如果在實例化的時候直接注入entity,你會發(fā)現(xiàn)無效,必須得用eq等方法
// 如下類似寫法均無效 LambdaQueryWrapper<WxCommentVO> wrapper = Wrappers.lambdaQuery(wxComment); QueryWrapper<WxCommentVO> wrapper1 = new QueryWrapper<>(wxComment); // 假如你需要判斷某字段值是否為1 wrapper.eq(WxComment::某字段,1); 必須得這樣寫,直接通過實體類注入是無效的
2020/5/1字段類型為 bit
、tinyint(1)
時映射為 boolean
類型
默認mysql驅動會把tinyint(1)字段映射為boolean: 0=false,非0=true
MyBatis 是不會自動處理該映射,如果不想把tinyint(1)映射為boolean類型:
- 修改類型tinyint(1)為tinyint(2)或者int
- 需要修改請求連接添加參數(shù)
tinyInt1isBit=false
,如下:
jdbc:mysql://127.0.0.1:3306/mp?tinyInt1isBit=false
2020/9/28 數(shù)據庫關鍵字如何處理?
@TableField(value = "`status`") private Boolean status;
2021/1/24 Map下劃線自動轉駝峰
@Bean public ConfigurationCustomizer configurationCustomizer() { return i -> i.setObjectWrapperFactory(new MybatisMapWrapperFactory()); }
到此這篇關于MyBatis-Plus3.x版本使用入門和踩過的坑的文章就介紹到這了,更多相關MyBatis-Plus3.x入門使用內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
詳解Java使用Pipeline對Redis批量讀寫(hmset&hgetall)
本篇文章主要介紹了Java使用Pipeline對Redis批量讀寫(hmset&hgetall),具有一定的參考價值,有興趣的可以了解一下。2016-12-12java web中的servlet3 upload上傳文件實踐
這篇文章主要介紹了servlet3 upload上傳文件實踐,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-11-11Java使用RedisTemplate操作Redis遇到的坑
這篇文章主要介紹了Java使用RedisTemplate操作Redis遇到的坑,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-12-12