mybatis-plus usage (1)

MyBatis-plus is a Mybatis enhancement tool used to simplify development and improve efficiency. The abbreviation mp is used below to simplify MyBatis-plus. This article mainly introduces the use of mp to integrate Spring Boot.

(5 messages) mybatis-plus usage (2) - slag baby engineer's blog - CSDN blog

1. Create a Spring Boot project.

2. Import dependencies

<!-- pom.xml -->  
   <?xml version="1.0" encoding="UTF-8"?>  
   <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">  
       <modelVersion>4.0.0</modelVersion>  
       <parent>  
           <groupId>org.springframework.boot</groupId>  
           <artifactId>spring-boot-starter-parent</artifactId>  
           <version>2.3.4.RELEASE</version>  
           <relativePath/> <!-- lookup parent from repository -->  
       </parent>  
       <groupId>com.example</groupId>  
       <artifactId>mybatis-plus</artifactId>  
       <version>0.0.1-SNAPSHOT</version>  
       <name>mybatis-plus</name>  
       <properties>  
           <java.version>1.8</java.version>  
       </properties>  
       <dependencies>  
           <dependency>  
               <groupId>org.springframework.boot</groupId>  
               <artifactId>spring-boot-starter</artifactId>  
           </dependency>  
           <dependency>  
               <groupId>org.springframework.boot</groupId>  
               <artifactId>spring-boot-starter-test</artifactId>  
               <scope>test</scope>  
           </dependency>  
           <dependency>  
               <groupId>org.springframework.boot</groupId>  
               <artifactId>spring-boot-configuration-processor</artifactId>  
           </dependency>  
           <dependency>  
               <groupId>com.baomidou</groupId>  
               <artifactId>mybatis-plus-boot-starter</artifactId>  
               <version>3.4.2</version>  
           </dependency>  
           <dependency>  
               <groupId>mysql</groupId>  
               <artifactId>mysql-connector-java</artifactId>  
               <scope>runtime</scope>  
           </dependency>  
           <dependency>  
               <groupId>org.projectlombok</groupId>  
               <artifactId>lombok</artifactId>  
           </dependency>  
       </dependencies>  
       <build>  
           <plugins>  
               <plugin>  
                   <groupId>org.springframework.boot</groupId>  
                   <artifactId>spring-boot-maven-plugin</artifactId>  
               </plugin>  
           </plugins>  
       </build>  
   </project>

 3. Configure the database

# application.yml  
   spring:  
     datasource:  
       driver-class-name: com.mysql.cj.jdbc.Driver  
       url: jdbc:mysql://localhost:3306/yogurt?serverTimezone=Asia/Shanghai  
       username: root  
       password: root  
         
   mybatis-plus:  
     configuration:  
       log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #开启SQL语句打印

4. Create an entity class

package com.example.mp.po;  
   import lombok.Data;  
   import java.time.LocalDateTime;  
   @Data  
   public class User {  
    private Long id;  
    private String name;  
    private Integer age;  
    private String email;  
    private Long managerId;  
    private LocalDateTime createTime;  
   }

5. Create a mapper interface

package com.example.mp.mappers;  
   import com.baomidou.mybatisplus.core.mapper.BaseMapper;  
   import com.example.mp.po.User;  
   public interface UserMapper extends BaseMapper<User> { }

6. Configure the scan path of the mapper interface on the SpringBoot startup class


package com.example.mp;  
   import org.mybatis.spring.annotation.MapperScan;  
   import org.springframework.boot.SpringApplication;  
   import org.springframework.boot.autoconp.SpringBootApplication;  
   @SpringBootApplication  
   @MapperScan("com.example.mp.mappers")  
   public class MybatisPlusApplication {  
    public static void main(String[] args) {  
     SpringApplication.run(MybatisPlusApplication.class, args);  
    }  
   }

7. Create a table in the database

DROP TABLE IF EXISTS user;  
   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  
   (1, '大BOSS', 40, '[email protected]', NULL, '2021-03-22 09:48:00'),  
   (2, '李经理', 40, '[email protected]', 1, '2021-01-22 09:48:00'),  
   (3, '黄主管', 40, '[email protected]', 2, '2021-01-22 09:48:00'),  
   (4, '吴组长', 40, '[email protected]', 2, '2021-02-22 09:48:00'),  
   (5, '小菜', 40, '[email protected]', 2, '2021-02-22 09:48:00')

8. Write a SpringBoot test class

