detailed! Mybatis-plus common API full set of tutorials, I don’t believe you don’t understand after reading it!

Preface

Official website: Mybatis-plus official document Simplify MyBatis!

Create database

The database name is mybatis_plus

Create table

Create user table

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]');

Note: - There are often these four fields in real development, version (optimistic lock), deleted (logical deletion), gmt_create (creation time), gmt_modified (modification time)

Initialize the project

使用SpringBoot器 初始化!

Import dependency

<!-- 数据库驱动 -->
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- lombok -->
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
</dependency>
<!-- mybatis-plus -->
<!-- mybatis-plus 是自己开发,并非官方的! -->
<dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>mybatis-plus-boot-starter</artifactId>
  <version>3.0.5</version>
</dependency>

Note: Try not to import mybatis and mybatis-plus at the same time! Avoid version differences causing unpredictable problems.

Connect to the database

Create application.yml

spring:
  profiles:
    active: dev
  datasource:
# 驱动不同 mysql 5  com.mysql.jdbc.Driver
#         mysql 8  com.mysql.cj.jdbc.Driver、需要增加时区的配置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

Business code

实体类

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

mapper interface

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.kuang.pojo.User;
import org.springframework.stereotype.Repository;
// 在对应的Mapper上面继承基本的类 BaseMapper
@Repository // 代表持久层
public interface UserMapper extends BaseMapper<User> {
  // 所有的CRUD操作都已经编写完成了
}

Note that we need to scan all interfaces under our mapper package on the main startup class
@MapperScan("com.kwhua.mapper")

test

@SpringBootTest
class MybatisPlusApplicationTests {
  // 继承了BaseMapper,所有的方法都来自己父类
  // 我们也可以编写自己的扩展方法!
  @Autowired
  private UserMapper userMapper;
  @Test
  void contextLoads() {
    // 参数是一个 Wrapper ,条件构造器,这里我们先设置条件为空,查询所有。
    List<User> users = userMapper.selectList(null);
    users.forEach(System.out::println);
 }
}

All data output

Configuration log

All of our sql is now invisible, we want to know how it is executed, all we have to configure the log output
application.yml file add log configuration

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

View log information of executing SQL

3. Mybatis-plus CRUD

1. Insert operation

// 测试插入
    @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); // 帮我们自动生成id
        System.out.println(result); // 受影响的行数
        System.out.println(user); // 看到id会自动填充。    }

See the id will be automatically filled. The default value of the id inserted into the database: the global unique id

Primary key generation strategy

1) The primary key is incremented
1. @TableId(type = IdType.AUTO) on the entity class field
2. The database id field is set to increment!

3. Test again (you can see that the id value is 1 greater than the last inserted)

Source code explanation of id generation strategy

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

The above will not be tested one by one.

Update operation

 @Test
    public void testUpdate(){
        User user = new User();
        // 通过条件自动拼接动态sql
        user.setId(1302223874217295874L);
        user.setName("kwhua_mybatis-plus_updateTest");
        user.setAge(20);
        // 注意:updateById 但是参数是一个对象!
        int i = userMapper.updateById(user);
        System.out.println(i);
    }

Auto fill

Creation time, modification time! These two field operations are done automatically, we do not want to update manually!
Alibaba Development Manual: All database tables must be configured with gmt_create and gmt_modified! And it needs to be automated!
Method 1: Database level (generally not used in work)
1. Add fields gmt_create, gmt_modified to the table

2. Synchronize entity classes

private Date gmtCreate;
private Date gmtModified;

3. Check again

Method 2: Code level
1, delete the default value of the database, update operation!

2. Annotations need to be added to the attributes of the entity class field

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

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

3. Write a processor to process this annotation!

@Slf4j
@Component // 一定不要忘记把处理器加到IOC容器中!
public class MyMetaObjectHandler implements MetaObjectHandler {
    // 插入时的填充策略
    @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);
    }

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

4. Test insert and update, check time changes.

Optimistic lock

Optimistic Locking: As its name suggests, it is very optimistic. It always thinks that there will be no problems, no matter what you do not lock it! If there is a problem,
update the value again to test.
Pessimistic lock: As the name suggests, it is very pessimistic. It always thinks that there is always a problem, and it will lock no matter what it does! Go ahead!

Optimistic lock implementation:

When fetching the record, when getting the current version
update, and when
performing the update with this version , set version = newVersion where version = oldVersion
If the version is incorrect, the update fails

乐观锁:1、先查询,获得版本号 version = 1
-- A
update user set name = "kwhua", version = version + 1
where id = 2 and version = 1
-- B 线程抢先完成,这个时候 version = 2,会导致 A 修改失败!
update user set name = "kwhua", version = version + 1
where id = 2 and version = 1

Optimistic lock test
1. Add the version field to the database!

2. Entity class plus corresponding fields

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

3. Register components

// 扫描我们的 mapper 文件夹
@MapperScan("com.kwhua.mapper")
@EnableTransactionManagement
@Configuration // 配置类
public class MyBatisPlusConfig {
    // 注册乐观锁插件
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }
   }

4. Test

