天天看點

Mybatis-Plus高階

作者:Iliuhu

主鍵政策

Mybatis-Plus提供了一個注解@TableId, 該注解提供了各種的主鍵生成政策。
package com.demo;

import com.demo.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class PrimaryKeyTest {

    @Autowired
    private UserMapper userMapper;
}           
  • AUTO:跟随資料庫表的主鍵遞增政策,前提資料庫表的主鍵設定為自增
package com.demo.domain;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;
}           
@Test
    void primary() {
        User user = new User();

        user.setName("Mary");
        user.setAge(35);
        user.setEmail("[email protected]");

        userMapper.insert(user);
    }           
  • INPUT:手動插入id,否則無法添加資料
package com.demo.domain;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    @TableId(type = IdType.INPUT)
    private Long id;
    private String name;
    private Integer age;
    private String email;
}           
package com.demo;

import com.demo.domain.User;
import com.demo.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class PrimaryKeyTest {

    @Autowired
    private UserMapper userMapper;

    @Test
    void primary() {
        User user = new User();

        // 手動設定ID
        user.setId(7L);
        user.setName("Mary");
        user.setAge(35);
        user.setEmail("[email protected]");

        userMapper.insert(user);
    }
}           
  • ASSIGN_ID

資料量很大,要進行分表:

1)水準拆分:按照資料量進行拆分

2)垂直拆分:按照字段進行拆分

Mybatis-Plus高階
    • 雪花算法:解決主鍵自增問題而生的
Mybatis-Plus高階
Mybatis-Plus高階
package com.demo.domain;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    @TableId(type = IdType.ASSIGN_ID) // ASSIGN_ID 雪花算法
    private Long id;
    private String name;
    private Integer age;
    private String email;
}           
// 插入的id是19位長度的十進制數,其實就是64位二進制得到的結果
    @Test
    void primary() {
        User user = new User();
        user.setName("Mary");
        user.setAge(35);
        user.setEmail("[email protected]");

        userMapper.insert(user);
    }           
  • NONE:不指定主鍵生成政策,跟随的是全局政策
mybatis-plus:
  global-config:
    db-config:
      id-type: ASSIGN_ID # 全局政策的預設值           
package com.demo.domain;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    @TableId(type = IdType.NONE) // 與不設定@TableId是一樣的,都使用的是全局政策
    private Long id;
    private String name;
    private Integer age;
    private String email;
}           
// 插入的id是19位長度的十進制數,其實就是64位二進制得到的結果
    @Test
    void primary() {
        User user = new User();
        user.setName("Mary");
        user.setAge(35);
        user.setEmail("[email protected]");

        userMapper.insert(user);
    }           
  • ASSIGN_UUID
UUID(Universally Unique Identifier)全局唯一辨別符,定義為一個字元串主鍵,采用32位數字組成。
Mybatis-Plus高階
package com.demo.domain;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    @TableId(type = IdType.ASSIGN_UUID)
    private String id;
    private String name;
    private Integer age;
    private String email;
}           
@Test
    void primary() {
        User user = new User();
        user.setName("Mary");
        user.setAge(35);
        user.setEmail("[email protected]");

        userMapper.insert(user);
    }           
Mybatis-Plus高階

id由bigint改為varchar(50)

分頁

分頁的本質就是需要設定一個攔截器,通過攔截器攔截SQL,通過在SQL語句的結尾添加limit關鍵字,來實作分頁的效果。
Mybatis-Plus高階
  • 分頁插件
package com.demo.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;

// 分頁插件
@Configuration
public class MybatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));

        return interceptor;
    }
}           
package com.demo;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.demo.domain.User;
import com.demo.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class PageTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    void selectPage() {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();

        // 指定分頁對象
        IPage<User> userPage = new Page<>(1, 3);

        // 執行查詢
        userMapper.selectPage(userPage, lambdaQueryWrapper);

        // 擷取分頁查詢的資訊
        System.out.println("目前頁:" + userPage.getCurrent());
        System.out.println("每頁顯示條數:" + userPage.getSize());
        System.out.println("總頁數:" + userPage.getPages());
        System.out.println("總條數:" + userPage.getTotal());
        System.out.println("分頁資料:" + userPage.getRecords());
    }
}           
  • 自定義分頁插件
