SpringBoot整合MyBatis-Plus詳細使用方法


SpringBoot整合mp

一、添加依賴pom.xml

<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.1.0</version> </dependency> <!-- mybatis plus 代碼生成器依賴 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.1.0</version> </dependency> <!-- 代碼生成器模板 --> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> </dependency> 

二、application.yml添加配置

spring: #數據庫配置 datasource: url: jdbc:mysql://127.0.0.1:3306/user_role?useUnicode=true&useSSL=false&characterEncoding=utf-8 username: root password: root # 使用druid數據源 type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver 

三、application配置@MapperScan

@SpringBootApplication @MapperScan("cn.com.vicente.demo.mapper") public class BdDemoApplication { public static void main(String[] args) { SpringApplication.run(BdDemoApplication.class, args); } } 

到這里就引入了MyBatis-Plus了。

四、代碼生成器

很多時候,都不想寫entity,mapper等文件,這個時候就可以使用代碼生成器來自動生成對應的文件了。
需要修改幾個地方:
1、數據庫連接
2、文件需要放置的文件夾地址。
具體代碼:

package cn.com.bluemoon.demo.generator; 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.NamingStrategy; import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine; import java.util.ArrayList; import java.util.List; import java.util.Scanner; // 演示例子,執行 main 方法控制台輸入模塊表名回車自動生成對應項目目錄中 public class CodeGenerator { /** * <p> * 讀取控制台內容 * </p> */ public static String scanner(String tip) { Scanner scanner = new Scanner(System.in); StringBuilder help = new StringBuilder(); help.append("請輸入" + tip + ":"); System.out.println(help.toString()); if (scanner.hasNext()) { String ipt = scanner.next(); if (StringUtils.isNotEmpty(ipt)) { return ipt; } } throw new MybatisPlusException("請輸入正確的" + tip + "!"); } public static void main(String[] args) { // 代碼生成器 AutoGenerator mpg = new AutoGenerator(); // 全局配置 GlobalConfig gc = new GlobalConfig(); String projectPath = System.getProperty("user.dir"); gc.setOutputDir(projectPath + "/src/main/java"); gc.setAuthor("vicente"); gc.setOpen(false); // service 命名方式 gc.setServiceName("%sService"); // service impl 命名方式 gc.setServiceImplName("%sServiceImpl"); // 自定義文件命名,注意 %s 會自動填充表實體屬性! gc.setMapperName("%sMapper"); gc.setXmlName("%sMapper"); gc.setFileOverride(true); gc.setActiveRecord(true); // XML 二級緩存 gc.setEnableCache(false); // XML ResultMap gc.setBaseResultMap(true); // XML columList gc.setBaseColumnList(false); // gc.setSwagger2(true); 實體屬性 Swagger2 注解 mpg.setGlobalConfig(gc); // 數據源配置 DataSourceConfig dsc = new DataSourceConfig(); dsc.setUrl("jdbc:mysql://127.0.0.1:3306/user_role?useUnicode=true&useSSL=false&characterEncoding=utf-8"); // dsc.setSchemaName("public"); dsc.setDriverName("com.mysql.jdbc.Driver"); dsc.setUsername("root"); dsc.setPassword("root"); mpg.setDataSource(dsc); // 包配置 PackageConfig pc = new PackageConfig(); //pc.setModuleName(scanner("模塊名")); pc.setParent("cn.com.vicente.demo"); pc.setEntity("entity"); pc.setService("service"); pc.setServiceImpl("service.impl"); mpg.setPackageInfo(pc); // 自定義配置 InjectionConfig cfg = new InjectionConfig() { @Override public void initMap() { // to do nothing } }; // 如果模板引擎是 freemarker String templatePath = "/templates/mapper.xml.ftl"; // 如果模板引擎是 velocity // String templatePath = "/templates/mapper.xml.vm"; // 自定義輸出配置 List<FileOutConfig> focList = new ArrayList<>(); // 自定義配置會被優先輸出 focList.add(new FileOutConfig(templatePath) { @Override public String outputFile(TableInfo tableInfo) { // 自定義輸出文件名 , 如果你 Entity 設置了前后綴、此處注意 xml 的名稱會跟着發生變化!! return projectPath + "/src/main/resources/mapper/" + pc.getModuleName() + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML; } }); /* cfg.setFileCreate(new IFileCreate() { @Override public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) { // 判斷自定義文件夾是否需要創建 checkDir("調用默認方法創建的目錄"); return false; } }); */ cfg.setFileOutConfigList(focList); mpg.setCfg(cfg); // 配置模板 TemplateConfig templateConfig = new TemplateConfig(); // 配置自定義輸出模板 //指定自定義模板路徑,注意不要帶上.ftl/.vm, 會根據使用的模板引擎自動識別 // templateConfig.setEntity("templates/entity2.java"); // templateConfig.setService(); // templateConfig.setController(); templateConfig.setXml(null); mpg.setTemplate(templateConfig); // 策略配置 StrategyConfig strategy = new StrategyConfig(); strategy.setNaming(NamingStrategy.underline_to_camel); strategy.setColumnNaming(NamingStrategy.underline_to_camel); //strategy.setSuperEntityClass("cn.com.bluemoon.demo.entity"); strategy.setEntityLombokModel(true); strategy.setRestControllerStyle(true); // 公共父類 //strategy.setSuperControllerClass("cn.com.bluemoon.demo.controller"); // 寫於父類中的公共字段 //strategy.setSuperEntityColumns("id"); strategy.setInclude(scanner("表名,多個英文逗號分割").split(",")); strategy.setControllerMappingHyphenStyle(true); strategy.setTablePrefix(pc.getModuleName() + "_"); mpg.setStrategy(strategy); mpg.setTemplateEngine(new FreemarkerTemplateEngine()); mpg.execute(); } } 

