MyBatis-Plus筆記(入門)

故事我忘了°發表於2021-04-17
作者:故事我忘了
個人微信公眾號:程式猿的月光寶盒
MyBatis-Plus筆記(入門)

官方文件

https://mybatis.plus/guide/

本篇基於springboot,mybatis Plus的版本為3.4.2

本篇對應的github地址

https://github.com/monkeyKinn/StudyMyBatisPlus

覺得有用給個Star哦~~~~

Star

Star

Star

建庫建表

#建立使用者表
CREATE TABLE user (
    id BIGINT(20) PRIMARY KEY NOT NULL COMMENT '主鍵',
    name VARCHAR(30) DEFAULT NULL COMMENT '姓名',
    age INT(11) DEFAULT NULL COMMENT '年齡',
    email VARCHAR(50) DEFAULT NULL COMMENT '郵箱',
    manager_id BIGINT(20) DEFAULT NULL COMMENT '直屬上級id',
    create_time DATETIME DEFAULT NULL COMMENT '建立時間',
    CONSTRAINT manager_fk FOREIGN KEY (manager_id)
        REFERENCES user (id)
)  ENGINE=INNODB CHARSET=UTF8;

#初始化資料:
INSERT INTO user (id, name, age, email, manager_id
	, create_time)
VALUES (1087982257332887553, '大boss', 40, 'boss@baomidou.com', NULL
		, '2019-01-11 14:20:20'),
	(1088248166370832385, '王天風', 25, 'wtf@baomidou.com', 1087982257332887553
		, '2019-02-05 11:12:22'),
	(1088250446457389058, '李藝偉', 28, 'lyw@baomidou.com', 1088248166370832385
		, '2019-02-14 08:31:16'),
	(1094590409767661570, '張雨琪', 31, 'zjq@baomidou.com', 1088248166370832385
		, '2019-01-14 09:15:15'),
	(1094592041087729666, '劉紅雨', 32, 'lhm@baomidou.com', 1088248166370832385
		, '2019-01-14 09:48:16');

引入依賴

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <scope>runtime</scope>
    </dependency>

    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <optional>true</optional>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
      <exclusions>
        <exclusion>
          <groupId>org.junit.vintage</groupId>
          <artifactId>junit-vintage-engine</artifactId>
        </exclusion>
      </exclusions>
    </dependency>

    <dependency>
      <groupId>com.baomidou</groupId>
      <artifactId>mybatis-plus-boot-starter</artifactId>
      <version>3.4.2</version>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13</version>
      <scope>test</scope>
    </dependency>

配置檔案

spring.application.name=MyBatisPlus
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mp?useSSL=false&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=admin

建立實體類

@Data
public class User{
    /** 主鍵 */
    private Long id;
    /** 姓名 */
    private String name;
    /** 年齡 */
    private Integer age;
    /** 郵件 */
    private String email;
    /** 直屬上級id */
    private Long managerId;
    /** 建立時間 */
    private LocalDateTime createTime;
}

建立mapper介面

public interface UserMapper extends BaseMapper<User> {
}

啟動類上加上註解

@SpringBootApplication
// 注意這裡的包掃描路徑 要寫到mapper所在的包名上
@MapperScan("com.jsc.mybatisplus.mapper")
public class MyBatisPlusApplication {

    public static void main(String[] args) {
        SpringApplication.run(MyBatisPlusApplication.class, args);
    }

}

建立測試類

@SpringBootTest
@RunWith(SpringRunner.class)
class MyBatisPlusApplicationTests {
	// 後面會用到,此為建立條件構造器
    private QueryWrapper<User> query = Wrappers.query();
    @Autowired
    private UserMapper userMapper;
     @Test
    void selectAllTest() {
        List<User> users = userMapper.selectList(null);
        Assertions.assertEquals(5,users.size());
        users.forEach(System.out::println);
    }

}

以上 ,入門練手

通用mapper新增方法

配置檔案加上日誌輸出