package com.demo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.demo.domain.User;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper extends BaseMapper<User> {
    IPage<User> selectByName(IPage<User> page, String name);
}           
package com.demo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.demo.domain.User;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper extends BaseMapper<User> {
    IPage<User> selectByName(IPage<User> page, String name);
}           
package com.demo;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.demo.domain.User;
import com.demo.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class PageTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    void selectPage() {
        // 指定分頁對象
        IPage<User> userPage = new Page<>(1, 2);

        // 執行查詢
        userMapper.selectByName(userPage, "Mary");

        // 擷取分頁查詢的資訊
        System.out.println("目前頁:" + userPage.getCurrent());
        System.out.println("每頁顯示條數:" + userPage.getSize());
        System.out.println("總頁數:" + userPage.getPages());
        System.out.println("總條數:" + userPage.getTotal());
        System.out.println("分頁資料:" + userPage.getRecords());
    }
}           

ActiveRecord模式

ActiveRecord(活動記錄)是一種領域模型模式,特點是一個模型類對應關系型資料庫中的一個表,而模型類的一個執行個體對應表中的一行記錄,圍繞一個資料對象進行CRUD操作,需要讓實體類繼承Model類且實作主鍵指定方法。
package com.demo.domain;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User extends Model<User> {
    @TableId
    private Long id;
    private String name;
    private Integer age;
    private String email;
}           
package com.demo;

import com.demo.domain.User;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class ActiveRecordTest {

    // 添加
    @Test
    void activeRecordAdd() {
        User user = new User();
        user.setName("zhang");
        user.setAge(30);
        user.setEmail("[email protected]");

        user.insert();
    }

    // 删除
    @Test
    void activeRecordDelete() {
        User user = new User();
        user.setId(1653291729962430466L);

        user.deleteById();
    }

    // 修改
    @Test
    void activeRecordUpdate() {
        User user = new User();
        user.setId(7L);
        user.setAge(50);

        user.updateById();
    }

    // 查詢
    @Test
    void activeRecordSelect() {
        User user = new User();
        user.setId(7L);

        User result = user.selectById();
        System.out.println("result = " + result);
    }
}           

SimpleQuery工具類

Mybatis-Plus高階
package com.demo.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}           
  • list: 基于字段封裝集合
package com.demo;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.toolkit.SimpleQuery;
import com.demo.domain.User;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
public class SimpleQueryTest {

    @Test
    void testList() {
        List<Long> idList = SimpleQuery.list(new LambdaQueryWrapper<User>().eq(User::getName, "Mary"), User::getId);
        System.out.println("idList = " + idList);
    }
}           
package com.demo;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.toolkit.SimpleQuery;
import com.demo.domain.User;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.swing.text.html.Option;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;

@SpringBootTest
public class SimpleQueryTest {

    @Test
    void testList() {
        List<String> nameList = SimpleQuery.list(new LambdaQueryWrapper<User>().eq(User::getName, "Mary"), User::getName, new Consumer<User>() {
            @Override
            public void accept(User user) {
                Optional.of(user.getName()).map(String::toLowerCase).ifPresent(user::setName);
            }
        });

        System.out.println("nameList = " + nameList);
    }
}           
  • map
// 将所有元素封裝為Map
    @Test
    void testMap() {
        Map<Long, User> longUserMap = SimpleQuery.keyMap(new LambdaQueryWrapper<User>(), User::getId);
        System.out.println("longUserMap = " + longUserMap);
    }           
// 一條元素封裝為Map
    @Test
    void testMap() {
        Map<Long, User> longUserMap = SimpleQuery.keyMap(new LambdaQueryWrapper<User>().eq(User::getId, 1L), User::getId);
        System.out.println("longUserMap = " + longUserMap);
    }           