package com.example.mp;  
   import com.example.mp.mappers.UserMapper;  
   import com.example.mp.po.User;  
   import org.junit.Test;  
   import org.junit.runner.RunWith;  
   import org.springframework.beans.factory.annotation.Autowired;  
   import org.springframework.boot.test.context.SpringBootTest;  
   import org.springframework.test.context.junit4.SpringRunner;  
   import java.util.List;  
   import static org.junit.Assert.*;  
   @RunWith(SpringRunner.class)  
   @SpringBootTest  
   public class SampleTest {  
    @Autowired  
    private UserMapper mapper;  
    @Test  
    public void testSelect() {  
     List<User> list = mapper.selectList(null);  
     assertEquals(5, list.size());  
     list.forEach(System.out::println);  
    }  
   }

The preparation work is completed, and the database situation is as follows:

The project directory is as follows:

 Run the test class

 It can be seen that for the basic CRUD operation of a single table, you only need to create an entity class and create an BaseMapperinterface inherited from it, which is very simple. Moreover, we noticed that the attributes Userin the class automatically correspond to those in the database table . This is because mp automatically converts the database underscore name to the camel case name of the Java class.managerIdcreateTimemanager_idcreate_time

annotation

mp provides a total of 8 annotations, which are used on Java entity classes.

@TableName

Note on the class, specify the mapping relationship between the class and the database table. When the class name of the entity class (after being converted to lowercase) is the same as the name of the database table , this annotation does not need to be specified.

@TableId

The annotation is on a certain field of the entity class, indicating that this field corresponds to the primary key of the database table . When the primary key name is id (the column name in the table is id, the field name in the entity class is id), there is no need to use this annotation to explicitly specify the primary key, and mp will be automatically associated. If the field name of the class is inconsistent with the column name of the table, valuethe column name of the table can be specified with the attribute. In addition, this annotation has an important attribute typefor specifying the primary key strategy.

@TableField

Note On a field, specify the mapping relationship between the field of the Java entity class and the column of the database table. This annotation has the following application scenarios.

  • Exclude non-table fields

    If a field in the Java entity class does not correspond to any column in the table, it is only used to save some additional or assembled data, you can set the property to, so that this will be ignored when inserting the existentity falseobject field. Excluding non-table fields can also be done in other ways, such as using staticor transientkeywords, but I personally think it is not very reasonable, so I won’t go into details

  • field validation strategy

    Through insertStrategythe configuration of the updateStrategyattribute whereStrategy, you can control how the fields in the object are assembled into the SQL statement when the entity object is inserted, updated, or used as a WHERE condition.

  • field population strategy

    Specify by fillattribute, when the field is empty, it will be automatically filled

@Version

Optimistic Lock Annotation

@EnumValue

Annotations on enum fields

@TableLogic

Tombstone

KeySequence

sequence primary key strategy ( oracle)

InterceptorIgnore

Plug-in filtering rules

CRUD interface

mp encapsulates some of the most basic CRUD methods, you only need to directly inherit the interface provided by mp, and you can eat it without writing any SQL. mp provides two sets of interfaces, namely Mapper CRUD interface and Service CRUD interface. And mp also provides a conditional constructor Wrapper, which can easily assemble WHERE conditions in SQL statements.

Mapper CRUD interface

Just define the entity class, then create an interface, inherit what mp provides BaseMapper, and you can eat it. mp will automatically parse the mapping relationship between entity classes and tables when mybatis starts, and inject mapper with common CRUD methods. BaseMapperSome of the methods provided in are listed below:

  • insert(T entity)  insert a record

  • deleteById(Serializable id)  Delete a record based on the primary key id

  • delete(Wrapper<T> wrapper) Delete according to the conditional constructor wrapper

  • selectById(Serializable id) Search by primary key id

  • selectBatchIds(Collection idList) Batch lookup based on primary key id

  • selectByMap(Map<String,Object> map)Perform equivalent matching search  based on the column names and column values ​​specified in the map

  • selectMaps(Wrapper<T> wrapper)  According to the wrapper conditions, query records, and encapsulate the query results into a Map, the key of the Map is the column of the result, and the value is the value

  • selectList(Wrapper<T> wrapper)wrapperQuery  by Condition Builder

  • update(T entity, Wrapper<T> wrapper)wrapperupdate  based on conditional constructor

  • updateById(T entity)

  • ...

Here are a few more specific methods

selectMaps

