日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

【Java萌新】MyBatis-Plus案例

發布時間:2024/9/30 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Java萌新】MyBatis-Plus案例 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

MyBatis-Plus是什么?

https://baomidou.com/#/
Mybatis-Plus(簡稱MP)是一個 Mybatis 的增強工具,在 Mybatis 的基礎上只做增強不做改變,為簡化開發、提高效率而生。這是官方給的定義,關于mybatis-plus的更多介紹及特性,可以參考mybatis-plus官網。那么它是怎么增強的呢?其實就是它已經封裝好了一些crud方法,我們不需要再寫xml了,直接調用這些方法就行,就類似于JPA。

特性

  • 無侵入 :只做增強不做改變,引入它不會對現有工程產生影響,如絲般順滑
  • 損耗小 :啟動即會自動注入基本 CURD,性能基本無損耗,直接面向對象操作, BaseMapper
  • 強大的 CRUD 操作 :內置通用 Mapper、通用 Service,僅僅通過少量配置即可實現單表大部分 CRUD 操作,更有強大的條件構造器,滿足各類使用需求, 以后的簡單的增刪改查, 它不用自己寫了!
  • 支持 Lambda 形式調用 :通過 Lambda 表達式,方便的編寫各類查詢條件,無需再擔心字段寫錯
  • 支持主鍵自動生成 :支持多達 4 種主鍵策略(內含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解決主鍵問題
  • 支持 ActiveRecord 模式 :支持 ActiveRecord 形式調用,實體類只需繼承 Model 類即可進行強大的 CRUD 操作
  • 支持自定義全局通用操作 :支持全局通用方法注入( Write once, use anywhere )
  • 內置代碼生成器 :采用代碼或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 層代碼,支持模板引擎,更有超多自定義配置等您來使用,可插拔的方式(自動幫你生成代碼)
  • 內置分頁插件 :基于 MyBatis 物理分頁,開發者無需關心具體操作,配置好插件之后,寫分頁等同于普通 List 查詢
  • 分頁插件支持多種數據庫 :支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多種數據庫
  • 內置性能分析插件 :可輸出 Sql 語句以及其執行時間,建議開發測試時啟用該功能,能快速揪出慢查詢
  • 內置全局攔截插件 :提供全表 delete 、 update 操作智能分析阻斷,也可自定義攔截規則,預防誤操作

快速入門

地址: https://baomidou.com/guide/quick-start.html
使用第三方組件

  • 導入對應依賴
  • 研究如何讓編寫配置
  • 代碼如何編寫
  • 提高拓展

步驟

創建數據庫

mybatis_plus

創建 user表

DROP TABLE IF EXISTS user;CREATE TABLE user (id BIGINT(20) NOT NULL COMMENT '主鍵ID',name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',age INT(11) NULL DEFAULT NULL COMMENT '年齡',email VARCHAR(50) NULL DEFAULT NULL COMMENT '郵箱',PRIMARY KEY (id) );真實開發過程中, version(樂觀鎖)、delete(邏輯刪除)、gmt_create、gm_modified

其對應的數據庫 Data 腳本如下:

DELETE FROM user;INSERT INTO user (id, name, age, email) VALUES (1, 'Jone', 18, 'test1@baomidou.com'), (2, 'Jack', 20, 'test2@baomidou.com'), (3, 'Tom', 28, 'test3@baomidou.com'), (4, 'Sandy', 21, 'test4@baomidou.com'), (5, 'Billie', 24, 'test5@baomidou.com');

創建SpringBoot項目

mybatis_plus

導入依賴

<!--數據庫驅動--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--mybatis-plus-boot-starter是自己開發的, 并非官方--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.0.5</version></dependency>

說明: 我們使用mybatis-plus可以節省我們大量代碼, 盡量不要導入mybtis和mybatis-plus! 版本差異

連接數據庫

spring.datasource.username=root spring.datasource.data-password=123456 spring.datasource.url=jdbc:mysql://cdb-q9atzwrq.bj.tencentcdb.com:10167/mybatis_plus?useSSL=false&amp;useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver # serverTimezone=GMT 時區 8.0以上版本需要添加否則會報錯

傳統項目結構對比使用mybatis-plus之后

  • pojo-dao(連接mybatis, 配置mapper.xml文件)service-controller
  • 使用mybatis-plus之后
  • pojo
  • mapper接口
package cn.com.codingce.mapper;import cn.com.codingce.pojo.User; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; import org.springframework.stereotype.Repository;/*** 在對應的Mapper上實現基本接口BaseMapper* @author xzMa*/ @Mapper @Repository public interface UserMapper extends BaseMapper<User> {//所有的CRUD操作都已經編寫完成 }
  • 使用
package cn.com.codingce;import cn.com.codingce.mapper.UserMapper; import cn.com.codingce.pojo.User; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest;import java.util.List;@SpringBootTest class MybatisPlusApplicationTests {@Autowiredprivate UserMapper userMapper;/*wrapper條件構造器, 這里我們先不用 null//查詢全部用戶*/@Testvoid contextLoads() {List<User> users = userMapper.selectList(null);users.forEach(System.out::println);}}

思考問題

  • SQL誰幫我們寫好了? MyBatis-Plus都寫好了
    方法哪里來? MyBatis-Plus都寫好了

配置日志

我們所有的SQL是不可見的, 我們希望知道它是怎么執行的, 所以我們必須要看日志
(真正上線, 在下)

# 配置日志 mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

CRUD拓展

Insert

@Testvoid testInsert() {User user = new User();user.setName("掌上編程");user.setAge(19);user.setEmail("2460798168@qq.com");userMapper.insert(user);}

數據庫插入的id的默認值為:全局的唯一id

主鍵的策略

分布式系統唯一id生成:

默認@TableId(type = IdType.ID_WORKER)private Long id;

雪花算法:snowflake是Twitter開源的分布式ID生成算法,結果是一個long型的ID。其核心思想是:使用41bit作為毫秒數,10bit作為機器的ID(5個bit是數據中心,5個bit的機器ID),12bit作為毫秒內的流水號(意味著每個節點在每毫秒可以產生 4096 個 ID),最后還有一個符號位,永遠是0。具體實現的代碼可以參看https://github.com/twitter/snowflake。

主鍵自增

我們需要配置主鍵自增

  • 實體類字段上 @TableId(type = IdType.AUTO)

  • 數據庫字段一定要自增!

  • 再次測試插入即可

其他源碼檢測

public enum IdType {AUTO(0), //數據庫id自增NONE(1), //未設置主鍵INPUT(2), //手動輸入ID_WORKER(3),//默認的全局idUUID(4), //全局唯一id uuidID_WORKER_STR(5); //ID_WORKER 字符串表示法private int key;private IdType(int key) {this.key = key;}public int getKey() {return this.key;} }

更新操作

@Testvoid testUpdate() {User user = new User();//通過條件自動拼接動態sqluser.setId(1L);user.setEmail("21211@qq.com");int i = userMapper.updateById(user);System.out.println(i);}

自動填充

創建時間、更改時間! 這些操作一遍都是自動化完成的, 我們不希望手動更新!
阿里巴巴開發手冊:所有的數據表:gm_create、 gmt_modified 幾乎所有的表都需要配置上!而且需要自動化!

方式一 數據庫級別

  • 在表中新增字段create_time、 update_time

package cn.com.codingce.pojo;import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;import java.util.Date;/*** @author xzMa*/ @Data @AllArgsConstructor @NoArgsConstructor public class User {@TableId(type = IdType.AUTO)private Long id;private String name;private Integer age;private String email;private Date createTime;private Date updateTime;}

方式二:代碼級別

數據庫的時間默認值去掉

直接在實體類中

package cn.com.codingce.pojo;import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;import java.util.Date;/*** @author xzMa*/ @Data @AllArgsConstructor @NoArgsConstructor public class User {@TableId(type = IdType.AUTO)private Long id;private String name;private Integer age;private String email;@TableField(fill = FieldFill.INSERT)private Date createTime;@TableField(fill = FieldFill.INSERT_UPDATE)private Date updateTime;}

MyMetaObjectHandler

package cn.com.codingce.handler;import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.reflection.MetaObject; import org.springframework.stereotype.Component;import java.util.Date;/*** 自己寫的處理器* @author xzMa*/ @Slf4j @Component //一定不要把我們的處理器加到IOC中 public class MyMetaObjectHandler implements MetaObjectHandler {//插入時的填充策略@Overridepublic void insertFill(MetaObject metaObject) {log.info("Start insert fill ...");//String fieldName, Object fieldVal, MetaObject metaObjectthis.setFieldValByName("createTime", new Date(), metaObject);this.setFieldValByName("updateTime", new Date(), metaObject);}//更新時的填充策略@Overridepublic void updateFill(MetaObject metaObject) {log.info("Start update fill ...");this.setFieldValByName("updateTime", new Date(), metaObject);} }

樂觀鎖

在面試過程中, 我們經常會被問到的樂觀鎖, 悲觀鎖! 這個其實非常簡單!

樂觀鎖:樂觀鎖( Optimistic Locking ) 相對悲觀鎖而言,樂觀鎖假設認為數據一般情況下不會造成沖突,所以在數據進行提交更新的時候,才會正式對數據的沖突與否進行檢測,如果發現沖突了,則讓返回用戶錯誤的信息,讓用戶決定如何去做。
故名思意十分樂觀, 它總是認為不會出現問題, 無論干什么都不去上鎖! 如果出現問題, 再次更新新值測試(version new version)

悲觀鎖:故名思意十分悲觀, 它總認為總是出現問題, 無論干什么都會上鎖! 再去操作!

樂觀鎖機制:

  • 取出記錄記錄, 獲取當前version
  • 更新時, 帶上這個version
  • 執行更新時, set version = new Version where version = oldVersion
  • 如果version不對, 就更新失敗
---A update user set name = "zhangshangbiancheng", version = version + 1 where id = 2 and version = 1---B 線程搶先完成, 這個時候 version = 2 會導致A修改失敗! update user set name = "zhangshangbiancheng", version = version + 1 where id = 2 and version = 1

測試MP樂觀鎖插件

  • 給數據庫中添加version字段

  • 我們對實體類添加對應的字段
@Version //樂觀鎖Version注解private Integer version;
  • 注冊組件
package cn.com.codingce.config;import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor; import org.mybatis.spring.annotation.MapperScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.transaction.annotation.EnableTransactionManagement;@EnableTransactionManagement //掃描我們的mapper文件夾 @MapperScan("cn.com.codingce.mapper") @Configuration //配置類 public class MyBatisPlusConfig {//注冊樂觀鎖插件@Beanpublic OptimisticLockerInterceptor optimisticLockerInterceptor() {return new OptimisticLockerInterceptor();}}
  • 測試
@Testvoid testOptimisticLocker() {//查詢用戶信息User user = userMapper.selectById(1L);//修改用戶信息user.setName("xzMhehe");user.setEmail("codingce@ce.com");//執行更新操作userMapper.updateById(user);}/*** 測試樂觀鎖失敗 多線程下*/@Testvoid testOptimisticLocker2() {//線程1User user = userMapper.selectById(1L);user.setName("xzMhehe111");user.setEmail("codingce@ce.com");//模擬另外一個線程執行了插隊操作User user2 = userMapper.selectById(1L);user2.setName("xzMhehe222");user2.setEmail("codingce@ce.com");userMapper.updateById(user2);//自旋鎖來多次嘗試提交userMapper.updateById(user); //如果沒有樂觀鎖就會覆蓋插隊線程的值!}

查詢操作

@Testpublic void select() {User user = userMapper.selectById(1L);System.out.println(user);}@Testpublic void selectBatchIds() {List<User> users = userMapper.selectBatchIds(Arrays.asList(1L, 2L, 3L));users.forEach(System.out::println);}//條件查詢 map@Testpublic void testSelectByBathIds() {HashMap<String, Object> map = new HashMap<>();//自定義要查詢map.put("name", "xzMhehe222");map.put("age", 12);List<User> userList = userMapper.selectByMap(map);userList.forEach(System.out::println);}

分頁查詢

分頁在網站使用的十分之多

  • 原始的limit進行分頁
  • pageHelper第三方插件
  • MP其實也內置了分頁插件

如何使用

配置攔截器組件

//Spring boot方式 @Configuration @MapperScan("com.baomidou.cloud.service.*.mapper*") public class MybatisPlusConfig {@Beanpublic PaginationInterceptor paginationInterceptor() {return new PaginationInterceptor();} }
  • 直接使用Page插件即可
/*** 測試分頁*/@Testpublic void testPage() {//current參數一:當前頁//參數二:頁面大小Page<User> page = new Page<>(1, 5);IPage<User> userIPage = userMapper.selectPage(page, null);page.getRecords().forEach(System.out::println);}

基本刪除操作

//真刪@Testpublic void testDelete() {userMapper.deleteById(1L);}//批量刪除@Testpublic void testDeleteBatchId() {userMapper.deleteBatchIds(Arrays.asList(1L, 2L, 3L));}//通過map刪除@Testpublic void testDeleteMap() {HashMap<String, Object> map = new HashMap<>();map.put("name", "xzMhehe");userMapper.deleteByMap(map);}

我們在工作中會遇到一些問題:邏輯刪除

邏輯刪除

物理刪除:從數據庫中直接刪除
邏輯刪除:在數據庫中沒有移除,而是通過一個變量讓他失效! deleted = 0 =>deleted = 1
管理員可以查看刪除記錄!防止數據丟失,類似于回收站

  • 在數據庫中添加deleted字段

  • 在實體類中添加屬性
@TableField //邏輯刪除private Integer deleted;
  • 配置
//邏輯刪除組件@Beanpublic ISqlInjector sqlInjector() {return new LogicSqlInjector();} mybatis-plus.global-config.db-config.logic-delete-value=1 mybatis-plus.global-config.db-config.logic-not-delete-value=0

性能分析插件

在平時開發中, 會遇到一些慢sql. 測試!druid
MP也提供性能分析插件, 如果超過這個時間停止運行!

  • 導入插件
@Bean@Profile({"dev", "test"}) //設置 dev text 環境開啟, 保障我們的效率public PerformanceInterceptor performanceInterceptor() {PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();// 在工作中, 不允許用戶等待performanceInterceptor.setMaxTime(500); //ms 設置sql執行的最大時間, 如果超過了則不執行performanceInterceptor.setFormat(true); //開啟格式化輸出return performanceInterceptor;}
  • 測試使用

條件構造器

十分重要 Wrapper

  • 測試1
@Testvoid contextLoads() {//查詢條件name和郵箱不為空的用戶, 年齡大于等于12的用戶QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.isNotNull("name").isNotNull("email").ge("age", 12);userMapper.selectList(wrapper).forEach(System.out::println); //對比Map}
  • 測試2
@Testpublic void Test() {//查詢名字 全棧自學社區QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.eq("name", "全棧自學社區");userMapper.selectList(wrapper).forEach(System.out::println);} @Testpublic void Test3() {//年齡在20~30歲之間的人QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.between("age", 20, 30);Integer count = userMapper.selectCount(wrapper);System.out.println(count);userMapper.selectList(wrapper).forEach(System.out::println);}@Testpublic void Test4() {//名字中不包含QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.notLike("name", "e").likeRight("email", "t"); //左和右 %t% likeRight("email", "t") t%List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);maps.forEach(System.out::println);}@Testpublic void Test5() {//id在子查詢查出來QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.inSql("id", "select id from user where id < 3");List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);maps.forEach(System.out::println);}@Testpublic void Test6() {//排序QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.orderByDesc("id");List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);maps.forEach(System.out::println);}

代碼自動生成器

dao pojo service controller 都是自動生成

package cn.com.codingce.generator;import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.generator.AutoGenerator; import com.baomidou.mybatisplus.generator.config.DataSourceConfig; import com.baomidou.mybatisplus.generator.config.GlobalConfig; import com.baomidou.mybatisplus.generator.config.PackageConfig; import com.baomidou.mybatisplus.generator.config.StrategyConfig; import com.baomidou.mybatisplus.generator.config.po.TableFill; import com.baomidou.mybatisplus.generator.config.rules.DateType; import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;import java.util.ArrayList;public class CodeGenerator {public static void main(String[] args) {// 1、創建代碼生成器AutoGenerator mpg = new AutoGenerator();// 2、全局配置GlobalConfig gc = new GlobalConfig();//當前的項目路徑String projectPath = System.getProperty("user.dir");//所有代碼都會生成到 /src/main/java 路徑下gc.setOutputDir(projectPath + "/src/main/java");gc.setAuthor("小馬Coding");gc.setOpen(false); //生成后是否打開資源管理器gc.setFileOverride(false); //重新生成時文件是否覆蓋gc.setServiceName("%sService"); //去掉Service接口的首字母Igc.setIdType(IdType.ID_WORKER_STR); //主鍵策略gc.setDateType(DateType.ONLY_DATE);//定義生成的實體類中日期類型gc.setSwagger2(true);//開啟Swagger2模式mpg.setGlobalConfig(gc);// 3、數據源配置DataSourceConfig dsc = new DataSourceConfig();dsc.setUrl("jdbc:mysql://cdb-q9atzwrq.bj.tencentcdb.com:10167/codingstudy?useUnicode=true&characterEncoding=utf-8&useSSL=false");dsc.setDriverName("com.mysql.jdbc.Driver");dsc.setUsername("root");dsc.setPassword("123456");dsc.setDbType(DbType.MYSQL);mpg.setDataSource(dsc);// 4、包配置PackageConfig pc = new PackageConfig();pc.setModuleName("blog");pc.setParent("cn.com.codingce");pc.setController("controller");pc.setEntity("pojo");pc.setService("service");pc.setMapper("mapper");mpg.setPackageInfo(pc);// 5、策略配置StrategyConfig strategy = new StrategyConfig();//strategy.setInclude("ze_user");//設置要映射的表名//strategy.setInclude("ze_user", "ze_course");//可設置多個strategy.setInclude("ze_user");//設置要映射的表名strategy.setNaming(NamingStrategy.underline_to_camel);//數據庫表映射到實體的命名策略strategy.setTablePrefix("ze_");//設置表前綴不生成strategy.setColumnNaming(NamingStrategy.underline_to_camel);//數據庫表字段映射到實體的命名策略strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter鏈式操作strategy.setRestControllerStyle(true); //restful api風格控制器strategy.setControllerMappingHyphenStyle(true); //url中駝峰轉連字符//strategy.setLogicDeleteFieldName("deleted"); //邏輯刪除字段//自動填充配置//TableFill gmtCreate = new TableFill("gmt_create", FieldFill.INSERT);//TableFill gmtModified = new TableFill("gmt_modified", FieldFill.INSERT_UPDATE);//ArrayList<TableFill> tableFills = new ArrayList<>();//tableFills.add(gmtCreate);//tableFills.add(gmtModified);//strategy.setTableFillList(tableFills);mpg.setStrategy(strategy);// 6、執行mpg.execute();} }

項目地址

https://github.com/xzMhehe/codingce-java/tree/master/mybatis_plus

總結

以上是生活随笔為你收集整理的【Java萌新】MyBatis-Plus案例的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。