// 任意元素字段封裝為Map
    @Test
    void testMap() {
        Map<Long, String> map = SimpleQuery.map(new LambdaQueryWrapper<User>(), User::getId, User::getName);
        System.out.println("map = " + map);
    }           
  • Group
@Test
    void testGroup() {
        Map<String, List<User>> map = SimpleQuery.group(new LambdaQueryWrapper<User>(), User::getName);
        System.out.println("map = " + map);
    }           

邏輯删除

不是真的删除,增加一個字段來表示這個資料的狀态,實際上是更新資料的狀态。
Mybatis-Plus高階
package com.demo.domain;

import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
    // 增加一個狀态字段
    @TableLogic(value = "1", delval = "0")
    private Integer status;
}           
package com.demo;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.demo.domain.User;
import com.demo.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class LogicTest {

    @Autowired
    private UserMapper userMapper;

    @Test
    void logicDelete() {
        userMapper.deleteById(7L);
    }

    // 邏輯删除的資料,是查詢不出來的,除非status=0的條件才能查詢出資料
    @Test
    void logicSelect() {
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getId, 7L);

        User user = userMapper.selectOne(lambdaQueryWrapper);
        System.out.println("user = " + user);
    }
}           

[愛慕]全局配置邏輯删除

mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: status
      logic-delete-value: 0
      logic-not-delete-value: 1           
package com.demo.domain;

import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
    // 增加一個狀态字段
//    @TableLogic(value = "1", delval = "0")
    private Integer status;
}           

通用枚舉

表示一組資訊,這組資訊隻能從一些固定的值中進行選擇,不能随意寫,這種場景下,枚舉最合适。
package com.demo.domain;

import com.baomidou.mybatisplus.annotation.TableLogic;
import com.demo.enums.GenderEnum;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
    private Integer status;
    private GenderEnum gender;
}           
package com.demo.enums;

import com.baomidou.mybatisplus.annotation.EnumValue;

public enum GenderEnum {
    MAN(0, "男"),WOMAN(1, "女");

    // @EnumValue 解決資料庫的類型和枚舉類型沒辦法轉換,報錯的問題
    @EnumValue
    private Integer gender;
    private String genderName;

    GenderEnum(Integer gender, String genderName) {
        this.gender = gender;
        this.genderName = genderName;
    }
}           
package com.demo;

import com.demo.domain.User;
import com.demo.enums.GenderEnum;
import com.demo.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class EnumTest {

    @Autowired
    private UserMapper userMapper;

    @Test
    void enumTest() {
        User user = new User();
        user.setName("liu");
        user.setAge(29);
        user.setEmail("[email protected]");
        user.setStatus(1);
        user.setGender(GenderEnum.MAN);

        userMapper.insert(user);
    }
}           

字段類型處理器

Mybatis-Plus高階
實體類的Map類型和資料庫的varchar類型的互相轉換,需要字段類型處理器來完成。
Mybatis-Plus高階
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>fastjson</artifactId>
  <version>1.2.83</version>
</dependency>           
package com.demo.domain;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
import com.demo.enums.GenderEnum;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Map;

@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName(autoResultMap = true)
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
    private Integer status;
    private GenderEnum gender;
    @TableField(typeHandler = FastjsonTypeHandler.class)
    private Map<String, String> contact; // 聯系方式
}           
@Test
    void typeHandler() {
        User user = new User();
        user.setName("li");
        user.setAge(28);
        user.setEmail("[email protected]");
        user.setGender(GenderEnum.MAN);
        user.setStatus(1);

        HashMap<String, String> map = new HashMap<>();
        map.put("tel", "13888888999");
        map.put("phone", "010-12345678");

        user.setContact(map);

        userMapper.insert(user);
    }

    @Test
    void typeHandlerSelect() {
        List<User> users = userMapper.selectList(null);
        System.out.println("users = " + users);
    }           

自動填充功能

建立時間和更新時間可以設定為自動填充。
Mybatis-Plus高階
mybatis-plus:
  configuration:
    map-underscore-to-camel-case: true # 隻有設定了下劃線和小駝峰映射,才能和實體類完成映射           