BaseMapperThe interface also provides a selectMapsmethod that encapsulates the query result as a Map, where the key of the Map is the column of the result, and the value is the value

The usage scenarios of this method are as follows:

  • Check only some columns

When there are too many columns in a certain table, and you only need to select individual columns when SELECTing, the query results do not need to be encapsulated into Java entity class objects (when only some columns are checked, after encapsulation into entities, many of the entity objects attribute will be null), it can be used selectMaps, after obtaining the specified column, and then process it by yourself

for example

@Test  
   public void test3() {  
    QueryWrapper<User> wrapper = new QueryWrapper<>();  
    wrapper.select("id","name","email").likeRight("name","黄");  
    List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);  
    maps.forEach(System.out::println);  
   }

Statistics

for example

// 按照直属上级进行分组,查询每组的平均年龄,最大年龄,最小年龄  
  /**  
  select avg(age) avg_age ,min(age) min_age, max(age) max_age from user group by manager_id having sum(age) < 500;  
  **/  
    
  @Test  
  public void test3() {  
   QueryWrapper<User> wrapper = new QueryWrapper<>();  
   wrapper.select("manager_id", "avg(age) avg_age", "min(age) min_age", "max(age) max_age")  
     .groupBy("manager_id").having("sum(age) < {0}", 500);  
   List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);  
   maps.forEach(System.out::println);  
  }

selectObjs

Only the value of the first field (the first column) will be returned, and other fields will be discarded

for example

@Test  
 public void test3() {  
  QueryWrapper<User> wrapper = new QueryWrapper<>();  
  wrapper.select("id", "name").like("name", "黄");  
  List<Object> objects = userMapper.selectObjs(wrapper);  
  objects.forEach(System.out::println);  
 }

The result obtained only encapsulates the id of the first column

selectCount

Query the total number that meets the conditions. Note that using this method, the method that cannot be called QueryWrappersets selectthe column to be queried. This method will automatically addselect count(1)

for example

@Test  
 public void test3() {  
  QueryWrapper<User> wrapper = new QueryWrapper<>();  
  wrapper.like("name", "黄");  
  
  Integer count = userMapper.selectCount(wrapper);  
  System.out.println(count);  
 }

Service CRUD interface

