MyBatis-Plus Detailed Explanation

1. Mybatis-Plus

MyBatis-Plus official website
MyBatis-Plus (opens new window) (MP for short) is an enhancement tool for MyBatis (opens new window). On the basis of MyBatis, only enhancements are made without changes, and it is born to simplify development and improve efficiency.
insert image description here

1. Mybatis-plus quick start

(1) Create a database and create related tables

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]');
#真实开发中,version(乐观锁)、delete(逻辑删除)、gmt_create、gmt_modified

(2) Use Spring Initializer to quickly initialize the maven project and add related dependencies

<dependencies>
    <!--mybatis-plus-->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.0.5</version>
    </dependency>
    <!--springboot-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <!--mysql数据库驱动-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <!--lombok-->
    <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>
    </dependency>
</dependencies>

(3) Configuration file application.properties (database connection, log, etc.)

#1.数据库连接
spring.datasource.username=root
spring.datasource.password=12345678
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?useUnicode=true&characterEncoding=UTF-8&useSSL=FALSE&serverTimezone=UTC&useOldAliasMetadataBehavior=true
#2.配置日志信息
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

(4) Create entity classes and mark related annotations

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

(5) Create a mapper interface and inherit the BaseMapper<T> interface

//代表持久层,此处的泛型T换成子类的实体类即可
@Repository
public interface UserMapper extends BaseMapper<User> {
    
    
}

(6) Annotate @MapperScan("the classpath of the corresponding mapper interface") on the main startup class
(7) Test

@SpringBootTest
class MybatisPlusApplicationTests {
    
    
    @Autowired
    private UserMapper userMapper;
    @Test
    void contextLoads() {
    
    
        List<User> users = userMapper.selectList(null);
        users.forEach(System.out::println);
    }
}

insert image description here

Two, CRUD extended operation

1. Insert operation

// 测试插入
@Test
public void testInsert(){
    
    
    User user = new User();
    //user.setId(6);
    user.setName("小王");
    user.setAge(2);
    user.setEmail("[email protected]");
    int result = userMapper.insert(user);// 无法帮我们自动生成id
    System.out.println(result); // 受影响的行数0
}

The version is updated quickly, and the id automatically generated by the snowflake algorithm has expired. If the id is not set, the insertion fails at this time. Set the id attribute value to test again, and the insertion is successful.
insert image description here

2. Primary key generation strategy

Snowflake Algorithm : Summary of Unique ID Generation Schemes for Distributed Systems
Snowflake is Twitter's open source distributed ID generation algorithm, and the result is a long ID. Its core idea is: use 41bit as the number of milliseconds, 10bit as the ID of the machine (5 bits are the data center, 5 bits for the machine ID), and 12bit as the serial number within milliseconds (meaning that each node can generate 4096 IDs), there is a sign bit at the end, which is always 0. Guaranteed to be almost unique in the world!

Set the primary key auto-increment:
(1) On the primary key field of the entity class User @TableId(type = IdType.AUTO)
(2) Set the primary key auto-increment for the corresponding database table, and set the initial value
insert image description here
(3) If the primary key is not set, the insertion is successful

// 测试插入
@Test
public void testInsert(){
    
    
    User user = new User();
    user.setName("小王");
    user.setAge(2);
    user.setEmail("[email protected]");
    int result = userMapper.insert(user);//自动生成id后插入成功
    System.out.println(user);//插入的记录
    System.out.println(result); // 受影响的行数
}

insert image description here
IdType source code explanation

public enum IdType {
    
    
    AUTO(0),	//数据库id自增
    NONE(1),	//未设置主键
    INPUT(2),	//手动输入
    ASSIGN_ID(3),	//默认的全局唯一id
    ASSIGN_UUID(4),	//全局唯一id UUID
    ID_WORKER_STR(5); //ID_WORKER 字符串表示法
}

3. Update operation

@Test
public void testUpdate(){
    
    
    User user = new User();
    user.setId(6L);
    user.setName("小吕");
    user.setAge(4);
    //updateById(User user)方法的参数是一对象
    int result = userMapper.updateById(user);
    System.out.println(result);
}

The update operation is performed according to the id, and the update is successful.
insert image description here

4. Autofill

Alibaba Development Manual: All database tables: gmt_create (create), gmr_modified (update) almost all tables must be configured! And it needs to be automated!
Method 1: Database level (not allowed in practice)
(1) Add new fields create_time, update_time in the table
insert image description here
(2) Synchronize the corresponding User entity class to add new attributes