設定MySQL的時區
-- 中國時區 東八區
set GLOBAL time_zone = '+8:00'           
目前工程環境的時區

url: jdbc:mysql://localhost:3306/mq?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useUnicode=true&useSSL=false

package com.demo.domain;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
import com.demo.enums.GenderEnum;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;
import java.util.Map;

@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName(autoResultMap = true)
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
    private Integer status;
    private GenderEnum gender;
    @TableField(typeHandler = FastjsonTypeHandler.class)
    private Map<String, String> contact; // 聯系方式
    // 設定時間,還要考慮時區因素(資料庫本身和目前工程環境的時區)
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
}           
package com.demo.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
public class MyMetaHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        setFieldValByName("createTime", new Date(), metaObject);
        setFieldValByName("updateTime", new Date(), metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        setFieldValByName("updateTime", new Date(), metaObject);
    }
}           
package com.demo;

import com.demo.domain.User;
import com.demo.enums.GenderEnum;
import com.demo.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.HashMap;

@SpringBootTest
public class FillTest {

    @Autowired
    private UserMapper userMapper;

    @Test
    void testFillInsert() {
        User user = new User();
        user.setName("wang");
        user.setAge(35);
        user.setEmail("[email protected]");
        user.setGender(GenderEnum.MAN);
        user.setStatus(1);
        HashMap<String, String> map = new HashMap<>();
        map.put("tel", "13888888999");
        map.put("phone", "010-12345678");
        user.setContact(map);

        userMapper.insert(user);
    }

    @Test
    void testFillUpdate() {
        // 1653386151156793346
        User user = new User();
        user.setId(1653386151156793346L);
        user.setName("wangwu");
        user.setAge(39);
        user.setEmail("[email protected]");
        user.setGender(GenderEnum.MAN);
        user.setStatus(1);
        HashMap<String, String> map = new HashMap<>();
        map.put("tel", "13888888999");
        map.put("phone", "010-12345678");
        user.setContact(map);

        userMapper.updateById(user);
    }
}           

防全表更新與删除插件

package com.demo.config;

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

// 分頁插件
@Configuration
public class MybatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
      	// 防全表更新與删除插件
        interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));

        return interceptor;
    }
}           

MybatisX逆向工程

Mybatis-Plus高階
Mybatis-Plus高階

MybatisX快速代碼生成

Mybatis-Plus高階
package com.demo.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;

import com.demo.domain.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper extends BaseMapper<User> {
    int deleteByNameAndAge(@Param("name") String name, @Param("age") Integer age);

    int updateNameByAge(@Param("name") String name, @Param("age") Integer age);

    List<User> selectAllByAgeBetween(@Param("beginAge") Integer beginAge, @Param("endAge") Integer endAge);
}           
<?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.demo.mapper.UserMapper">

    <resultMap id="BaseResultMap" type="com.demo.domain.User">
            <id property="id" column="id" jdbcType="BIGINT"/>
            <result property="name" column="name" jdbcType="VARCHAR"/>
            <result property="age" column="age" jdbcType="INTEGER"/>
            <result property="email" column="email" jdbcType="VARCHAR"/>
            <result property="status" column="status" jdbcType="INTEGER"/>
            <result property="gender" column="gender" jdbcType="INTEGER"/>
            <result property="contact" column="contact" jdbcType="VARCHAR"/>
            <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
            <result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
    </resultMap>

    <sql id="Base_Column_List">
        id,name,age,
        email,status,gender,
        contact,create_time,update_time
    </sql>
    <delete id="deleteByNameAndAge">
        delete
        from user
        where name = #{name,jdbcType=VARCHAR}
          AND age = #{age,jdbcType=NUMERIC}
    </delete>
    <update id="updateNameByAge">
        update user
        set name = #{name,jdbcType=VARCHAR}
        where age = #{age,jdbcType=NUMERIC}
    </update>
    <select id="selectAllByAgeBetween" resultMap="BaseResultMap">
        select
        <include refid="Base_Column_List"/>
        from user
        where
        age between #{beginAge,jdbcType=INTEGER} and #{endAge,jdbcType=INTEGER}
    </select>
