天天看點

mybatisplus快速使用MP入門主鍵更新自動填充樂觀鎖查詢删除性能分析條件查詢

快速使用

  • MP入門
  • 主鍵
  • 更新
  • 自動填充
  • 樂觀鎖
  • 查詢
  • 删除
  • 性能分析
  • 條件查詢

MP入門

mybatis

增求,簡化開發

  1. 建立資料庫和表,添加資料
    create database mybatis_plus;
    user mybatis_plus;
    
    
    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)
    );
    
    DELETE FROM user;
    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]');
               
  2. 建立

    SpringBoot

    工程
  3. 引入

    mybatis-plus

    相關依賴
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.0.5</version>
    </dependency>
    
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
               
  4. 配置資料庫對應的屬性
    # mysql8+ 用com.mysql.cj.jdbc.Driver 和 serverTimezone=GMT%2B8時區
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/mybatisplus?serverTimezone=GMT%2B8
    spring.datasource.username=root
    spring.datasource.password=
               
  5. 編寫實體類
    package com.jerry.mpdemo.pojo;
    
    import lombok.Data;
    
    @Data
    public class User {
        private Long id;
        private String name;
        private Integer age;
        protected String email;
    }
               
  6. 編寫

    Mapper

    檔案
    package com.jerry.mpdemo.mapper;
    
    
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.jerry.mpdemo.pojo.User;
    
    public interface UserMapper extends BaseMapper<User> {
    }
               
  7. 掃描

    mapper

    @SpringBootApplication
    @MapperScan("com.jerry.mpdemo.mapper")
    public class MpdemoApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(MpdemoApplication.class, args);
        }
    
    }
               
  8. 測試
    @SpringBootTest
    class MpdemoApplicationTests {
    
        @Autowired
        private UserMapper userMapper;
    
        @Test
        void contextLoads() {
            List<User> users = userMapper.selectList(null);
            users.forEach((User user) -> {
                System.out.println(user);
            });
        }
    
    }
               

主鍵

MP自動生成19位的ID

自動增長

@Data
public class User {
    @TableId(type = IdType.AUTO) // 加注解
    private Long id;
    private String name;
    private Integer age;
    protected String email;
}
           

更新

@Test
public void updateUser() {
    User user = new User();
    user.setId(2L);
    user.setAge(21);
    int row = userMapper.updateById(user);
    System.out.println(row);
}
           

自動填充

  1. 表添加兩個字段
    • create_time

    • update_time

  2. 實體類添加屬性
    private Date createTime;
    private Date updateTime;
               
  3. 添加注解

    @TableField(fill = FieldFill.INSERT)

  4. 實作接口

    MetaObjectHandler

    @Component // 放在spring容器中,很重要!!
    public class MyMetaObjectHandler implements MetaObjectHandler {
        // 使用mp實作更新操作,這個方法執行
        @Override
        public void updateFill(MetaObject metaObject) {
            this.setFieldValByName("updateTime", new Date(), metaObject);
        }
    
        // 使用mp實作添加操作,這個方法執行
        @Override
        public void insertFill(MetaObject metaObject) {
            this.setFieldValByName("createTime", new Date(), metaObject);
            this.setFieldValByName("updateTime", new Date(), metaObject);
        }
    }
               
  5. 正常添加更新即可,不用再寫這兩個字段

樂觀鎖

主要解決丢失更新,如果不考慮事務隔離性,産生讀問題:

  1. 髒讀
  2. 不可重複讀
  3. 幻讀s

寫問題:丢失更新問題:

比如

id = 1

salary = 500

,兩個人都想修改這個工資

兩人都需要開啟事務,

A

500

改為了

800

B

500

改成

200

事務最終需要送出,如果

A

先送出了事務,表中工資就會變為

800

B

随後送出事務,工資變為了

200

,此時

A

看到了就會發現不對勁,

自己送出的資料被覆寫了。正常應該是

B

800

改成

200

解決方法:

  1. 悲觀鎖:串行,

    A

    用的時候别人不能用,隔離級别max
  2. 樂觀鎖:擷取目前version,

    A

    送出時比較版本号和資料庫中的是否一樣,然後将版本号+1,

    B

    在看到版本号不一樣就無法送出
  3. 添加字段,作為版本号
  4. 實體類添加版本号

    private Integer version;

  5. 添加

    @Version

    注解
    @Version
    private Integer version;
               
  6. 配置樂觀鎖的插件
    @Configuration
    @MapperScan("com.jerry.mpdemo.mapper")
    public class MpConfig {
    
        @Bean
        public OptimisticLockerInterceptor optimisticLockerInterceptor() {
            return new OptimisticLockerInterceptor();
        }
    }
               
  7. 測試
    @Test
    public void addUser() {
        User user = new User();
        user.setAge(18);
        user.setName("xxx");
        user.setEmail("[email protected]");
    
        int insert = userMapper.insert(user);
        System.out.println("insert: ---------- " + insert);
    }
    
    // 樂觀鎖必須先查再改
    @Test
    public void testLock() {
        User user = userMapper.selectById(1355352835969359878L);
        user.setAge(666);
        int row = userMapper.updateById(user);
        System.out.println(row);
    }
               

查詢

多個

id

的批量查詢

@Test
public void testSelect() {
    List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3)); // 将1,2,3查詢出來
    for (User user : users) {
        System.out.println(user);
    }
}
           

分頁查詢:

  1. 配置分頁插件
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
               
  2. 使用
    @Test
    public void testPage() {
        Page<User> page = new Page<>(1, 3); // 目前頁, 每頁記錄數
        IPage<User> userIPage = userMapper.selectPage(page, null);
        System.out.println(userIPage.getCurrent());
        System.out.println(userIPage.getSize());
        System.out.println(userIPage.getTotal());
        System.out.println(userIPage.getPages());
        List<User> records = userIPage.getRecords();
        for (User record : records) {
            System.out.println(record);
        }
    }
               

删除

實體删除

@Test
public void testDelete() {
    int count = userMapper.deleteById(1L);
    System.out.println("成功删除了" + count + "行");
}
           

批量删除

@Test
public void testBatchDelete() {
    userMapper.deleteBatchIds(Arrays.asList(1, 2, 3));
}
           

邏輯删除,資料真實存在,但是查詢不出來

  1. 添加deleted字段
  2. 添加字段并且添加注解

    @TableLogic

  3. 配置邏輯删除插件
    @Bean
    public ISqlInjector sqlInjector() {
        return new LogicSqlInjector();
    }
               

性能分析

@Bean
@Profile({"dev", "test"})
public PerformanceInterceptor performanceInterceptor() {
    PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
    performanceInterceptor.setMaxTime(200); // 超過100ms的sql不執行
    performanceInterceptor.setFormat(true);
    return performanceInterceptor;
}
           

條件查詢

@Test
public void testSelectQuery() {
    QueryWrapper queryWrapper = new QueryWrapper();
    // ge大于等于 gt大于 le小于等于 lt小于
    queryWrapper.ge("age", 20);
    List<User> list = userMapper.selectList(queryWrapper);
    list.forEach((user) -> System.out.println(user));

    // eq等于 ne不等于

    // between在範圍内 like模糊查詢會->自動幫忙傳遞%

    // orderBy排序

    // last拼接到sql的最後,有sql注入風險

    // 查詢指定列
    queryWrapper.select("id", "name", "age");


}
           

繼續閱讀