private Date createTime;
private Date updateTime;

(3) Update and view the results again.
insert image description here
Method 2: Code level
(1) Delete the default value of the database
insert image description here
(2) Add annotations to the fields of the User entity class

//字段添加填充内容
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.UPDATE)
private Date updateTime;

(3) Write processor processing annotations

@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    
    
    @Override
    public void insertFill(MetaObject metaObject) {
    
    
        log.info("insert Fill start...");
        this.setFieldValByName("createTime",new Date(),metaObject);
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
    @Override
    public void updateFill(MetaObject metaObject) {
    
    
        log.info("update Fill start...");
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
}

(4) Test the insert and update operations, and you can see that the same function is also implemented. (If it is inconsistent with the computer system time here, you should configure the time zone when configuring the url in application.properties)
insert image description here

5. Optimistic lock

Optimistic lock: always think that there will be no problems, no matter what you do, don't lock it! If something goes wrong, update the value test again!
Pessimistic locking: always think that there will be problems, no matter what you do, it will be locked! Do it again!

When updating a record, hope that this record has not been updated by others
Optimistic lock implementation method:
① Get the current version when taking out the record
② Bring this version when updating
③ When performing update, set version = newVersion where version = oldVersion
④ If the version is wrong, the update will fail

(1) Add a version field to the database table
insert image description here
(2) Add attributes to the corresponding entity class

@Version    //乐观锁version注解
private Integer version;

(3) Configuration class registration component

@Configuration
@MapperScan("按需修改")
public class MyBatisPlusConfig {
    
    
    /**
     * 旧版
     */
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
    
    
        return new OptimisticLockerInterceptor();
    }

    /**
     * 新版
     */
    /*
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return mybatisPlusInterceptor;
    }*/
}

(4) Test optimistic lock

//乐观锁执行成功,单线程
@Test
public void testOptimisticLocker(){
    
    
    User user = userMapper.selectById(1L);
    user.setName("小王");
    user.setAge(3);
    int result = userMapper.updateById(user);
    System.out.println(result);
}

//乐观锁执行失败,模拟多线程插队
@Test
public void testOptimisticLocker02(){
    
    
    User user = userMapper.selectById(1L);
    user.setAge(15);
    user.setName("张扬");
    //模拟另一个线程执行了插队操作
    User user2 = userMapper.selectById(1L);
    user2.setName("沉默");
    user2.setAge(5);
    int result = userMapper.updateById(user2);
    System.out.println(result);
}

insert image description here

6. Query operation

//1.单条记录查询SELECT id,name,age,email,create_time,update_time,version FROM user WHERE id=? 
@Test
public void testSelectById(){
    
    
    User user = userMapper.selectById(1L);
    System.out.println(user);
}
//2.多条记录查询SELECT id,name,age,email,create_time,update_time,version FROM user WHERE id IN ( ? , ? , ? ) 
@Test
public void testSelectBatchIds(){
    
    
    List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
    users.forEach(System.out::println);
}
//3.条件查询SELECT id,name,age,email,create_time,update_time,version FROM user WHERE name = ? AND age = ? 
@Test
public void test(){
    
    
    HashMap<String, Object> map = new HashMap<>();
    map.put("name","沉默");
    map.put("age",5);
    List<User> users = userMapper.selectByMap(map);
    users.forEach(System.out::println);
}

7. Paging query

(1) Configure the pagination plug-in interceptor

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

(2) Test pagination query

//分页查询
@Test
public void testPage(){
    
    
    //参数1:当前页 参数2:页面大小
    Page<User> page = new Page<>(1,5);
    //参数1:page对象 参数2:条件选择器
    userMapper.selectPage(page, null);
    page.getRecords().forEach(System.out::println);
    System.out.println(page.getTotal());
}

insert image description here

8. Delete operation

//1.删除单条记录
@Test
public void testDeleteById(){
    
    
    int result = userMapper.deleteById(6L);
    System.out.println(result);
}
//2.删除多条记录
@Test
public void testDeleteBatchIds(){
    
    
    int result = userMapper.deleteBatchIds(Arrays.asList(7, 8, 9));
    System.out.println(result);
}
//3.条件删除
@Test
public void testDeleteByMap(){
    
    
    HashMap<String, Object> map = new HashMap<>();
    map.put("name","沉默");
    map.put("age",5);
    int result = userMapper.deleteByMap(map);
    System.out.println(result);
}