Another set of CRUD is in the Service layer. You only need to write an interface, inherit it IService, and create an interface implementation class to eat it. (The CRUD method provided by this interface is similar to the function provided by the Mapper interface. The obvious difference is thatIService it supports more batch operations, such as saveBatch, saveOrUpdateBatchand other methods.

The edible example is as follows

1. First, create a new interface and inherit itIService

package com.example.mp.service;  
     
   import com.baomidou.mybatisplus.extension.service.IService;  
   import com.example.mp.po.User;  
     
   public interface UserService extends IService<User> {  
   }

 2. Create the implementation class of this interface, inherit it ServiceImpl, and finally @Serviceannotate it, register it in the Spring container, and you can eat it

package com.example.mp.service.impl;  
     
   import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;  
   import com.example.mp.mappers.UserMapper;  
   import com.example.mp.po.User;  
   import com.example.mp.service.UserService;  
   import org.springframework.stereotype.Service;  
     
   @Service  
   public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { }

 3. Test code

package com.example.mp;  
     
   import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;  
   import com.baomidou.mybatisplus.core.toolkit.Wrappers;  
   import com.example.mp.po.User;  
   import com.example.mp.service.UserService;  
   import org.junit.Test;  
   import org.junit.runner.RunWith;  
   import org.springframework.beans.factory.annotation.Autowired;  
   import org.springframework.boot.test.context.SpringBootTest;  
   import org.springframework.test.context.junit4.SpringRunner;  
   @RunWith(SpringRunner.class)  
   @SpringBootTest  
   public class ServiceTest {  
    @Autowired  
    private UserService userService;  
    @Test  
    public void testGetOne() {  
     LambdaQueryWrapper<User> wrapper = Wrappers.<User>lambdaQuery();  
     wrapper.gt(User::getAge, 28);  
     User one = userService.getOne(wrapper, false); // 第二参数指定为false,使得在查到了多行记录时,不抛出异常,而返回第一条记录  
     System.out.println(one);  
    }  
   }

 4. Results

 In addition, IServicechain calls are also supported, and the code is very simple to write. The query example is as follows

@Test  
 public void testChain() {  
  List<User> list = userService.lambdaQuery()  
    .gt(User::getAge, 39)  
    .likeRight(User::getName, "王")  
    .list();  
  list.forEach(System.out::println);  
 }

 The updated example is as follows

@Test  
 public void testChain() {  
  userService.lambdaUpdate()  
    .gt(User::getAge, 39)  
    .likeRight(User::getName, "王")  
    .set(User::getEmail, "[email protected]")  
    .update();  
 }

 The deletion example is as follows

@Test  
 public void testChain() {  
  userService.lambdaUpdate()  
    .like(User::getName, "青蛙")  
    .remove();  
 }

conditional constructor

What makes mp extremely convenient to me is that it provides a powerful conditional constructor Wrapper, which can construct WHERE conditions very conveniently. The conditional constructor mainly involves 3 classes, AbstractWrapper. QueryWrapper, UpdateWrapper, their class relationship is as follows

Provides AbstractWrappera lot of methods for building WHERE conditions, and QueryWrapperfor SELECTstatements, provides select()methods to customize the columns that need to be queried, and UpdateWrapperfor UPDATEstatements, provides set()methods for constructing setstatements. The conditional constructor also supports lambda expressions, which is very comfortable to write.

The following AbstractWrapperis a partial list of the methods used to construct the WHERE condition in the SQL statement

  • eq: equals, equal to

  • allEq: all equals, equal to

  • ne: not equals, not equal to

  • gt: greater than, greater than >

  • ge: greater than or equals, greater than or equal to

  • lt: less than, less than<

  • le: less than or equals, less than or equal to

  • between: Equivalent to BETWEEN in SQL

  • notBetween

  • like: Fuzzy matching. like("name","黄"), equivalent to SQL'sname like '%黄%'

  • likeRight: Fuzzy match the right half. likeRight("name","黄"), equivalent to SQL'sname like '黄%'

  • likeLeft: Fuzzy match left half. likeLeft("name","黄"), equivalent to SQL'sname like '%黄'

  • notLike: notLike("name","黄"), equivalent to SQL'sname not like '%黄%'

  • isNull

  • isNotNull

  • in

  • and: SQL connector AND

  • or: SQL connector OR

  • apply: Used for splicing SQL, this method can be used for database functions, and can dynamically pass parameters

  • .......

Example of use

Let's practice the use of conditional constructors through some specific cases. (using the table created earlier user)

// 案例先展示需要完成的SQL语句,后展示Wrapper的写法  
  
// 1. 名字中包含佳,且年龄小于25  
// SELECT * FROM user WHERE name like '%佳%' AND age < 25  
QueryWrapper<User> wrapper = new QueryWrapper<>();  
wrapper.like("name", "佳").lt("age", 25);  
List<User> users = userMapper.selectList(wrapper);  
// 下面展示SQL时,仅展示WHERE条件;展示代码时, 仅展示Wrapper构建部分  
  
// 2. 姓名为黄姓,且年龄大于等于20,小于等于40,且email字段不为空  
// name like '黄%' AND age BETWEEN 20 AND 40 AND email is not null  
wrapper.likeRight("name","黄").between("age", 20, 40).isNotNull("email");  
  
// 3. 姓名为黄姓,或者年龄大于等于40,按照年龄降序排列,年龄相同则按照id升序排列  
// name like '黄%' OR age >= 40 order by age desc, id asc  
wrapper.likeRight("name","黄").or().ge("age",40).orderByDesc("age").orderByAsc("id");  
  
// 4.创建日期为2021年3月22日,并且直属上级的名字为李姓  
// date_format(create_time,'%Y-%m-%d') = '2021-03-22' AND manager_id IN (SELECT id FROM user WHERE name like '李%')  
wrapper.apply("date_format(create_time, '%Y-%m-%d') = {0}", "2021-03-22") // 建议采用{index}这种方式动态传参, 可防止SQL注入  
    .inSql("manager_id", "SELECT id FROM user WHERE name like '李%'");  
// 上面的apply, 也可以直接使用下面这种方式做字符串拼接,但当这个日期是一个外部参数时,这种方式有SQL注入的风险  
wrapper.apply("date_format(create_time, '%Y-%m-%d') = '2021-03-22'");  
  
// 5. 名字为王姓,并且(年龄小于40,或者邮箱不为空)  
// name like '王%' AND (age < 40 OR email is not null)  
wrapper.likeRight("name", "王").and(q -> q.lt("age", 40).or().isNotNull("email"));  
  
// 6. 名字为王姓,或者(年龄小于40并且年龄大于20并且邮箱不为空)  
// name like '王%' OR (age < 40 AND age > 20 AND email is not null)  
wrapper.likeRight("name", "王").or(  
    q -> q.lt("age",40)  
      .gt("age",20)  
      .isNotNull("email")  
  );  
  
// 7. (年龄小于40或者邮箱不为空) 并且名字为王姓  
// (age < 40 OR email is not null) AND name like '王%'  
wrapper.nested(q -> q.lt("age", 40).or().isNotNull("email"))  
    .likeRight("name", "王");  
  
// 8. 年龄为30,31,34,35  
// age IN (30,31,34,35)  
wrapper.in("age", Arrays.asList(30,31,34,35));  
// 或  
wrapper.inSql("age","30,31,34,35");  
  
// 9. 年龄为30,31,34,35, 返回满足条件的第一条记录  
// age IN (30,31,34,35) LIMIT 1  
wrapper.in("age", Arrays.asList(30,31,34,35)).last("LIMIT 1");  
  
// 10. 只选出id, name 列 (QueryWrapper 特有)  
// SELECT id, name FROM user;  
wrapper.select("id", "name");  
  
// 11. 选出id, name, age, email, 等同于排除 manager_id 和 create_time  
// 当列特别多, 而只需要排除个别列时, 采用上面的方式可能需要写很多个列, 可以采用重载的select方法,指定需要排除的列  
wrapper.select(User.class, info -> {  
   String columnName = info.getColumn();  
   return !"create_time".equals(columnName) && !"manager_id".equals(columnName);  
  });

Condition

Among the many methods of the conditional constructor, a booleanparameter of a type can be specified conditionto determine whether the condition is added to the final generated WHERE statement, such as

String name = "黄"; // 假设name变量是一个外部传入的参数  
QueryWrapper<User> wrapper = new QueryWrapper<>();  
wrapper.like(StringUtils.hasText(name), "name", name);  
// 仅当 StringUtils.hasText(name) 为 true 时, 会拼接这个like语句到WHERE中  
// 其实就是对下面代码的简化  
if (StringUtils.hasText(name)) {  
 wrapper.like("name", name);  
}

entity object as condition

When calling the constructor to create an Wrapperobject, an entity object can be passed in. When using this later , the non-empty attributes in the entity object will be used to construct the WHERE condition (by default, the WHERE condition for equivalent matchingWrapper is constructed , and this behavior can be changed through the attributes in the annotations on each field in the entity class )@TableFieldcondition

The example is as follows

@Test  
 public void test3() {  
  User user = new User();  
  user.setName("黄主管");  
  user.setAge(28);  
  QueryWrapper<User> wrapper = new QueryWrapper<>(user);  
  List<User> users = userMapper.selectList(wrapper);  
  users.forEach(System.out::println);  
 }

The execution results are as follows. It can be seen that the equivalent matching query is performed according to the non-null attributes in the entity object .

If you want to change the behavior of equivalent matching@TableField for certain attributes, you can configure them with annotations in the entity class , as shown below

package com.example.mp.po;  
import com.baomidou.mybatisplus.annotation.SqlCondition;  
import com.baomidou.mybatisplus.annotation.TableField;  
import lombok.Data;  
import java.time.LocalDateTime;  
@Data  
public class User {  
 private Long id;  
 @TableField(condition = SqlCondition.LIKE) // 配置该字段使用like进行拼接  
 private String name;  
 private Integer age;  
 private String email;  
 private Long managerId;  
 private LocalDateTime createTime;  
}

Run the test code below

@Test  
 public void test3() {  
  User user = new User();  
  user.setName("黄");  
  QueryWrapper<User> wrapper = new QueryWrapper<>(user);  
  List<User> users = userMapper.selectList(wrapper);  
  users.forEach(System.out::println);  
 }

 From the results obtained in the figure below, for the fields in the entity object name, likesplicing is used

 @TableFieldconditionThe attribute configured in is actually a string, and SqlConditionsome strings are predefined in the class for selection

package com.baomidou.mybatisplus.annotation;  
  
public class SqlCondition {  
    //下面的字符串中, %s 是占位符, 第一个 %s 是列名, 第二个 %s 是列的值  
    public static final String EQUAL = "%s=#{%s}";  
    public static final String NOT_EQUAL = "%s&lt;&gt;#{%s}";  
    public static final String LIKE = "%s LIKE CONCAT('%%',#{%s},'%%')";  
    public static final String LIKE_LEFT = "%s LIKE CONCAT('%%',#{%s})";  
    public static final String LIKE_RIGHT = "%s LIKE CONCAT(#{%s},'%%')";  
}

 SqlConditionThe configuration provided in is relatively limited. When we need <or >other splicing methods, we need to define them ourselves. for example

package com.example.mp.po;  
import com.baomidou.mybatisplus.annotation.SqlCondition;  
import com.baomidou.mybatisplus.annotation.TableField;  
import lombok.Data;  
import java.time.LocalDateTime;  
@Data  
public class User {  
 private Long id;  
 @TableField(condition = SqlCondition.LIKE)  
 private String name;  
    @TableField(condition = "%s &gt; #{%s}") // 这里相当于大于, 其中 &gt; 是字符实体  
 private Integer age;  
 private String email;  
 private Long managerId;  
 private LocalDateTime createTime;  
}

 The test is as follows

@Test  
 public void test3() {  
  User user = new User();  
  user.setName("黄");  
        user.setAge(30);  
  QueryWrapper<User> wrapper = new QueryWrapper<>(user);  
  List<User> users = userMapper.selectList(wrapper);  
  users.forEach(System.out::println);  
 }

From the results obtained in the figure below, it can be seen that namethe attributes are likespliced ​​​​and agethe attributes are >spliced

allEq method

The allEq method passes in one mapfor equivalent matching

@Test  
 public void test3() {  
  QueryWrapper<User> wrapper = new QueryWrapper<>();  
  Map<String, Object> param = new HashMap<>();  
  param.put("age", 40);  
  param.put("name", "黄飞飞");  
  wrapper.allEq(param);  
  List<User> users = userMapper.selectList(wrapper);  
  users.forEach(System.out::println);  
 }

When there is an element with value in the Map passed in by the allEq method null, it will be set tois null

@Test  
 public void test3() {  
  QueryWrapper<User> wrapper = new QueryWrapper<>();  
  Map<String, Object> param = new HashMap<>();  
  param.put("age", 40);  
  param.put("name", null);  
  wrapper.allEq(param);  
  List<User> users = userMapper.selectList(wrapper);  
  users.forEach(System.out::println);  
 }

 If you want to ignore the element whose value is in the map null, you can set the parameter boolean null2IsNulltofalse

@Test  
 public void test3() {  
  QueryWrapper<User> wrapper = new QueryWrapper<>();  
  Map<String, Object> param = new HashMap<>();  
  param.put("age", 40);  
  param.put("name", null);  
  wrapper.allEq(param, false);  
  List<User> users = userMapper.selectList(wrapper);  
  users.forEach(System.out::println);  
 }

If you want to filter out some elements in the Map when executing allEq, you can call the overloaded method of allEqallEq(BiPredicate<R, V> filter, Map<R, V> params)

@Test  
 public void test3() {  
  QueryWrapper<User> wrapper = new QueryWrapper<>();  
  Map<String, Object> param = new HashMap<>();  
  param.put("age", 40);  
  param.put("name", "黄飞飞");  
  wrapper.allEq((k,v) -> !"name".equals(k), param); // 过滤掉map中key为name的元素  
  List<User> users = userMapper.selectList(wrapper);  
  users.forEach(System.out::println);  
 }

lambda conditional constructor

The lambda conditional constructor supports lambda expressions. It is not necessary to specify the column name in the form of a string like the ordinary conditional constructor. It can directly specify the column with the method reference of the entity class. The example is as follows

@Test  
 public void testLambda() {  
  LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();  
  wrapper.like(User::getName, "黄").lt(User::getAge, 30);  
  List<User> users = userMapper.selectList(wrapper);  
  users.forEach(System.out::println);  
 }

Like ordinary conditional constructors, column names are specified in the form of strings, and the validity of column names cannot be checked at compile time, which is not as elegant as lambda conditional constructors.

In addition, there is also a chained lambda conditional constructor , the usage example is as follows

@Test  
 public void testLambda() {  
  LambdaQueryChainWrapper<User> chainWrapper = new LambdaQueryChainWrapper<>(userMapper);  
  List<User> users = chainWrapper.like(User::getName, "黄").gt(User::getAge, 30).list();  
  users.forEach(System.out::println);  
 }

update operation

The above are all query operations, now let’s talk about update and delete operations.

BaseMapper2 update methods are provided in

  • updateById(T entity)

Update according to the input parameter entity( primary key). For attributes that are not empty in the middle, they will appear after the SET of the UPDATE statement, that is, attributes that are not empty in the middle will be updated to the database. The example is as followsidentityentity

@RunWith(SpringRunner.class)  
  @SpringBootTest  
  public class UpdateTest {  
   @Autowired  
   private UserMapper userMapper;  
   @Test  
   public void testUpdate() {  
    User user = new User();  
    user.setId(2L);  
    user.setAge(18);  
    userMapper.updateById(user);  
   }  
  }

  • update(T entity, Wrapper<T> wrapper)

Update based on entity entityand conditional constructors , examples are as followswrapper

@Test  
   public void testUpdate2() {  
    User user = new User();  
    user.setName("王三蛋");  
    LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();  
    wrapper.between(User::getAge, 26,31).likeRight(User::getName,"吴");  
    userMapper.update(user, wrapper);  
   }

 For an additional demonstration, pass in the entity object Wrapper, that is, use the entity object to construct the case of the WHERE condition

@Test  
   public void testUpdate3() {  
    User whereUser = new User();  
    whereUser.setAge(40);  
    whereUser.setName("王");  
    
    LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>(whereUser);  
    User user = new User();  
    user.setEmail("[email protected]");  
    user.setManagerId(10L);  
    
    userMapper.update(user, wrapper);  
   }

Notice that in our User class, namethe attributes and ageattributes are set as follows

@Data  
public class User {  
 private Long id;  
 @TableField(condition = SqlCondition.LIKE)  
 private String name;  
 @TableField(condition = "%s &gt; #{%s}")  
 private Integer age;  
 private String email;  
 private Long managerId;  
 private LocalDateTime createTime;  
}

 Results of the

 Let me demonstrate the use of chained lambda conditional constructors


@Test  
 public void testUpdate5() {  
  LambdaUpdateChainWrapper<User> wrapper = new LambdaUpdateChainWrapper<>(userMapper);  
  wrapper.likeRight(User::getEmail, "share")  
    .like(User::getName, "飞飞")  
    .set(User::getEmail, "[email protected]")  
    .update();  
 }

to reflect

Since BaseMapperthe two update methods provided both pass in an entity object to perform the update, this is fine when there are many columns to be updated . If you only want to update one or two columns, creating an entity object seems a bit trouble. In response to this situation, UpdateWrapperthere is seta method to manually splice the SET statement in SQL. At this time, it is not necessary to pass in the entity object. The example is as follows

@Test  
 public void testUpdate4() {  
  LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();  
  wrapper.likeRight(User::getEmail, "share").set(User::getManagerId, 9L);  
  userMapper.update(null, wrapper);  
 }

delete operation

BaseMapperA total of the following methods for deletion are provided

  • deleteById  Delete according to the primary key id

  • deleteBatchIds  Batch delete based on primary key id

  • deleteByMap  Delete according to the Map (the key in the Map is the column name, the value is the value, and the equivalent matching is performed according to the column and value)

  • delete(Wrapper<T> wrapper)Wrapperdelete   by conditional constructor

It is similar to the previous query and update operations, so I won’t go into details

Custom SQL

When the method provided by mp cannot meet the requirements, you can customize SQL.

Native mybatis

The example is as follows

  • Annotation method

    package com.example.mp.mappers;  
      
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;  
    import com.example.mp.po.User;  
    import org.apache.ibatis.annotations.Select;  
      
    import java.util.List;  
      
    /**  
     * @Author yogurtzzz  
     * @Date 2021/3/18 11:21  
     **/  
    public interface UserMapper extends BaseMapper<User> {  
       
     @Select("select * from user")  
     List<User> selectRaw();  
    }

  • xml way

    <?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.example.mp.mappers.UserMapper">  
     <select id="selectRaw" resultType="com.example.mp.po.User">  
            SELECT * FROM user  
        </select>  
    </mapper>  
    package com.example.mp.mappers;  
      
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;  
    import com.example.mp.po.User;  
    import org.apache.ibatis.annotations.Select;  
    import java.util.List;  
      
    public interface UserMapper extends BaseMapper<User> {  
     List<User> selectRaw();  
    }

    When using xml, if the xml file and the mapper interface file are not in the same directory , you need to application.ymlconfigure the storage path of mapper.xml in

    mybatis-plus:  
      mapper-locations: /mappers/*

    If there are multiple places to store the mapper, configure it in the form of an array

    
    mybatis-plus:  
      mapper-locations:   
      - /mappers/*  
      - /com/example/mp/*

    The test code is as follows

    
    @Test  
     public void testCustomRawSql() {  
      List<User> users = userMapper.selectRaw();  
      users.forEach(System.out::println);  
     }

    result

mybatis-plus

You can also use the Wrapper condition constructor provided by mp to customize SQL

The example is as follows

  • Annotation method

    package com.example.mp.mappers;  
    import com.baomidou.mybatisplus.core.conditions.Wrapper;  
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;  
    import com.baomidou.mybatisplus.core.toolkit.Constants;  
    import com.example.mp.po.User;  
    import org.apache.ibatis.annotations.Param;  
    import org.apache.ibatis.annotations.Select;  
    import java.util.List;  
      
    public interface UserMapper extends BaseMapper<User> {  
      
        // SQL中不写WHERE关键字,且固定使用${ew.customSqlSegment}  
     @Select("select * from user ${ew.customSqlSegment}")  
     List<User> findAll(@Param(Constants.WRAPPER)Wrapper<User> wrapper);  
    }

  • xml way

    package com.example.mp.mappers;  
    import com.baomidou.mybatisplus.core.conditions.Wrapper;  
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;  
    import com.example.mp.po.User;  
    import java.util.List;  
      
    public interface UserMapper extends BaseMapper<User> {  
     List<User> findAll(Wrapper<User> wrapper);  
    }  
    <!-- 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.example.mp.mappers.UserMapper">  
      
        <select id="findAll" resultType="com.example.mp.po.User">  
            SELECT * FROM user ${ew.customSqlSegment}  
        </select>  
    </mapper>

    Paging query

    BaseMapperTwo methods are provided for pagination query, namely selectPageand selectMapsPage, the former will encapsulate the query result into a Java entity object, and the latter will encapsulate it into a Java entity object Map<String,Object>. An edible example of a paging query is as follows

    1. Create a paging interceptor for mp and register it in the Spring container

    package com.example.mp.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 {  
         
           /** 新版mp **/  
        @Bean  
        public MybatisPlusInterceptor mybatisPlusInterceptor() {  
         MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();  
         interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));  
         return interceptor;  
        }  
           /** 旧版mp 用 PaginationInterceptor **/  
       }

    2. Execute paging query

    @Test  
        public void testPage() {  
         LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();  
         wrapper.ge(User::getAge, 28);  
               // 设置分页信息, 查第3页, 每页2条数据  
         Page<User> page = new Page<>(3, 2);  
               // 执行分页查询  
         Page<User> userPage = userMapper.selectPage(page, wrapper);  
         System.out.println("总记录数 = " + userPage.getTotal());  
         System.out.println("总页数 = " + userPage.getPages());  
         System.out.println("当前页码 = " + userPage.getCurrent());  
               // 获取分页查询结果  
         List<User> records = userPage.getRecords();  
         records.forEach(System.out::println);  
        }

    3. Results

  • 4. Other

    Note that the pagination query issued a total of 2 SQLs, once to check the total number of records, and once to check the specific data. If you want to not check the total number of records, only check the paged results . PageThe overloaded constructor that can be passed can be specified isSearchCountasfalse

    public Page(long current, long size, boolean isSearchCount)
    

    In actual development, you may encounter the scene of multi-table joint queryBaseMapper . At this time, the single-table paging query method provided in this article cannot meet the requirements, and you need to customize SQL . The example is as follows (use SQL for single-table query for demonstration, and actually perform multi-table query. When querying tables, just modify the SQL statement)

    1. Define a function in the mapper interface, receive a Page object as a parameter, and write custom SQL

    // 这里采用纯注解方式。当然,若SQL比较复杂,建议还是采用XML的方式  
    @Select("SELECT * FROM user ${ew.customSqlSegment}")  
    Page<User> selectUserPage(Page<User> page, @Param(Constants.WRAPPER) Wrapper<User> wrapper);
    

    2. Execute the query

    @Test  
    public void testPage2() {  
      LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();  
      wrapper.ge(User::getAge, 28).likeRight(User::getName, "王");  
      Page<User> page = new Page<>(3,2);  
      Page<User> userPage = userMapper.selectUserPage(page, wrapper);  
      System.out.println("总记录数 = " + userPage.getTotal());  
      System.out.println("总页数 = " + userPage.getPages());  
     userPage.getRecords().forEach(System.out::println);  
    }
    

    3. Results

Guess you like

Origin blog.csdn.net/weixin_46894136/article/details/131138081