五、添加測試

這里主要是Mybatis-Plus的CURD等方法。


@RunWith(SpringRunner.class) @SpringBootTest public class SampleTest { private static Logger log = LoggerFactory.getLogger(SampleTest.class); @Autowired private MpUserService mpUserService; @Test public void test1() { // 插入新記錄 MpUser mpUser = new MpUser(); //mpUser.setId(1L); mpUser.setEmail("test66@baomidou.com"); mpUser.setAge(22); mpUser.setName("David Hong"); mpUserService.save(mpUser); // 或者 mpUser.insertOrUpdate(); // 更新完成后,mpUser對象的id會被補全 log.info("mpUser={}", mpUser.toString()); } @Test public void test2() { // 通過主鍵id查詢 MpUser mpUser = mpUserService.getById(1); log.info("mpUser={}", mpUser.toString()); } @Test public void test3() { // 條件查詢,下面相當於xml中的 select * from mp_user where name = 'Tom' and age = '28' limit 1 MpUser mpUser = mpUserService.getOne(new QueryWrapper<MpUser>().eq("name", "Tom").eq("age", "28").last("limit 1")); log.info("mpUser={}", mpUser.toString()); // 批量查詢 List<MpUser> mpUserList = mpUserService.list(); System.out.println("------------------------------all"); mpUserList.forEach(System.out::println); // 分頁查詢 int pageNum = 1; int pageSize = 10; IPage<MpUser> mpUserIPage = mpUserService.page(new Page<>(pageNum, pageSize), new QueryWrapper<MpUser>().gt("age", "20")); // IPage to List List<MpUser> mpUserList1 = mpUserIPage.getRecords(); System.out.println("------------------------------page"); mpUserList1.forEach(System.out::println); // 總頁數 long allPageNum = mpUserIPage.getPages(); System.out.println("------------------------------allPageNum"); System.out.println(allPageNum); } @Test public void test4() { MpUser mpUser = mpUserService.getById(2); // 修改更新 mpUser.setName("廣東廣州"); //mpUserService.updateById(mpUser); // 或者 mpUser.insertOrUpdate(); // 通過主鍵id刪除 mpUserService.removeById(1); // 或者 //mpUser.deleteById(); } } 

六、數據分頁

1、簡單分頁方法

int pageNum = 1; int pageSize = 10; IPage<MpUser> mpUserIPage = mpUserService.page(new Page<>(pageNum, pageSize), new QueryWrapper<MpUser>().gt("age", "20")); 

上面的分頁其實是調用BaseMapper的selectPage方法,這樣的分頁返回的數據確實是分頁后的數據,但在控制台打印的SQL語句上看到其實並沒有真正的物理分頁,而是通過緩存來獲得全部數據中再進行的分頁,這樣對於大數據量操作時是不可取的,那么接下來就敘述一下,真正實現物理分頁的方法。

2、 物理分頁方法

新建一個MybatisPlusConfig配置類文件

//Spring boot方式 @EnableTransactionManagement @Configuration @MapperScan("com.baomidou.cloud.service.*.mapper*") public class MybatisPlusConfig { @Bean public PaginationInterceptor paginationInterceptor() { PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); // 設置請求的頁面大於最大頁后操作, true調回到首頁,false 繼續請求 默認false // paginationInterceptor.setOverflow(false); // 設置最大單頁限制數量,默認 500 條,-1 不受限制 // paginationInterceptor.setLimit(500); return paginationInterceptor; } } 

重新調用mpUserService.page可以看到數據有物理分頁

3、XML自定義分頁