9. Logical deletion (false deletion)

Physical deletion: directly removed from the database
Logical deletion: not removed from the database, but invalidated by a variable! deleted = 0 => deleted = 1
delete: update user set deleted=1 where id = 1 and deleted=0
search: select id,name,deleted from user where deleted=0
(1) add fields in the database table
insert image description here
(2) corresponding Add attributes to the User entity class

@TableLogic     //逻辑删除
private Integer deleted;

(3) Configuration file configuration tombstone

#配置逻辑删除
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0

(4) Configure logical deletion

//逻辑删除
@Bean
public ISqlInjector sqlInjector(){
    
    
    return new LogicSqlInjector();
}

(5) Test delete operation

@Test
public void testDelete(){
    
    
    int res = userMapper.deleteById(3L);
    System.out.println(res);
}

You can see that the update operation is actually performed, and the records in the database still exist. Tombstoned records are automatically filtered when querying.
insert image description here

3. Wrapper condition queryer

conditional constructor

@SpringBootTest
public class WrapperTest {
    
    
    @Autowired
    private UserMapper userMapper;
    @Test
    void contextLoads() {
    
    
        //查询name不为空的用户,并且邮箱不为空的用户,年龄大于12
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.isNotNull("name")
                .isNotNull("email")
                .eq("name","Tom");
        userMapper.selectList(wrapper).forEach(System.out::println); //和我们刚刚学习的map对比一下
    }
    @Test
    void test2(){
    
    
        //查询名字Chanv
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("name", "Chanv");
        User user = userMapper.selectOne(wrapper);
        System.out.println(user);
    }
    @Test
    void test3(){
    
    
        //查询年龄在19到30岁之间的用户
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.between("age", 19, 30); //区间
        Integer count = userMapper.selectCount(wrapper);
        System.out.println(count);
    }
    //模糊查询
    @Test
    void test4(){
    
    
        //查询年龄在19到30岁之间的用户
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //左和右
        wrapper.notLike("name", "b")
                .likeRight("email", "t");
        List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
        maps.forEach(System.out::println);
    }
    @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);
    }
    @Test
    void test6(){
    
    
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //通过id进行排序
        wrapper.orderByDesc("id");
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }
}

4. Code generator

AutoGenerator is the code generator of MyBatis-Plus. Through AutoGenerator, the codes of various modules such as Entity, Mapper, Mapper XML, Service, and Controller can be quickly generated, which greatly improves the development efficiency.
1. Introduce related dependencies

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.5.2</version>
</dependency>

2. Configure related policies

//代码生成器
public class Code {
    
    
    public static void main(String[] args) {
    
    
        //需要构建一个 代码自动生成器 对象
        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();
        //配置策略

        //1、全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor("wds");
        gc.setOpen(false);
        gc.setFileOverride(false);  //是否覆盖
        gc.setServiceName("%sService"); //去Service的I前缀
        gc.setIdType(IdType.ID_WORKER);
        gc.setDateType(DateType.ONLY_DATE);
        gc.setSwagger2(true);
        mpg.setGlobalConfig(gc);

        //2、设置数据源
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("12345678");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);

        //3、包的配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName("blog");
        pc.setParent("com.chanv");
        pc.setEntity("pojo");
        pc.setMapper("mapper");
        pc.setService("service");
        pc.setController("controller");
        mpg.setPackageInfo(pc);

        //4、策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude("user");    //设置要映射的表名
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setEntityLombokModel(true);    //自动lombok
        strategy.setLogicDeleteFieldName("deleted");
        //自动填充配置
        TableFill createTime = new TableFill("create_time", FieldFill.INSERT);
        TableFill updateTime = new TableFill("update_time", FieldFill.UPDATE);
        ArrayList<TableFill> tableFills = new ArrayList<>();
        tableFills.add(createTime);
        tableFills.add(updateTime);
        strategy.setTableFillList(tableFills);
        //乐观锁
        strategy.setVersionFieldName("version");
        strategy.setRestControllerStyle(true);
        strategy.setControllerMappingHyphenStyle(true);     //localhost:8080/hello_id_2
        mpg.setStrategy(strategy);

        mpg.execute();  //执行代码构造器
    }
}

For more technologies, you can go to station b to learn Kuangshen said: [Crazy God Talks Java] The latest and complete tutorial of MyBatisPlus is easy to understand

Guess you like

Origin blog.csdn.net/weixin_46081857/article/details/124110912