spring.application.name=MyBatisPlus
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mp?useSSL=false&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=admin


#日誌輸出配置
logging.level.root=warn
#只想看這個包裡的sql日誌 trace是最低階別
logging.level.com.jsc.mybatisplus.mapper=trace

建立測試類

	@Test
    void insertTest() {
        User user = new User();
        user.setName("老金");
        user.setAge(18);
        // 沒有email 預設不給插入 沒有id 是因為預設雪花id
        user.setManagerId(1087982257332887553L);
        user.setCreateTime(LocalDateTime.now());

        int rows = userMapper.insert(user);
        System.out.println("影響行數: " + rows);
    }

常用註解

@TableName("表名") //在實體類上,用來當db中表和實體類名不一致時候,指定表
@TableId //在欄位上,用來指定對應的主鍵,當資料庫中的主鍵不是id命名時,實體類也不是id時用
@TableField("欄位名") //在實體類上,用來指定對應的欄位名

排除非表欄位的三種方式

transient //關鍵字 無法被序列化(存到磁碟)
static //關鍵字  只有一份 屬於類
@TableField(exit=false) //預設是true,資料庫中存在

查詢

基本查詢

	@Test
    void selectByIdTest() {
        // 根據id查詢
        User user = userMapper.selectById(1382699085670719489L);
        // User(id=1382699085670719489, name=老金, age=18, email=null, managerId=1087982257332887553, createTime=2021-04-15T22:15:26)
        System.out.println(user);
    }
	@Test
    void selectBatchIdsTest() {
        // 根據id批量查詢
        List<Long> ids = Arrays.asList(1382699085670719489L, 1094592041087729666L, 1094590409767661570L);
        List<User> users = userMapper.selectBatchIds(ids);
        users.forEach(System.out::println);
    }

    @Test
    void selectByMapTest() {
        Map<String, Object> map = new HashMap<>();
        // map.put("name", "老金");
        // map的key是資料庫中的欄位
        map.put("age", 27);
        // WHERE name = ? AND age = ?
        // WHERE age = ?
        List<User> users = userMapper.selectByMap(map);
        System.out.println(users);
    }

