<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          MyBatis-Plus常用API全套教程,看完沒有不懂的

          共 15420字,需瀏覽 31分鐘

           ·

          2021-04-06 13:32


          今天來分享一篇,MyBatis-Plus常用API全套教程,MyBatis在持久層框架中還是比較火的,雖然MyBatis可以直接在xml中通過SQL語句操作數(shù)據(jù)庫,很是靈活。但正其操作都要通過SQL語句進(jìn)行,就必須寫大量的xml文件,很是麻煩。MyBatis-Plus就很好的解決了這個(gè)問題。


          官網(wǎng):https://baomidou.com


          MyBatis-plus官方文檔 簡化 MyBatis !

          創(chuàng)建數(shù)據(jù)庫

          數(shù)據(jù)庫名為mybatis_plus

          創(chuàng)建表

          創(chuàng)建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)
          );
          INSERT INTO user (id, name, age, email) VALUES
          (1, 'Jone', 18, '[email protected]'),
          (2, 'Jack', 20, '[email protected]'),
          (3, 'Tom', 28, '[email protected]'),
          (4, 'Sandy', 21, '[email protected]'),
          (5, 'Billie', 24, '[email protected]');

          注意:-- 真實(shí)開發(fā)中往往都會(huì)有這四個(gè)字段,version(樂觀鎖)、deleted(邏輯刪除)、gmt_create(創(chuàng)建時(shí)間)、gmt_modified(修改時(shí)間)

          初始化項(xiàng)目

          使用SpringBoot器 初始化!

          導(dǎo)入依賴

          <!-- 數(shù)據(jù)庫驅(qū)動(dòng) -->
          <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          </dependency>
          <!-- lombok -->
          <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
          </dependency>
          <!-- mybatis-plus -->
          <!-- mybatis-plus 是自己開發(fā),并非官方的!-->
          <dependency>
          <groupId>com.baomidou</groupId>
          <artifactId>mybatis-plus-boot-starter</artifactId>
          <version>3.0.5</version>
          </dependency>

          注意:盡量不要同時(shí)導(dǎo)入 mybatis 和 mybatis-plus!避免版本的差異造成無法預(yù)知的問題。

          連接數(shù)據(jù)庫

          創(chuàng)建application.yml

          spring:
          profiles:
          active: dev
          datasource:
          # 驅(qū)動(dòng)不同 mysql 5 com.mysql.jdbc.Driver
          # mysql 8 com.mysql.cj.jdbc.Driver、需要增加時(shí)區(qū)的配置serverTimezone=GMT%2B8
          url: jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
          driver-class-name: com.mysql.cj.jdbc.Driver
          username: root
          password: root

          業(yè)務(wù)代碼

          實(shí)體類

          @Data
          @AllArgsConstructor
          @NoArgsConstructor
          public class User {
          private Long id;
          private String name;
          private Integer age;
          private String email;
          }

          mapper接口

          import com.baomidou.mybatisplus.core.mapper.BaseMapper;
          import com.kuang.pojo.User;
          import org.springframework.stereotype.Repository;
          // 在對(duì)應(yīng)的Mapper上面繼承基本的類 BaseMapper
          @Repository // 代表持久層
          public interface UserMapper extends BaseMapper<User> {
          // 所有的CRUD操作都已經(jīng)編寫完成了
          }

          注意點(diǎn),我們需要在主啟動(dòng)類上去掃描我們的mapper包下的所有接口
          @MapperScan(“com.kwhua.mapper”)

          測(cè)試

          @SpringBootTest
          class MybatisPlusApplicationTests {
          // 繼承了BaseMapper,所有的方法都來自己父類
          // 我們也可以編寫自己的擴(kuò)展方法!
          @Autowired
          private UserMapper userMapper;
          @Test
          void contextLoads() {
          // 參數(shù)是一個(gè) Wrapper ,條件構(gòu)造器,這里我們先設(shè)置條件為空,查詢所有。
          List<User> users = userMapper.selectList(null);
          users.forEach(System.out::println);
          }
          }

          所有數(shù)據(jù)輸出


          配置日志

          我們所有的sql現(xiàn)在是不可見的,我們希望知道它是怎么執(zhí)行的,所有我們要配置日志的輸出
          application.yml文件添加日志配置

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

          查看執(zhí)行sql的日志信息


          三.Mybatis-plus的CRUD

          1.插入操作

          // 測(cè)試插入
          @Test
          public void testInsert(){
          User user = new User();
          user.setName("kwhua_mybatis-plus_insertTest");
          user.setAge(15);
          user.setEmail("[email protected]");

          int result = userMapper.insert(user); // 幫我們自動(dòng)生成id
          System.out.println(result); // 受影響的行數(shù)
          System.out.println(user); // 看到id會(huì)自動(dòng)填充。}

          看到id會(huì)自動(dòng)填充。數(shù)據(jù)庫插入的id的默認(rèn)值為:全局的唯一id

          主鍵生成策略

          1)主鍵自增
          1、實(shí)體類字段上 @TableId(type = IdType.AUTO)
          2、數(shù)據(jù)庫id字段設(shè)置為自增!


          3、再次測(cè)試(可以看到id值比上次插入的大1)


          id的生成策略源碼解釋

          public enum IdType {
          AUTO(0), // 數(shù)據(jù)庫id自增
          NONE(1), // 未設(shè)置主鍵
          INPUT(2), // 手動(dòng)輸入
          ID_WORKER(3), // 默認(rèn)的方式,全局唯一id
          UUID(4), // 全局唯一id uuid
          ID_WORKER_STR(5); //ID_WORKER 字符串表示法
          }

          以上不再逐一測(cè)試。

          更新操作

           @Test
          public void testUpdate(){
          User user = new User();
          // 通過條件自動(dòng)拼接動(dòng)態(tài)sql
          user.setId(1302223874217295874L);
          user.setName("kwhua_mybatis-plus_updateTest");
          user.setAge(20);
          // 注意:updateById 但是參數(shù)是一個(gè)對(duì)象!
          int i = userMapper.updateById(user);
          System.out.println(i);
          }

          自動(dòng)填充

          創(chuàng)建時(shí)間、修改時(shí)間!這兩個(gè)字段操作都是自動(dòng)化完成的,我們不希望手動(dòng)更新!
          阿里巴巴開發(fā)手冊(cè):所有的數(shù)據(jù)庫表都要配置上gmt_create、gmt_modified!而且需要自動(dòng)化!
          方式一:數(shù)據(jù)庫級(jí)別(工作中一般不用)
          1、在表中新增字段 gmt_create, gmt_modified


          2、把實(shí)體類同步

          private Date gmtCreate;
          private Date gmtModified;

          3、再次查看


          方式二:代碼級(jí)別
          1、刪除數(shù)據(jù)庫的默認(rèn)值、更新操作!


          2、實(shí)體類字段屬性上需要增加注解

              // 字段添加填充內(nèi)容
          @TableField(fill = FieldFill.INSERT)
          private Date gmt_create;

          @TableField(fill = FieldFill.INSERT_UPDATE)
          private Date gmt_modified;

          3、編寫處理器來處理這個(gè)注解即可!

          @Slf4j
          @Component // 一定不要忘記把處理器加到IOC容器中!
          public class MyMetaObjectHandler implements MetaObjectHandler {
          // 插入時(shí)的填充策略
          @Override
          public void insertFill(MetaObject metaObject) {
          log.info("start insert fill.....");
          // setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject
          this.setFieldValByName("gmt_create",new Date(),metaObject);
          this.setFieldValByName("gmt_modified",new Date(),metaObject);
          }

          // 更新時(shí)的填充策略
          @Override
          public void updateFill(MetaObject metaObject) {
          log.info("start update fill.....");
          this.setFieldValByName("gmt_modified",new Date(),metaObject);
          }
          }

          4、測(cè)試插入和更新,檢查時(shí)間變化。

          樂觀鎖

          樂觀鎖 : 故名思意,十分樂觀,它總是認(rèn)為不會(huì)出現(xiàn)問題,無論干什么不去上鎖!如果出現(xiàn)了問題,
          再次更新值測(cè)試
          悲觀鎖:故名思意,十分悲觀,它總是認(rèn)為總是出現(xiàn)問題,無論干什么都會(huì)上鎖!再去操作!

          樂觀鎖實(shí)現(xiàn)方式:

          取出記錄時(shí),獲取當(dāng)前version
          更新時(shí),帶上這個(gè)version
          執(zhí)行更新時(shí), set version = newVersion where version = oldVersion
          如果version不對(duì),就更新失敗

          樂觀鎖:1、先查詢,獲得版本號(hào) version = 1
          -- A
          update user set name = "kwhua", version = version + 1
          where id = 2 and version = 1
          -- B 線程搶先完成,這個(gè)時(shí)候 version = 2,會(huì)導(dǎo)致 A 修改失敗!
          update user set name = "kwhua", version = version + 1
          where id = 2 and version = 1

          樂觀鎖測(cè)試
          1、給數(shù)據(jù)庫中增加version字段!


          2、實(shí)體類加對(duì)應(yīng)的字段

              @Version //樂觀鎖Version注解
          private Integer version;

          3、注冊(cè)組件

          // 掃描我們的 mapper 文件夾
          @MapperScan("com.kwhua.mapper")
          @EnableTransactionManagement
          @Configuration // 配置類
          public class MyBatisPlusConfig {
          // 注冊(cè)樂觀鎖插件
          @Bean
          public OptimisticLockerInterceptor optimisticLockerInterceptor() {
          return new OptimisticLockerInterceptor();
          }
          }

          4、測(cè)試

          // 測(cè)試樂觀鎖成功!
          @Test
          public void testOptimisticLocker(){
          // 1、查詢用戶信息
          User user = userMapper.selectById(1L);
          // 2、修改用戶信息
          user.setName("kwhua");
          user.setEmail("[email protected]");
          // 3、執(zhí)行更新操作
          userMapper.updateById(user);
          }

          version字段已經(jīng)由1變成了2

          // 測(cè)試樂觀鎖失敗!多線程下
          @Test
          public void testOptimisticLocker2(){

          // 線程 1
          User user = userMapper.selectById(1L);
          user.setName("kwhua111");
          user.setEmail("[email protected]");

          // 模擬另外一個(gè)線程執(zhí)行了插隊(duì)操作
          User user2 = userMapper.selectById(1L);
          user2.setName("kwhua222");
          user2.setEmail("[email protected]");
          userMapper.updateById(user2);

          // 自旋鎖來多次嘗試提交!
          userMapper.updateById(user); // 如果沒有樂觀鎖就會(huì)覆蓋插隊(duì)線程的值!
          }

          可以看到線程1執(zhí)行更新失敗

          查詢操作

          // 測(cè)試查詢
          @Test
          public void testSelectById(){
          User user = userMapper.selectById(1L);
          System.out.println(user);
          }

          // 測(cè)試批量查詢!
          @Test
          public void testSelectByBatchId(){
          List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
          users.forEach(System.out::println);
          }

          // 按條件查詢之一使用map操作
          @Test
          public void testSelectByBatchIds(){
          HashMap<String, Object> map = new HashMap<>();
          // 自定義要查詢
          map.put("name","kwhua");
          map.put("age",15);

          List<User> users = userMapper.selectByMap(map);
          users.forEach(System.out::println);
          }

          6.1分頁查詢
          1、配置攔截器組件

          // 分頁插件
          @Bean
          public PaginationInterceptor paginationInterceptor() {
          return new PaginationInterceptor();
          }

          2、直接使用Page對(duì)象即可!

          // 測(cè)試分頁查詢
          @Test
          public void testPage(){
          // 參數(shù)一:當(dāng)前頁
          // 參數(shù)二:頁面大小
          Page<User> page = new Page<>(2,5);
          userMapper.selectPage(page,null);
          page.getRecords().forEach(System.out::println);
          System.out.println(page.getTotal());
          }

          物理刪除

          // 測(cè)試刪除
          @Test
          public void testDeleteById(){
          userMapper.deleteById(1L);
          }

          // 通過id批量刪除
          @Test
          public void testDeleteBatchId(){
          userMapper.deleteBatchIds(Arrays.asList(2L,3L));
          }

          // 通過map刪除
          @Test
          public void testDeleteMap(){
          HashMap<String, Object> map = new HashMap<>();
          map.put("name","kwhua");
          userMapper.deleteByMap(map);
          }

          邏輯刪除

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

          1、在數(shù)據(jù)表中增加一個(gè) deleted 字段


          2、實(shí)體類中增加屬性

           @TableLogic //邏輯刪除
          private Integer deleted;

          3、配置

              // 邏輯刪除組件!
          @Bean
          public ISqlInjector sqlInjector() {
          return new LogicSqlInjector();
          }

          配置文件配置

            global-config:
          db-config:
          logic-delete-value: 1
          logic-not-delete-value: 0

          4、測(cè)試
          測(cè)試刪除


          字段值也從0修改成了1


          測(cè)試查詢


          性能分析插件

          作用:性能分析攔截器,用于輸出每條 SQL 語句及其執(zhí)行時(shí)間
          MP也提供性能分析插件,如果超過這個(gè)時(shí)間就停止運(yùn)行!
          1、導(dǎo)入插件

          /**
          * SQL執(zhí)行效率插件
          */

          @Bean
          @Profile({"dev","test"})// 設(shè)置 dev test 環(huán)境開啟,保證我們的效率
          public PerformanceInterceptor performanceInterceptor() {
          PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
          performanceInterceptor.setMaxTime(100); //ms 設(shè)置sql執(zhí)行的最大時(shí)間,如果超過了則不執(zhí)行
          performanceInterceptor.setFormat(true);
          return performanceInterceptor;
          }

          條件構(gòu)造器(Wrapper)

          .isNotNull .gt

          @Test
          void contextLoads() {
          // 查詢name不為空的用戶,并且郵箱不為空的用戶,年齡大于等于12
          QueryWrapper<User> wrapper = new QueryWrapper<>();
          wrapper
          .isNotNull("name") //不為空
          .isNotNull("email")
          .ge("age",18);
          userMapper.selectList(wrapper).forEach(System.out::println); // 和我們剛才學(xué)習(xí)的map對(duì)比一下
          }

          .eq

           @Test
          void test2(){
          // 查詢名字kwhua
          QueryWrapper<User> wrapper = new QueryWrapper<>();
          wrapper.eq("name","kwhua");
          User user = userMapper.selectOne(wrapper); // 查詢一個(gè)數(shù)據(jù)用selectOne,查詢多個(gè)結(jié)果使用List 或者 Map
          System.out.println(user);
          }

          .between

          @Test
          void test3(){
          // 查詢年齡在 20 ~ 30 歲之間的用戶
          QueryWrapper<User> wrapper = new QueryWrapper<>();
          wrapper.between("age",20,30); // 區(qū)間
          Integer count = userMapper.selectCount(wrapper);// 查詢結(jié)果數(shù)
          System.out.println(count);
          }

          .like

           // 模糊查詢
          @Test
          void test4(){
          // 查詢名字中不帶e且 郵箱以t開頭的數(shù)據(jù)
          QueryWrapper<User> wrapper = new QueryWrapper<>();
          // 左 likelift %t ,右 likeRight t%
          wrapper
          .notLike("name","e")
          .likeRight("email","t");

          List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
          maps.forEach(System.out::println);
          }

          .insql

           // 模糊查詢
          @Test
          void test5(){

          QueryWrapper<User> wrapper = new QueryWrapper<>();
          // id 在子查詢中查出來
          wrapper.inSql("id","select id from user where id<3");

          List<Object> objects = userMapper.selectObjs(wrapper);
          objects.forEach(System.out::println);
          }

          .orderByAsc

          //測(cè)試六
          @Test
          void test6(){
          QueryWrapper<User> wrapper = new QueryWrapper<>();
          // 通過id進(jìn)行排序
          wrapper.orderByAsc("id");

          List<User> users = userMapper.selectList(wrapper);
          users.forEach(System.out::println);
          }

          代碼自動(dòng)生成器

          可以在test文件夾在創(chuàng)建一個(gè)java類

          // 代碼自動(dòng)生成器
          public class generateCode {
          public static void main(String[] args) {
          // 需要構(gòu)建一個(gè) 代碼自動(dòng)生成器 對(duì)象
          AutoGenerator mpg = new AutoGenerator();
          // 配置策略
          // 1、全局配置
          GlobalConfig gc = new GlobalConfig();
          String projectPath = System.getProperty("user.dir");
          gc.setOutputDir(projectPath+"/src/main/java");
          gc.setAuthor("kwhua");//作者名稱
          gc.setOpen(false);
          gc.setFileOverride(false); // 是否覆蓋
          gc.setIdType(IdType.ID_WORKER);
          gc.setDateType(DateType.ONLY_DATE);
          gc.setSwagger2(true);//實(shí)體屬性 Swagger2 注解

          // 自定義文件命名,注意 %s 會(huì)自動(dòng)填充表實(shí)體屬性!
          gc.setServiceName("%sService");
          gc.setControllerName("%sController");
          gc.setServiceName("%sService");
          gc.setServiceImplName("%sServiceImpl");
          gc.setMapperName("%sMapper");
          gc.setXmlName("%sMapper");

          mpg.setGlobalConfig(gc);

          //2、設(shè)置數(shù)據(jù)源
          DataSourceConfig dsc = new DataSourceConfig();
          dsc.setUrl("jdbc:mysql://localhost:3306/kwhua_test?
          useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8"
          );
          dsc.setDriverName("com.mysql.cj.jdbc.Driver");
          // dsc.setDriverName("com.mysql.jdbc.Driver"); //mysql5.6以下的驅(qū)動(dòng)
          dsc.setUsername("root");
          dsc.setPassword("root");
          dsc.setDbType(DbType.MYSQL);
          mpg.setDataSource(dsc);
          //3、包的配置
          PackageConfig pc = new PackageConfig();
          pc.setParent("com.kwhua"); //包名
          pc.setModuleName("model"); //模塊名
          pc.setEntity("entity");
          pc.setMapper("mapper");
          pc.setService("service");
          pc.setController("controller");
          mpg.setPackageInfo(pc);

          //4、策略配置
          StrategyConfig strategy = new StrategyConfig();
          strategy.setInclude("user","course"); // 設(shè)置要映射的表名
          strategy.setNaming(NamingStrategy.underline_to_camel);
          strategy.setColumnNaming(NamingStrategy.underline_to_camel);
          strategy.setEntityLombokModel(true); // 自動(dòng)lombok;
          strategy.setLogicDeleteFieldName("deleted");
          // 自動(dòng)填充配置
          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);
          // 樂觀鎖
          strategy.setVersionFieldName("version");
          //根據(jù)你的表名來建對(duì)應(yīng)的類名,如果你的表名沒有下劃線,比如test,那么你就可以取消這一步
          strategy.setTablePrefix("t_");
          strategy.setRestControllerStyle(true); //rest請(qǐng)求
          //自動(dòng)轉(zhuǎn)下劃線,比如localhost:8080/hello_id_2
          strategy.setControllerMappingHyphenStyle(true);
          mpg.setStrategy(strategy);
          mpg.execute(); //執(zhí)行
          }
          }

          執(zhí)行主方法即可生成對(duì)應(yīng)代碼

             
          -END-


          PS:歡迎在留言區(qū)留下你的觀點(diǎn),一起討論提高。如果今天的文章讓你有新的啟發(fā),歡迎轉(zhuǎn)發(fā)分享給更多人。

          Java后端編程交流群已成立

          公眾號(hào)運(yùn)營至今,離不開小伙伴們的支持。為了給小伙伴們提供一個(gè)互相交流的平臺(tái),特地開通了官方交流群。掃描下方二維碼備注 進(jìn)群 或者關(guān)注公眾號(hào) Java后端編程 后獲取進(jìn)群通道。

              

          —————END—————

              
          推薦閱讀:


               
                 
          最近面試BAT,整理一份面試資料Java面試BAT通關(guān)手冊(cè),覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫、數(shù)據(jù)結(jié)構(gòu)等等。
          獲取方式:關(guān)注公眾號(hào)并回復(fù) java 領(lǐng)取,更多內(nèi)容陸續(xù)奉上。
          明天見(??ω??)??
          瀏覽 39
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  一级A婬片试看2O分钟 | 美颜巨乳-熊猫成人网 | 一道本一二三区 | 狼友视频网址 | 中文字幕无码在线播放 |