</mapper>           

并發問題

多個使用者修改同一個資料時,要求隻有一個請求修改資料,其它的不允許修改。
Mybatis-Plus高階
Mybatis-Plus高階
  • 悲觀鎖
Mybatis-Plus高階
  • 樂觀鎖
Mybatis-Plus高階
Mybatis-Plus高階

1)在資料庫表中添加一個字段version,表示版本,預設值是1;

2)找到實體類,添加對應的屬性,并使用@version表諸位這是一個樂觀鎖字段資訊。

package com.demo.domain;

import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
import com.demo.enums.GenderEnum;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;
import java.util.Map;

@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName(autoResultMap = true)
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
    private Integer status;
    private GenderEnum gender;
    @TableField(typeHandler = FastjsonTypeHandler.class)
    private Map<String, String> contact; // 聯系方式
    // 設定時間,還要考慮時區因素(資料庫本身和目前工程環境的時區)
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
    @Version // 樂觀鎖
    private Integer version;
}           
package com.demo.config;

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

// 分頁插件
@Configuration
public class MybatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        // 實作樂觀鎖的控制
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());

        return interceptor;
    }
}           

代碼生成器

<!--代碼生成器-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.5.3</version>
        </dependency>

        <!--freemarker模闆依賴-->
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.32</version>
        </dependency>           
FastAutoGenerator.create("url", "username", "password")
    .globalConfig(builder -> {
        builder.author("baomidou") // 設定作者
            .enableSwagger() // 開啟 swagger 模式
            .fileOverride() // 覆寫已生成檔案
            .outputDir("D://"); // 指定輸出目錄
    })
    .dataSourceConfig(builder -> builder.typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> {
        int typeCode = metaInfo.getJdbcType().TYPE_CODE;
        if (typeCode == Types.SMALLINT) {
            // 自定義類型轉換
            return DbColumnType.INTEGER;
        }
        return typeRegistry.getColumnType(metaInfo);

    }))
    .packageConfig(builder -> {
        builder.parent("com.baomidou.mybatisplus.samples.generator") // 設定父包名
            .moduleName("system") // 設定父包子產品名
            .pathInfo(Collections.singletonMap(OutputFile.xml, "D://")); // 設定mapperXml生成路徑
    })
    .strategyConfig(builder -> {
        builder.addInclude("t_simple") // 設定需要生成的表名
            .addTablePrefix("t_", "c_"); // 設定過濾表字首
    })
    .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模闆,預設的是Velocity引擎模闆
    .execute();           

執行SQL分析列印

<dependency>
            <groupId>p6spy</groupId>
            <artifactId>p6spy</artifactId>
            <version>3.9.1</version>
        </dependency>           
spring:
  datasource:
    driver-class-name: com.p6spy.engine.spy.P6SpyDriver
    url: jdbc:p6spy:mysql://localhost:3306/mq?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=false
    username: root
    password: root           
# ***spy.properties***
#3.2.1以上使用
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
#3.2.1以下使用或者不配置
#modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
# 自定義日志列印
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
#日志輸出到控制台
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
# 使用日志系統記錄 sql
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 設定 p6spy driver 代理
deregisterdrivers=true
# 取消JDBC URL字首
useprefix=true
# 配置記錄 Log 例外,可去掉的結果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
excludecategories=info,debug,result,commit,resultset
# 日期格式
dateformat=yyyy-MM-dd HH:mm:ss
# 實際驅動可多個
#driverlist=org.h2.Driver
# 是否開啟慢SQL記錄
outagedetection=true
# 慢SQL記錄标準 2 秒
outagedetectioninterval=2           

多資料源環境

<dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
            <version>3.1.0</version>
        </dependency>           
spring:
  datasource:
    dynamic:
      primary: master
      strict: false
      datasource:
        master:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://localhost:3306/mq?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=false
          username: root
          password: root
        slave_1:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://localhost:3306/mq1?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=false
          username: root
          password: root           
Mybatis-Plus高階
Mybatis-Plus高階