mybatis_plus -- CRUD, extension, plug-in

Posted by Q on Wed, 06 Oct 2021 01:46:06 +0200

1. Mapper CRUD interface

  • The universal CRUD encapsulates the BaseMapper (opens new window) interface, which automatically resolves the entity table relationship mapping when Mybatis plus starts, and transforms it into the Mybatis internal object injection container
  • Generic T is any entity object
  • Wrapper updateWrapper entity object encapsulates the operation class (can be null, and the entity in it is used to generate the where statement)
  • The parameter Serializable is any type of primary key. Mybatis plus does not recommend using the compound primary key convention. Each table has its own unique id primary key
  • The object Wrapper is a conditional constructor

1.1 Insert - add User - default ID_WORKER globally unique id

Syntax:

// Insert a record
int insert(T entity); 

The insert operation will automatically generate the id, return the number of affected rows, and the id will automatically backfill the value User object

The default value of the id inserted in the database is the global unique id

// Test insertion
@Test
public void testInsert(){
  User user = new User();
  user.setName("mybatis_plus");
  user.setAge(3);
  user.setEmail("12345678@qq.com");
  int result = userMapper.insert(user); // Help us automatically generate id
  System.out.println(result); // Number of rows affected
  System.out.println(user); // If found, id will be backfilled automatically
}

Extension: primary key (id) generation policy - id is automatically generated during insertion

fielddescribe
AUTODatabase ID self increment
NONEStateless. This type has no primary key set (in the annotation, it is equal to follow the global, and the global value is equal to INPUT)
INPUTset the primary key value before insert ing
ASSIGN_IDAssign ID (the primary key type is Number(Long and Integer) or String)(since 3.3.0), and use the method NextID of interface - IdentifierGenerator (the default implementation class is DefaultIdentifierGenerator)
ASSIGN_UUIDAllocate UUID. The primary key type is String(since 3.3.0). Use the method of interface IdentifierGenerator - nextuuid (default method)
ID_WORKERDistributed globally unique ID long integer type (please use ASSIGN_ID)
UUID32-bit UUID string (please use ASSIGN_UUID)
ID_WORKER_STRDistributed globally unique ID string type (please use ASSIGN_ID)

1) ID_WORKER globally unique id – snowflake algorithm

Generation of unique id of distributed system: https://www.cnblogs.com/haoxinyue/p/5208136.html

Snowflake algorithm:
snowflake is Twitter's open source distributed ID generation algorithm, and the result is a long ID. Its core idea is to use 41bit as
In milliseconds, 10bit is used as the machine ID (5 bits are the data center and 5 bits are the machine ID), and 12bit is used as the serial number within milliseconds (meaning
It means that each node can generate 4096 ID S per millisecond), and finally there is a symbol bit, which is always 0. Can guarantee almost global only
One!

2) Set primary key generation policy

@ TableId(type = IdType.AUTO) on entity class field

public class User {
    @TableId(type = IdType.UUID)
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

1.2 Update – update User data with id 3

Syntax:

// Update the record according to the whereWrapper condition
int update(@Param(Constants.ENTITY) T updateEntity, @Param(Constants.WRAPPER) Wrapper<T> whereWrapper);
// Modify according to ID
int updateById(@Param(Constants.ENTITY) T entity);

updateById, but the parameter is an object! Update automatically splices dynamic sql through conditions

// Test update
@Test
public void testUpdate(){
  User user = new User();
  // Automatic splicing of dynamic sql through conditions
  user.setId(3L);//long type
  user.setName("mybayis_plus");
  user.setAge(18);
  // Note: updateById, but the parameter is an object!
  int i = userMapper.updateById(user);
  System.out.println(i);
}

Extension: auto fill – automatically fill data when inserting and updating

Automatically fill in the creation time and modification time! These operations are completed automatically. We don't want to update them manually!

Alibaba Development Manual: all database tables: gmt_create,gmt_modified almost all tables should be configured! And need
Automation!

1) Annotation needs to be added on the field attribute of entity class

  • DEFAULT is not processed by DEFAULT
  • INSERT fill fields when inserting
  • Fill in fields when UPDATE
  • INSERT_UPDATE fill fields when inserting and updating
// Add padding to fields
@TableField(fill = FieldFill.INSERT)
private Date createTime;

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

2) Write a processor to handle this annotation

@Slf4j
@Component // Don't forget to add the processor to the IOC container!
public class MyMetaObjectHandler implements MetaObjectHandler {

// Population policy at insertion
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill.....");
// setFieldValByName(String fieldName, Object fieldVal, MetaObject
metaObject
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}

// Population policy when updating
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill.....");
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}

Plug in: optimistic lock - when you want to update a record, you hope that the record has not been updated by others

Optimistic lock: hence the name Siyi is very optimistic. It always thinks that there will be no problem. No matter what you do, don't lock it! If something goes wrong,
Update value test again
Pessimistic lock: hence the name Siyi is very pessimistic. It always thinks that there is always a problem and it will lock no matter what it does! Do it again!
Optimistic lock implementation method:

  • When the record is fetched, the current version is obtained
  • When updating, bring this version
  • When updating, set version = newVersion where version = oldVersion
    newVersion = oldVersion + 1 auto assemble
  • If the version is incorrect, the update fails

1. Only supported data types are: int,Integer,long,Long,Date,Timestamp,LocalDateTime
2. newVersion = oldVersion + 1 under integer type
3.newVersion will be written back to entity
4. Only updateById(id) and update(entity, wrapper) methods are supported
5. Under the update(entity, wrapper) method, the wrapper cannot be reused!!!

1) Register components in configuration class

// Scan our mapper folder
@MapperScan("com.yanyu.mapper")
@EnableTransactionManagement
@Configuration // Configuration class
public class MyBatisPlusConfig {
// Register optimistic lock plug-in
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}

2) Add annotations to the corresponding fields of the entity class

@Version //Optimistic lock Version annotation
private Integer version;

1.3 Select

Syntax:

// Query by ID
T selectById(Serializable id);
// Query a record according to the entity condition
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// Query (batch query by ID)
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// Query all records according to the entity condition
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// Query (based on columnMap criteria)
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
// Query all records according to Wrapper conditions
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// Query all records according to Wrapper conditions. Note: only the value of the first field is returned
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// Query all records (and turn the page) according to the entity condition
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// Query all records (and turn pages) according to Wrapper conditions
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// Query the total number of records according to Wrapper conditions
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

Query test:

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

// Test batch query!
@Test
public void testSelectByBatchId(){
List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
users.forEach(System.out::println);
}

// Using map operations by one of the conditional queries
@Test
public void testSelectByBatchIds(){
HashMap<String, Object> map = new HashMap<>();
// Custom query
map.put("name","mybatis_plus");
map.put("age",3);
List<User> users = userMapper.selectByMap(map);
users.forEach(System.out::println);
}

Plug in: pagination – pagination of query data

1) Register components in configuration class

@Configuration
@MapperScan("scan.yanyu.mapper")
public class MybatisPlusConfig {

@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}

2) Testing

Syntax:

// Query all records (and turn the page) according to the entity condition
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// Query all records (and turn pages) according to Wrapper conditions
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// Query the total number of records according to Wrapper conditions
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

Test:

  • The IPage of the input parameter cannot be null because the returned IPage = = the IPage of the input parameter
  • List returned by IPage.setRecords;
// Test paging query
@Test
public void testPage(){
// Parameter 1: current page
// Parameter 2: page size
// After using the paging plug-in, all paging operations become simple!
 Page<User> page = new Page<>(2,5);
 userMapper.selectPage(page,null);
 page.getRecords().forEach(System.out::println);
 System.out.println(page.getTotal());
}

3) Custom mapper uses pagination

If the return type is IPage, the IPage of the input parameter cannot be null because the returned IPage = = the IPage of the input parameter
If the return type is List, the IPage of the input parameter can be null (null does not page), but you need to manually enter the IPage of the parameter
Ipage.setrecords (returned List);

IPage<UserVo> selectPageVo(IPage<?> page, Integer state);
// or (class MyPage extends Ipage<UserVo>{ private Integer state; })
MyPage selectPageVo(MyPage page);
// or
List<UserVo> selectPageVo(IPage<UserVo> page, Integer state);
---------------------------------------------------------
<select id="selectPageVo" resultType="xxx.xxx.xxx.UserVo">
    SELECT id,name FROM user WHERE state=#{state}
</select>

1.4 Delete

Syntax:

// Delete the record according to the entity condition
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
// Delete (batch delete according to ID)
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// Delete by ID
int deleteById(Serializable id);
// Delete the record according to the columnMap condition
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

Test delete

@Test
public void testDeleteById(){
userMapper.deleteById(1L);
}
// Batch delete by id
@Test
public void testDeleteBatchId(){
userMapper.deleteBatchIds(Arrays.asList(1L,2L));
}
// Delete by map
@Test
public void testDeleteMap(){
HashMap<String, Object> map = new HashMap<>();
map.put("name","Madness theory Java");
userMapper.deleteByMap(map);
}

Extensions: logical deletion

Physical delete: remove directly from the database
Logical deletion: it is not removed from the database, but invalidated by a variable! deleted = 0 => deleted = 1

explain:

Only works for automatically injected sql:

  • Insert: no restrictions
  • Find: append a where condition to filter the deleted data, and the where condition generated by wrapper.entity will ignore this field
  • Update: append a where condition to prevent updating to deleted data, and the where condition generated using wrapper.entity will ignore this field
  • Delete: convert to update

For example:
Delete: update user set deleted=1 where id = 1 and deleted=0
Search: select id,name,deleted from user where deleted=0

Field type support Description:
All data types are supported (integer, Boolean, localdatetime are recommended)
If the database field uses datetime, the logical undeleted value and deleted value can be configured as string null, and the other value can be configured as a function to obtain the value, such as now()

1) Configure class registration component

// Delete components logically!
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}

2) The Profile sets logical undeleted and deleted values

mybatis-plus:
  global-config:
    db-config:
      logic-delete-value: 1 # Logical deleted value (default is 1)
      logic-not-delete-value: 0 # Logical undeleted value (0 by default)

3) Add annotation to entity class field

@TableLogic //Logical deletion
private Integer deleted;

Topics: Java Database