// 测试乐观锁成功!
    @Test
    public void testOptimisticLocker(){
        // 1、查询用户信息
        User user = userMapper.selectById(1L);
        // 2、修改用户信息
        user.setName("kwhua");
        user.setEmail("[email protected]");
        // 3、执行更新操作
        userMapper.updateById(user);
    }

The version field has changed from 1 to 2

// 测试乐观锁失败!多线程下
    @Test
    public void testOptimisticLocker2(){

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

        // 模拟另外一个线程执行了插队操作
        User user2 = userMapper.selectById(1L);
        user2.setName("kwhua222");
        user2.setEmail("[email protected]");
        userMapper.updateById(user2);

        // 自旋锁来多次尝试提交!
        userMapper.updateById(user); // 如果没有乐观锁就会覆盖插队线程的值!
    }

You can see that thread 1 failed to perform the update

Query operation

// 测试查询
    @Test
    public void testSelectById(){
        User user = userMapper.selectById(1L);
        System.out.println(user);
    }

    // 测试批量查询!
    @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 Pagination query
1, configure the interceptor component

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

2. Just use the Page object directly!

// 测试分页查询
@Test
public void testPage(){
  // 参数一:当前页
  // 参数二:页面大小
  Page<User> page = new Page<>(2,5);
  userMapper.selectPage(page,null);
  page.getRecords().forEach(System.out::println);
  System.out.println(page.getTotal());
}

Physical deletion

// 测试删除
    @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);
    }

Tombstone

Physical deletion: directly removed from the database
Logical deletion: not removed from the database , but invalidated through a variable! deleted = 0 => deleted = 1 The
administrator can view the deleted records! Prevent the loss of data, similar to the recycle bin!

1. Add a deleted field to the data table

2. Add attributes to the entity class

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

3. Configuration

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

Profile configuration

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

4. Test
test delete

The field value is also changed from 0 to 1

Test query

Performance analysis plugin

Function: Performance analysis interceptor, used to output each SQL statement and its execution time.
MP also provides a performance analysis plug-in. If it exceeds this time, it will stop running!
1. Import the plugin

/**
     * SQL执行效率插件
     */
    @Bean
    @Profile({"dev","test"})// 设置 dev test 环境开启,保证我们的效率
    public PerformanceInterceptor performanceInterceptor() {
        PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
        performanceInterceptor.setMaxTime(100); //ms 设置sql执行的最大时间,如果超过了则不执行
        performanceInterceptor.setFormat(true);
        return performanceInterceptor;
    }

Conditional Constructor (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); // 和我们刚才学习的map对比一下
    }

.eq

 @Test
    void test2(){
        // 查询名字kwhua
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("name","kwhua");
        User user = userMapper.selectOne(wrapper); // 查询一个数据用selectOne,查询多个结果使用List 或者 Map
        System.out.println(user);
    }

.between

@Test
    void test3(){
        // 查询年龄在 20 ~ 30 岁之间的用户
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.between("age",20,30); // 区间
        Integer count = userMapper.selectCount(wrapper);// 查询结果数
        System.out.println(count);
    }

.like

 // 模糊查询
    @Test
    void test4(){
        // 查询名字中不带e且 邮箱以t开头的数据
        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

//测试六
    @Test
    void test6(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        // 通过id进行排序
        wrapper.orderByAsc("id");

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

Automatic code generator

You can create a java class in the test folder

// 代码自动生成器
public class generateCode {
   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("kwhua");//作者名称
    gc.setOpen(false);
    gc.setFileOverride(false); // 是否覆盖
    gc.setIdType(IdType.ID_WORKER);
    gc.setDateType(DateType.ONLY_DATE);
    gc.setSwagger2(true);//实体属性 Swagger2 注解

    // 自定义文件命名,注意 %s 会自动填充表实体属性!
    gc.setServiceName("%sService"); 
    gc.setControllerName("%sController");
    gc.setServiceName("%sService");
    gc.setServiceImplName("%sServiceImpl");
    gc.setMapperName("%sMapper");
    gc.setXmlName("%sMapper");

    mpg.setGlobalConfig(gc);

    //2、设置数据源
    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以下的驱动
    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"); // 设置要映射的表名
    strategy.setNaming(NamingStrategy.underline_to_camel);
    strategy.setColumnNaming(NamingStrategy.underline_to_camel);
    strategy.setEntityLombokModel(true); // 自动lombok;
    strategy.setLogicDeleteFieldName("deleted");
    // 自动填充配置
    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");
    //根据你的表名来建对应的类名,如果你的表名没有下划线,比如test,那么你就可以取消这一步
    strategy.setTablePrefix("t_");
    strategy.setRestControllerStyle(true); //rest请求
    //自动转下划线,比如localhost:8080/hello_id_2
    strategy.setControllerMappingHyphenStyle(true); 
    mpg.setStrategy(strategy);
    mpg.execute(); //执行
 }
}

The corresponding code can be generated by executing the main method

At last

Thank you for seeing here. Please correct me if there are any shortcomings in the article. If you think the article is helpful to you, remember to give me a thumbs up. You will share java-related technical articles or industry information every day. Welcome everyone to follow and forward the article!

Guess you like

Origin blog.csdn.net/weixin_47277170/article/details/108446858