以條件構造器為引數

	@Test
    void selectByWrapper0() {
        /*
         * 1、名字中包含雨並且年齡小於40
         * name like '%雨%' and age<40
         * 條件構造器
         */

        query.like("name", "雨").lt("age", 40);
        List<User> users = userMapper.selectList(query);
        users.forEach(System.out::println);
    }

    @Test
    void selectByWrapper1() {
        /*
         * 名字中包含雨年並且齡大於等於20且小於等於40並且email不為空
         * name like '%雨%' and age between 20 and 40 and email is not null
         */
        query.like("name", "雨").between("age", 20, 40).isNotNull("email");
        List<User> users = userMapper.selectList(query);
        users.forEach(System.out::println);
    }

    @Test
    void selectByWrapper2() {
        /*
         * 名字為王姓或者年齡大於等於25,按照年齡降序排列,年齡相同按照id升序排列
         *  name like '王%' or age>=25 order by age desc,id asc
         */
        query.like("name", "王").or().ge("age", 18).orderByDesc("age").orderByAsc("id");
        List<User> users = userMapper.selectList(query);
        users.forEach(System.out::println);
    }

	@Test
    void selectByWrapper3() {
        /*
         * 建立日期為2019年2月14日並且直屬上級為名字為王姓 --函式開頭用apple拼接sql
         * date_format(create_time,'%Y-%m-%d')='2019-02-14' and manager_id in (select id from user where name like '王%')
         */
        query.apply("date_format(create_time,'%Y-%m-%d')={0}", "2019-02-14")
                .inSql("manager_id", "select id from user where name like '王%'");

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

	@Test
    void selectByWrapper4() {
        /*
         * 名字為王姓並且(年齡小於40或郵箱不為空)
         * name like '王%' and (age<40 or email is not null)
         */
        query.likeRight("name","王").and(qw->qw.lt("age",40 ).or().isNotNull("email"));

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

	@Test
    void selectByWrapper5() {
        /*
         * 名字為王姓或者(年齡小於40並且年齡大於20並且郵箱不為空)
         * name like '王%' or (age<40 and age>20 and email is not null)
         */
        query.likeRight("name","王").or(qw->
                qw.lt("age",40 )
                        .gt("age",20).isNotNull("email"));
        List<User> users = userMapper.selectList(query);
        users.forEach(System.out::println);
    }

	@Test
    void selectByWrapper6() {
        /*
         * (年齡小於40或郵箱不為空)並且名字為王姓,nested 正常巢狀 不帶 AND 或者 OR
         * (age<40 or email is not null) and name like '王%'
         */
        query.nested(qw->
                qw.lt("age",40).or().isNotNull("email")).likeRight("name","王");
        List<User> users = userMapper.selectList(query);
        users.forEach(System.out::println);
    }

	@Test
    void selectByWrapper7() {
        /*
         * 年齡為30、31、34、35
         *   age in (30、31、34、35)
         */
        query.in("age",18,30,31,34,35);
        List<User> users = userMapper.selectList(query);
        users.forEach(System.out::println);
    }

    

select中欄位不全部出現的查詢

	@Test
    void selectByWrapper8() {
        /*
         * 10、名字中包含雨並且年齡小於40(需求1加強版)
                    第一種情況:  select id,name -- 就用select("")
	                            from user
	                            where name like '%雨%' and age<40
                    第二種情況:  select id,name,age,email
	                            from user
	                            where name like '%雨%' and age<40
         */

        query.like("name","雨").lt("age",40).select("name","age");
        List<User> users = userMapper.selectList(query);
        users.forEach(System.out::println);
    }

 	@Test
    void selectByWrapper9() {
        /*
         * 10、名字中包含雨並且年齡小於40(需求1加強版)
                    第一種情況:  select id,name -- 就用select("")
	                            from user
	                            where name like '%雨%' and age<40
                    第二種情況:  select id,name,age,email -- 就用select("")
	                            from user
	                            where name like '%雨%' and age<40
         */

        query.like("name","雨").lt("age",40).select(User.class,info ->
                !info.getColumn().equals("create_time")
                        &&!info.getColumn().equals("manager_id"));
        List<User> users = userMapper.selectList(query);
        users.forEach(System.out::println);
    }

條件構造器中condition的作用(執行條件.可理解為條件查詢)

@Test
    void selectByCondition() {
        // 根據引數條件查詢
        // String name = "金";
        String name = "玉";
        String age = "18";
        // 如果不為空,就有後面的條件加入到sql中
        query.like(StringUtils.isNotBlank(name),"name",name)
                .eq(StringUtils.isNotBlank(age),"age",age);
        List<User> users = userMapper.selectList(query);
        users.forEach(System.out::println);
    }

建立條件構造器時,傳入實體物件

 	@Test
    void selectByWrapperEntity() {
        /*
         * 使用場景:
         *  1、通過實體傳過來資料
         *  2.不想永理科這樣的構造器,預設是等值的
         *          如果不想等值,在實體類中加上註解
         *          @TableField(condition=SqlCondition.like)
         *                     小於的話就是="%s&lt;#{%s}"
         *                                 列名<列值
         */
        User whereUser = new User();
        whereUser.setName("老金");
        whereUser.setAge(18);
        query = Wrappers.query(whereUser);
        // query.like("name", "雨").lt("age", 40);
        List<User> users = userMapper.selectList(query);
        users.forEach(System.out::println);
    }

條件構造器中allEq用法

@Test
    void selectByWrapperAllEq() {
        HashMap<String, Object> params = new HashMap<>();
        params.put("name", "王天風");
        params.put("age", null);
		
        // 後面的false,是忽略null值的列
        // query.allEq(params,false);
        // 前面一個函式是過濾用的  比如這裡就是不包含age列
        query.allEq((k,v)->!"age".equals(k),params);
        List<User> users = userMapper.selectList(query);
        users.forEach(System.out::println);
    }

其他以條件構造器為引數的方法

    @Test
    void selectByWrapperMaps() {
        /*
        * 使用場景:
        *  1.當表特別的多色時候只要查少數 幾列,返回一個map,而不是屬性大部分都為空的實體
        *  2.返回的是統計結果
        *       按照直屬上級分組,查詢每組的 平均年齡、最小齡、最大年齡。
        *           並且只取年齡總和小於500的組。
        *               select
        *                   avg(age) avg_age,
        *                   min(age) min_age,
        *                   max(age) max_age
        *               from user
        *               group by manager_id --上級id分組
        *               having sum(age) <500 --只有總和小於500
        * */
        // 第一種情況
        // query.like("name","雨").lt("age",40).select("id","name");

        // 第二種情況
        query.select("avg(age) avg_age","min(age) min_age","max(age) max_age")
                .groupBy("manager_id")
                .having("sum(age) < {0}",500);
        List<Map<String, Object>> users = userMapper.selectMaps(query);
        users.forEach(System.out::println);
    }

    @Test
    void selectByWrapperObjs() {
        query.select("id","name").like("name","雨").lt("age",40);
        // 返回第一列的值 只返回一列的時候用
        List<Object> users = userMapper.selectObjs(query);
        users.forEach(System.out::println);
    }

	@Test
    void selectByWrapperCounts() {
        // 不能設定查詢的列名了
        query.like("name","雨").lt("age",40);
        // 查總記錄數
        Integer count = userMapper.selectCount(query);
        System.out.println(count);
    }

    @Test
    void selectByWrapperOne() {
        // 不能設定查詢的列名了
        query.like("name","老金").lt("age",40);
        // 只返回一條資料
        User user = userMapper.selectOne(query);
        System.out.println(user);
    }

lambda條件構造器

    @Test
    void selectLambda() {
        // 建立方式
        // QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        // LambdaQueryWrapper<User> userLambdaQueryWrapper1 = new LambdaQueryWrapper<>();
        LambdaQueryWrapper<User> lambdaQueryWrapper = Wrappers.lambdaQuery();

        // 好處: 防止誤寫欄位名
        
        // where name like '%雨%' and age<40
        // 前面是類名 後面是get方法,表示屬性
        lambdaQueryWrapper.like(User::getName, "雨").lt(User::getAge, 40);

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

    @Test
    void selectLambda1() {
        /*
         * 名字為王姓並且(年齡小於40或郵箱不為空)
         * name like '王%' and (age<40 or email is not null)
         */
        LambdaQueryWrapper<User> lambdaQueryWrapper = Wrappers.lambdaQuery();
        // 好處: 防止誤寫欄位名
        // 前面是類名 後面是get方法,表示屬性
        lambdaQueryWrapper.likeRight(User::getName,"王").and(lqw->lqw.lt(User::getAge,40).or().isNotNull(User::getEmail));

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

	@Test
    void selectLambda2() {
        /*
         * 名字為王姓並且(年齡小於40或郵箱不為空)
         * name like '王%' and (age<40 or email is not null)
         */
        // 3.0.7新增建立方式
        List<User> users = new LambdaQueryChainWrapper<>(userMapper)
                .like(User::getName, "雨").ge(User::getAge, 20).list();

        users.forEach(System.out::println);
    }

使用條件構造器的自定義SQL

方式1,sql寫在介面中

在mapper介面中自定義
public interface UserMapper extends BaseMapper<User> {
    // 引數的註解是固定的 ew 就是WRAPPER的值
    @Select("select * from user ${ew.customSqlSegment}")
    List<User> selectAll(@Param(Constants.WRAPPER) Wrapper<User> wrapper);
}

測試類
 	@Test
    void selectAllCustomize() {
        // 自定義的方法

        LambdaQueryWrapper<User> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.likeRight(User::getName,"王").and(lqw->lqw.lt(User::getAge,40).or().isNotNull(User::getEmail));
        List<User> users = userMapper.selectAll(lambdaQueryWrapper);
        users.forEach(System.out::println);
    }
方式2,sql寫在mapper中

在配置檔案中配置介面對應的mapper檔案

#設定掃描路徑
mybatis-plus.mapper-locations=mapper/*.xml
在resources下建mapper包

省略圖

建立xml檔案 UserMapper.xml
<?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="com.jsc.mybatisplus.mapper.UserMapper">
  <select id="selectAll" resultType="com.jsc.mybatisplus.entity.User">
<!--     引數的註解是固定的 ew 就是WRAPPER的值-->
    select * from user ${ew.customSqlSegment}
  </select>
</mapper>

介面中的sql註解就不用了

分頁查詢

首先明確一點,mybatis分頁rowbounds確實實現了分頁,但是是邏輯分頁/記憶體分頁,他先把資料全查出來,load到memory中,然後給你你想要的,換句話說,是海選...你懂我意思吧...可想而知,資料爆炸的時代,你得給多記憶體,記憶體不要錢嗎,海選可貴,選擇又多,多了換一批時間就 ,一個道理~

Mp就提供了物理分頁的外掛,解決上述問題

既然是外掛,肯定要配置

1.建立配置包 config

省略

2.建立配置類

package com.jsc.mybatisplus.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * mybatis的分頁配置
 *
 * @author 金聖聰
 * @version v1.0
 * @email jinshengcong@163.com
 * @date Created in 2021/04/16 15:48
 */
@Configuration
public class MyBatisPlusConfig {
    // 新版廢棄
    // @Bean
    // public PaginationInterceptor paginationInterceptor() {
    //     return new PaginationInterceptor();
    // }
    //-------------------------------------------------
    /*
      未測試
      新的分頁外掛,一緩和二緩遵循mybatis的規則,
      需要設定 MybatisConfiguration#useDeprecatedExecutor = false
      避免快取出現問題(該屬性會在舊外掛移除後一同移除)
     */
    /* @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }

    @Bean
    public ConfigurationCustomizer configurationCustomizer() {
        return configuration -> configuration.setUseDeprecatedExecutor(false);
    }*/
    //***************************************************
    /**
     * 註冊外掛
     *  依賴以下版本+
     *      <dependency>
     *         <groupId>com.baomidou</groupId>
     *         <artifactId>mybatis-plus-boot-starter</artifactId>
     *         <version>3.4.1</version>
     *     </dependency>
     * @return com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor 攔截器
     * @author 金聖聰
     * @email jinshengcong@163.com
     * Modification History:
     * Date         Author        Description        version
     *--------------------------------------------------------*
     * 2021/04/16 15:56    金聖聰     修改原因            1.0
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        // 0.建立一個攔截器
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

        // 1. 新增分頁外掛
        PaginationInnerInterceptor pageInterceptor = new PaginationInnerInterceptor();
        // 2. 設定請求的頁面大於最大頁後操作,true調回到首頁,false繼續請求。預設false
        pageInterceptor.setOverflow(false);
        // 3. 單頁分頁條數限制,預設無限制
        pageInterceptor.setMaxLimit(500L);
        // 4. 設定資料庫型別
        pageInterceptor.setDbType(DbType.MYSQL);
        // 5.新增內部攔截器
        interceptor.addInnerInterceptor(pageInterceptor);

        return interceptor;
    }
}

3.測試類測試

	@Test
    void selectPage() {
        //分頁查詢
        /*
         * 1、名字中包含雨並且年齡小於40
         * name like '%雨%' and age<40
         * 條件構造器
         */
        LambdaQueryWrapper<User> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.ge(User::getAge,18);

        // 泛型是實體類 , 當前頁數 預設是1,從1開始,不是0。每頁最多多少條

        // 第一種用selectPage方法,返回的是 Page<User> userPage
        /*Page<User> page = new Page<>(1, 2);
        Page<User> userPage = userMapper.selectPage(page, lambdaQueryWrapper);

        System.out.println("總頁數: "+userPage.getPages());
        System.out.println("總記錄數: "+userPage.getTotal());
        userPage.getRecords().forEach(System.out::println);*/

        // 第二種用 selectMapsPage方法,返回的是 IPage<Map<String, Object>>
        // 如果第一個引數還是用的上面的page,此時page胡報錯
        // 解決方案:
        //      把page 轉成對應的型別IPage<Map<String, Object>>
        //          因為新版後(3.4.1+), 更改了原始碼 給他設定了具體型別
        IPage<Map<String, Object>> page1 = new Page<>(4, 2);
        IPage<Map<String, Object>> mapIPage = userMapper.selectMapsPage(page1, lambdaQueryWrapper);

        System.out.println("總頁數: "+mapIPage.getPages());
        System.out.println("總記錄數: "+mapIPage.getTotal());
        List<Map<String, Object>> records = mapIPage.getRecords();
        records.forEach(System.out::println);
    }

多表聯查分頁

實際開發中有的查詢是多表聯查的,這樣就不能用上面的兩個方法了,但是不甘心使用傳統的寫法,,那怎麼辦?

用xml自定義查詢方法

在介面中建立自定義方法

// 自定義分頁
IPage<User> selectUserPage(Page<User> page,@Param(Constants.WRAPPER) Wrapper<User> wrapper);

xml中配置

<select id="selectUserPage" resultType="com.jsc.mybatisplus.entity.User">
    <!--     引數的註解是固定的 ew 就是WRAPPER的值-->
    <!--    沒有什麼改變,但是可以自己多表聯查-->
    select *
    from user ${ew.customSqlSegment}
  </select>

測試

    @Test
    void selectPageCustomize() {
        //分頁查詢
        /*
         * 1、名字中包含雨並且年齡小於40
         * name like '%雨%' and age<40
         * 條件構造器
         */
        LambdaQueryWrapper<User> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.ge(User::getAge,18);

        // 泛型是實體類 , 當前頁數 預設是1,從1開始,不是0。每頁最多多少條

        // 第一種用selectPage方法,返回的是 Page<User> userPage
        Page<User> page = new Page<>(1, 2);
        IPage<User> userIPage = userMapper.selectUserPage(page, lambdaQueryWrapper);

        System.out.println("總頁數: "+userIPage.getPages());
        System.out.println("總記錄數: "+userIPage.getTotal());
        userIPage.getRecords().forEach(System.out::println);
    }

更新

根據id更新

	@Test
    void UpdateById() {
        User user = new User();
        user.setId(1382713714941648898L);
        user.setName("小陳");
        int i = userMapper.updateById(user);
        System.out.println("影響記錄數: "+i);
    }

以條件構造器作為引數的更新方法

	private UpdateWrapper<User> update = Wrappers.update();

	@Test
    void UpdateByWrapper() {
        User user = new User();
        // user.setId(1382713714941648898L);
        user.setName("小金");

        update.eq("name","老金");
        int i = userMapper.update(user,update);
        System.out.println("影響記錄數: "+i);
    }

 	@Test
    void UpdateByWrapper1() {
        User whereUser = new User();
        // user.setId(1382713714941648898L);
        whereUser.setName("小金");
        // 可以直接把實體傳進去
        update = new UpdateWrapper<>(whereUser);
        update.eq("age",18);

        User user = new User();
        user.setAge(21);
        int i = userMapper.update(user,update);
        System.out.println("影響記錄數: "+i);
    }


條件構造器中set方法的使用

	@Test
    void UpdateByWrapper2() {
        // 不建立實體傳入,直接在條件中set
        update.eq("name","小金").set("name","老金");

        int i = userMapper.update(null,update);
        System.out.println("影響記錄數: "+i);
    }

用lambda語法更新

	@Test
    void UpdateByLambda() {
        LambdaUpdateWrapper<User> updateLambda = Wrappers.lambdaUpdate();
        updateLambda.eq(User::getName,"老金").set(User::getName,"小金");
        int i = userMapper.update(null,updateLambda);
        System.out.println("影響記錄數: "+i);
    }
	
	@Test
    void UpdateByLambdaChain() {
        // 鏈式呼叫
        boolean update = new LambdaUpdateChainWrapper<User>(userMapper).eq(User::getName, "小金").set(User::getName, "老金").update();
        System.out.println(update?"成功":"失敗");
    }

刪除

根據id刪除

    @Test
    void deleteById() {
        int i = userMapper.deleteById(1382699085670719489L);
        System.out.println("影響行數: "+ i);
    }

其他普通方法刪除

    @Test
    void deleteByMap() {
        Map<String, Object> columnMap = new HashMap<>();
        columnMap.put("name","小金");
        columnMap.put("age","18");
        // WHERE name = ? AND age = ?
        int i = userMapper.deleteByMap(columnMap);

        System.out.println("影響行數: "+ i);
    }

    @Test
    void deleteByBatchIds() {
        List<Long> longs = Arrays.asList(1383035889074692097L, 1383035840634646530L);
        int i = userMapper.deleteBatchIds(longs);
        // WHERE id IN ( ? , ? )
        // 根據id批量刪除
        System.out.println("影響行數: " + i);
    }

以條件構造器為引數的刪除方法

   @Test
    void deleteByWrapper() {
        LambdaQueryWrapper<User> lambdaQuery = Wrappers.lambdaQuery();
        lambdaQuery.eq(User::getId, "1383037094597267457");
        int delete = userMapper.delete(lambdaQuery);
        System.out.println("影響行數: " + delete);
    }

AR模式(ActiveRecord)

AR模式簡介

活動記錄,是一個領域模型模式,

特點:

​ 一個模型類對應資料庫中的一個表

​ 模型類的一個例項對應表中的一個記錄

簡單來說就是通過實體類物件對錶進行增刪改查操作,方便開發人員的開發

MP中AR模式的實現

1.首先實體類要繼承一個抽象類Model<泛型是這個類本身>

用lombok的@Data後,繼承別的類後會有個警告,用註解@EqualsAndHashCode(callSuper=false)可以消除警告,再新增一個系列化id

````@EqualsAndHashCode(callSuper=false)``就是不呼叫父類,

但是,別的時候 大部分需要父類的一些屬性作為等值比較的

@Data
@EqualsAndHashCode(callSuper = false)
public class User extends Model<User> {
    private static final long serialVersionUID = 7589930312778081895L;
    /** 主鍵 */
    private Long id;
    /** 姓名 */
    private String name;
    /** 年齡 */
    private Integer age;
    /** 郵件 */
    private String email;
    /** 直屬上級id */
    private Long managerId;
    /** 建立時間 */
    private LocalDateTime createTime;
}

2.必須存在原始mapper的介面,並繼承baseMapper介面

    @Test
    void ARInsertTest() {
        User user = new User();
        user.setName("xx");
        user.setAge(0);
        user.setManagerId(1088248166370832385L);
        user.setCreateTime(LocalDateTime.now());

        // 直接insert,自己插自己可還行
        boolean insert = user.insert();
        System.out.println(insert?"成功":"失敗");
    }

    @Test
    void ARSelectByIdTest1() {
        // 不需要引數,直接實體上設定
        // 直接查,自己查自己可還行
        User user = new User();
        user.setId(1383044106274050049L);

        User user1 = user.selectById();
        System.out.println(user1);
    }
// 查出來的都是新的物件,並沒有把值設定到原來的物件上

    @Test
    void ARUpdateTest() {
        User user = new User();
        user.setId(1383044106274050049L);
        user.setName("xxoo");
        user.setAge(16);
        user.setManagerId(1383035808669888513L);
        user.setCreateTime(LocalDateTime.now());

        // 自己操作
        boolean b = user.updateById();
        System.out.println(b?"success":"fail");

    }

    @Test
    void ARDeleteTest() {
        User user = new User();
        user.setId(1383044106274050049L);

        // 自己操作
        boolean b = user.deleteById();
        System.out.println(b?"success":"fail");

    }




主鍵策略

MP支援的主鍵策略介紹

0.基於雪花演算法(預設的)

1.區域性主鍵策略實現

通過在實體類上id的註解@TableId(type=IdType.XXX)設定

AUTO 資料庫ID自增
NONE 無狀態,該型別為未設定主鍵型別(註解裡等於跟隨全域性,全域性裡約等於 INPUT)
INPUT insert前自行set主鍵值
ASSIGN_ID 分配ID(主鍵型別為Number(Long和Integer)或String)(since 3.3.0),使用介面IdentifierGenerator的方法nextId(預設實現類為
DefaultIdentifierGenerator雪花演算法)
ASSIGN_UUID 分配UUID,主鍵型別為String(since 3.3.0),使用介面IdentifierGenerator的方法nextUUID(預設default方法)
ID_WORKER 分散式全域性唯一ID 長整型型別 (please use ASSIGN_ID)
UUID 32位UUID字串 (please use ASSIGN_UUID)
ID_WORKER_STR 分散式全域性唯一ID 字串型別 (please use ASSIGN_ID)

2.全域性主鍵策略實現

在配置檔案中設定

mybatis-plus.global-config.db-config.id-type=uuid

如果區域性策略和全域性策略都設定了 ,就近原則

MP配置

基本配置

基本的在官網,這裡不做過多記錄

https://mybatis.plus/config/#基本配置

進階配置

https://mybatis.plus/config/#configuration

mapUnderscoreToCamelCase這個配置不能和configLocation一起出現,會報錯

欄位驗證策略可以看一下~

不過一般都是預設的NOT_NULL

not_empty (欄位為"")也是忽略

ignored 就是空的也插入 但是有風險 在更新的時候

但是在實體類中,

個別的,可以在欄位上配置@TableField(stragegy=FieldStrategy.NOT_EMPTY),就是欄位為""的時候也忽略

同樣的就近原則

tablePrefix 表名字首 全域性設定

mybatis-plus.global-config.db-config.table-prefix=

通用Service

  1. 新建service包

  2. 新建介面UserService

  3. 繼承IService<T> 泛型寫所對應的實體類

  4. 建立service的實現包impl

  5. 建立UserServiceImp

  6. 繼承ServiceImpl<UserMapper, User> 第一個蠶食數索要操作的mapper介面,第二個引數是對應的實體類

  7. 實現剛才的介面UserService,並給上@Service的註解

    UserService.java

    public interface UserService extends IService<User> {
    }
    

    ServiceImpl.java

    @Service
    public class UserServiceImp extends ServiceImpl<UserMapper, User> implements UserService{
    }
    

基本方法

    @Autowired
    private UserService userService;

    @Test
    public void testService() {
        User one = userService.getOne(Wrappers.<User>lambdaQuery().gt(User::getAge,25),false);
        System.out.println(one);
    }

批量操作方法

    @Test
    public void batchTest() {
        // 批量
        User user = new User();
        user.setName("犀利");
        user.setAge(12);

        User user1 = new User();
        user1.setName("犀利1");
        user1.setAge(121);

        List<User> users = Arrays.asList(user1, user);
        userService.saveBatch(users);
    }

鏈式呼叫方法

	@Test
    public void chainTest() {
        // 查大於25的
        List<User> list = userService.lambdaQuery().gt(User::getAge, 25).list();
        list.forEach(System.out::println);
    }

    @Test
    public void chainTest1() {
        // 更新
        boolean update = userService.lambdaUpdate().eq(User::getName, "小陳").set(User::getName, "小玉").update();
        System.out.println(update?"success":"fail");
    }

    @Test
    public void chainTest2() {
        // 直接刪除
        boolean update = userService.lambdaUpdate().eq(User::getName, "xx").remove();
        System.out.println(update?"success":"fail");
    }

相關文章