  • UserMapper.java 方法內容
public interface UserMapper{//可以繼承或者不繼承BaseMapper /** * <p> * 查詢 : 根據state狀態查詢用戶列表,分頁顯示 * 注意!!: 如果入參是有多個,需要加注解指定參數名才能在xml中取值 * </p> * * @param page 分頁對象,xml中可以從里面進行取值,傳遞參數 Page 即自動分頁,必須放在第一位(你可以繼承Page實現自己的分頁對象) * @param state 狀態 * @return 分頁對象 */ IPage<User> selectPageVo(Page page, @Param("age") Integer age); } 
  • UserMapper.xml 等同於編寫一個普通 list 查詢,mybatis-plus 自動替你分頁
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="cn.com.bluemoon.demo.mapper.MpUserMapper"> <select id="selectPageVo" resultType="cn.com.bluemoon.demo.entity.MpUser"> SELECT * FROM mp_user WHERE age=#{age} </select> </mapper> 
  • UserServiceImpl.java 調用分頁方法
public IPage<User> selectUserPage(Page<User> page, Integer state) { // 不進行 count sql 優化,解決 MP 無法自動優化 SQL 問題,這時候你需要自己查詢 count 部分 // page.setOptimizeCountSql(false); // 當 total 為小於 0 或者設置 setSearchCount(false) 分頁插件不會進行 count 查詢 // 要點!! 分頁返回的對象與傳入的對象是同一個 return baseMapper.selectPageVo(page, state); } 

4、測試自定義方法

 @Test public void test5() { Page<MpUser> mpUserPage = new Page<>(1,2); IPage<MpUser> iPage = mpUserService.selectUserPage(mpUserPage,22); System.out.println("總頁數:"+iPage.getPages()); System.out.println("總記錄數:"+iPage.getTotal()); List<MpUser> mpUserList1 = iPage.getRecords(); mpUserList1.forEach(System.out::println); } 

七、打印sql日志

為了方便排查錯誤,很多時候需要打印mybatis生成的sql語句,這時候就需要打印日志了。
在application.yml中添加:

# Logger Config
logging: level: cn.com.vicente.demo: debug 

或者

mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl 

八、邏輯刪除

很多時候需要表的數據雖然刪除了,但是還是希望不是真正刪除數據,數據還是留在數據庫中,只需要使用一個字段來做標志為即可,這時候就需要邏輯刪除功能。

SpringBoot 配置方式:

  • application.yml 加入配置(如果你的默認值和mp默認的一樣,該配置可無):

    mybatis-plus: global-config: db-config: logic-delete-value: 1 # 邏輯已刪除值(默認為 1) logic-not-delete-value: 0 # 邏輯未刪除值(默認為 0) 
  • 注冊 Bean(3.1.1開始不再需要這一步):

    import com.baomidou.mybatisplus.core.injector.ISqlInjector; import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MyBatisPlusConfiguration { @Bean public ISqlInjector sqlInjector() { return new LogicSqlInjector(); } } 
  • 實體類字段上加上@TableLogic注解

  • @TableField(select = false)注解,可以不查詢出deleted字段

    @TableLogic //@TableField(select = false) private Integer deleted; 
  • 效果: 使用mp自帶方法刪除和查找都會附帶邏輯刪除功能 (自己寫的xml不會)

    example
    刪除時 update user set deleted=1 where id =1 and deleted=0 查找時 select * from user where deleted=0 

附件說明

  • 邏輯刪除是為了方便數據恢復和保護數據本身價值等等的一種方案,但實際就是刪除。
  • 如果你需要再查出來就不應使用邏輯刪除,而是以一個狀態去表示。

九、主鍵策略

mybatis-plus 的主鍵生成的類型 默認類型 是 IdType.ID_WORKER全局唯一ID,內容為空自動填充(默認配置),雪花算法

1,局部主鍵策略實現

在實體類中 ID屬性加注解

@TableId(type = IdType.AUTO) 主鍵自增 數據庫中需要設置主鍵自增 private Long id; @TableId(type = IdType.NONE) 默認跟隨全局策略走 private Long id; @TableId(type = IdType.UUID) UUID類型主鍵 private Long id; @TableId(type = IdType.ID_WORKER) 數值類型數據庫中也必須是數值類型 否則會報錯 private Long id; @TableId(type = IdType.ID_WORKER_STR) 字符串類型 數據庫也要保證一樣字符類型 private Long id; @TableId(type = IdType.INPUT) 用戶自定義了 數據類型和數據庫保持一致就行 private Long id; 

2,全局主鍵策略實現

需要在application.yml文件中添加

mybatis-plus: global-config: db-config: id-type: uuid/none/input/id_worker/id_worker_str/auto 表示全局主鍵都采用該策略(如果全局策略和局部策略都有設置,局部策略優先級高) 

十、自動填充

很多時候表中都需要添加創建時間,創建人,修改時間,修改人來跟蹤數據的來源和變動,但每次插入數據和修改數據的時候都要set這幾個字段又感覺很麻煩,這個時候就系統系統能自動填充這幾個字段了。

  1. 字段必須聲明TableField注解,屬性fill選擇對應策略,該申明告知 Mybatis-Plus 需要預留注入 SQL 字段

    @TableField(fill = FieldFill.INSERT) private LocalDateTime createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updateTime; 

    屬性fill有四種對應策略,分別為:

    public enum FieldFill { /** * 默認不處理 */ DEFAULT, /** * 插入填充字段 */ INSERT, /** * 更新填充字段 */ UPDATE, /** * 插入和更新填充字段 */ INSERT_UPDATE } 
  1. 自定義實現類 MyMetaObjectHandler:

    @Component public class MyMetaObjectHandler implements MetaObjectHandler { private static final Logger LOGGER = LoggerFactory.getLogger(MyMetaObjectHandler.class); @Override public void insertFill(MetaObject metaObject) { LOGGER.info("start insert fill ...."); //this.setFieldValByName("createTime", LocalDateTime.now(), metaObject); this.setInsertFieldValByName("createTime", LocalDateTime.now(), metaObject); this.setInsertFieldValByName("updateTime", LocalDateTime.now(), metaObject); } @Override public void updateFill(MetaObject metaObject) { LOGGER.info("start update fill ...."); this.setUpdateFieldValByName("updateTime", LocalDateTime.now(), metaObject); } } 
  2. 測試使用

     @Test public void testInsert() { // 插入新記錄 MpUser mpUser = new MpUser(); mpUser.setEmail("wm@baomidou.com"); mpUser.setAge(28); mpUser.setName("王蒙"); mpUserService.save(mpUser); log.info("mpUser={}", mpUser.toString()); } @Test public void testUpdate() { // 更新記錄 MpUser mpUser = new MpUser(); mpUser.setId(1182478087497998337L); MpUser newUser = mpUser.selectById(); System.out.println(mpUser == newUser); mpUser.setName("王天"); mpUser.updateById(); log.info("mpUser={}", mpUser.toString()); log.info("newUser={}", newUser.toString()); } 
  1. 自動填充優化

    insertFill方法每次插入的時候都會調用,如果不存在createTime屬性的話,每次插入都會白白調用了,浪費資源,所以可以判斷是否存在該屬性

     boolean hasCreateTime = metaObject.hasSetter("createTime"); if (hasCreateTime){ this.setInsertFieldValByName("createTime", LocalDateTime.now(), metaObject); } 

希望,當更新時有設定時間,就用更新時設定的時間,當沒有設定時就自動填充更新時間,可以這樣設置

Object fieldValue = getFieldValByName("updateTime", metaObject); if (fieldValue == null){ this.setUpdateFieldValByName("updateTime", LocalDateTime.now(), metaObject);/ }


作者:weisen
鏈接:https://www.jianshu.com/p/1a163148b078
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM