Mybatis plus study notes

1, Quick start

mybatis+MP

Step 1:

Based on the original code, let the XXXMapper (such as UserMapper) interface inherit the BaseMapper interface, so you can use the following methods defined in BaseMapper:

Note that inheriting BaseMapper requires specifying the generic type of the entity class of the operation

public interface UserMapper extends BaseMapper<User> {
List<User> findAll();
}

Step 2: use MybatisSqlSessionFactoryBuilder in MP instead of SqlSessionFactoryBuilder in mybatis to build SqlSessionFactory objects

The integration is completed here. It can still be executed according to the original writing method of mybatis. If you want to use the method in BaseMapper to realize the function, you need to use @ TableName on the entity class object to specify the table name of the table to be operated., Otherwise, the database name will be found by default A lowercase table of entity classes
This is because the functions in baseMapper are used, and the sql statements are written by the mp plug-in, and we need to specify the table name.

spring+mybatis+MP

On the basis of integrating mybatis in spring, change the SqlSessionFactoryBean provided by mybatis to use the MybatisSqlSessionFactoryBean provided by mybatis plus

<!--Use here MP Provided sqlSessionFactory,It's done Spring And MP Integration of-->
<bean id="sqlSessionFactory"
class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
</bean>

2, CRUD operation

The following is a detailed explanation of the methods in BaseMapper:

Add: insert

Note that the return value of this method is not the id value after data insertion, but the number of rows affected by the database

The real id will be backfilled into the entity object after calling the method, so you only need to use entity to obtain the id of the newly inserted data Getid().

To realize Id self growth, it needs to be combined with @ TableId annotation
@TableId source code:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
public @interface TableId {
	//Specify the field name of the corresponding database
    String value() default "";
	//Specify id generation policy
    IdType type() default IdType.NONE;
}
public enum IdType {
    AUTO(0),//id self growth
    NONE(1),//The type is not set with primary key
    INPUT(2),// User input ID

/* The following two types are automatically filled only when the inserted object ID is empty. */
    ASSIGN_ID(3),
    ASSIGN_UUID(4);
    private final int key;
    private IdType(int key) {
        this.key = key;
    }
    public int getKey() {
        return this.key;
    }
}

@TableField source code:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
public @interface TableField {
	/*Specify the corresponding database field,
	The property name used to resolve the problem does not match the property name of the class*/
    String value() default "";
	
	/*Declare that the attribute has no corresponding field in the database,
	This field does not need to be considered when inserting*/
    boolean exist() default true;

	/*Specify that this field does not need to be queried during query*/
	boolean select() default true;

    String condition() default "";
    String update() default "";
    FieldStrategy insertStrategy() default FieldStrategy.DEFAULT;
    FieldStrategy updateStrategy() default FieldStrategy.DEFAULT;
    FieldStrategy whereStrategy() default FieldStrategy.DEFAULT;
    FieldFill fill() default FieldFill.DEFAULT;
    boolean keepGlobalFormat() default false;
    String property() default "";
    JdbcType jdbcType() default JdbcType.UNDEFINED;
    Class<? extends TypeHandler> typeHandler() default UnknownTypeHandler.class;
    boolean javaType() default false;
    String numericScale() default "";
}

change

Update by id: updateById

This method updates the non null fields in the entity according to the id of the entity.
For example:

@Test
public void testUpdateById() {
User user = new User();
user.setId(6L); //Primary key
user.setAge(21); //Updated fields
//Update according to id, update non null fields
this.userMapper.updateById(user);
}

Update according to conditions: int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) WrapperupdateWrapper);

Using QueryWrapper

@Test
public void testUpdate() {
User user = new User();
user.setAge(22); //Updated fields
//Updated conditions
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("id", 6);
//Perform update operation
int result = this.userMapper.update(user, wrapper);
}
}

Using UpdateWrapper

@Test
public void testUpdate() {
//Updated conditions and fields
UpdateWrapper<User> wrapper = new UpdateWrapper<>();
wrapper.set("age", 18).set("name","Zhang San").eq("id", 6);
//Perform update operation
int result = this.userMapper.update(null, wrapper);
}

Delete:

deleteById: delete by id

@Test
public void testDeleteById() {
//Perform delete operation
int result = this.userMapper.deleteById(6L);
System.out.println("result = " + result);
}

deleteByMap: use map as the parameter

@Test
public void testDeleteByMap() {
Map<String, Object> columnMap = new HashMap<>();
columnMap.put("age",20);
columnMap.put("name","Zhang San");
//Set the element in the columnMap as the deletion condition, and the relationship between multiple elements is and
int result = this.userMapper.deleteByMap(columnMap);
System.out.println("result = " + result);
}

delete: use QueryWrapper

@Test
public void testDeleteByMap() {
User user = new User();
user.setAge(20);
user.setName("Zhang San");
//Wrap the entity object as an operating condition
QueryWrapper<User> wrapper = new QueryWrapper<>(user);
int result = this.userMapper.delete(wrapper);
System.out.println("result = " + result);
}

deleteBatchIds: deletes batches by id

Method definition

int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable>idList);

Use the incoming ids collection. Note that ids cannot be an empty collection or null

@Test
public void testDeleteByMap() {
//Batch deletion based on id set
int result = this.userMapper.deleteBatchIds(Arrays.asList(1L,10L,20L));
System.out.println("result = " + result);
}

check

selectById

@Test
public void testSelectById() {
//Query data by id
User user = this.userMapper.selectById(2L);
System.out.println("result = " + user);
}

selectBatchIds

@Test
public void testSelectBatchIds() {
//Batch query based on id set
List<User> users = this.userMapper.selectBatchIds(Arrays.asList(2L, 3L, 10L));
for (User user : users) {
System.out.println(user);
}
}

selectOne

@Test
public void testSelectOne() {
QueryWrapper<User> wrapper = new QueryWrapper<User>();
wrapper.eq("name", "Li Si");
//Query a piece of data according to the criteria. If the result exceeds one, an error will be reported
User user = this.userMapper.selectOne(wrapper);
System.out.println(user);
}

selectCount

@Test
public void testSelectCount() {
QueryWrapper<User> wrapper = new QueryWrapper<User>();
wrapper.gt("age", 23); //Older than 23
//Query the number of data according to criteria
Integer count = this.userMapper.selectCount(wrapper);
System.out.println("count = " + count);
}

selectList

@Test
public void testSelectList() {
QueryWrapper<User> wrapper = new QueryWrapper<User>();
wrapper.gt("age", 23); //Older than 23
//Query data according to criteria
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println("user = " + user);
}
}

selectPage

Configure paging plug-in

@Configuration
@MapperScan("cn.edu.szu.Test.Mapper") //Set the scanning package of mapper interface
public class MybatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
@Test
public void testSelectPage() {
QueryWrapper<User> wrapper = new QueryWrapper<User>();
wrapper.gt("age", 20); //Older than 20
Page<User> page = new Page<>(1,1);//Page(currentPage,pageSize)
//Query data according to criteria
IPage<User> iPage = this.userMapper.selectPage(page, wrapper);
System.out.println("Total number of data:" + iPage.getTotal());
System.out.println("Total pages:" + iPage.getPages());
List<User> users = iPage.getRecords();
for (User user : users) {
System.out.println("user = " + user);
}
}

3, Disposition

Basic configuration

<bean id="sqlSessionFactory"
class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<!--MyBatis Configuration file location.
Please configure its path to configLocation Yes.-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>

<!--MyBatis Mapper Corresponding XML File location.
be careful: Maven The scan path of a multi module project needs to be classpath*: Start (i.e. load multiple) jar Under the bag XML (file)
-->
<property name="mapperLocations" value="classpath*:mybatis/*.xml"/>

<!--MyBaits Alias package scan path-->
<property name="typeAliasesPackage" value="com.baomidou.mybatisplus.samples.quickstart.entity"/>
</bean>

DB policy configuration

<!--Use here MP Provided sqlSessionFactory,It's done Spring And MP Integration of-->
<bean id="sqlSessionFactory"
class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
	<property name="dataSource" ref="dataSource"/>
		<property name="globalConfig">
		<bean class="com.baomidou.mybatisplus.core.config.GlobalConfig">
			<property name="dbConfig">
				<bean class="com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig">
					<!--Global default primary key type,
					After setting, you can omit the in the entity object@TableId(type=IdType.AUTO)to configure-->
					<property name="idType" value="AUTO"/>

					<!--Table name prefix, which can be omitted after global configuration@TableName()to configure-->
					<property name="tablePrefix" value="tb_"/>
				</bean>
			</property>
		</bean>
	</property>
</bean>

4, Conditional constructor Wrapper

The interface has two important implementation classes: AbstractWrapper and AbstractChainWrapper. It mainly studies AbstractWrapper

allEq

allEq(Map<R, V> params)
allEq(Map<R, V> params, boolean null2IsNull)
allEq(boolean condition, Map<R, V> params, boolean null2IsNull)
/* null2IsNull :Specifies whether null values are to be satisfied as a condition
 When true: isNull will be used as one of the conditions in the where part of the generated sql statement
 When it is false: this field will not be used as a condition to be met
*/

allEq(BiPredicate<R, V> filter, Map<R, V> params)
allEq(BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull)
allEq(boolean condition, BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull)
/*filter: Filter function, whether to allow the field to be passed into the comparison condition, which is often replaced by lambda expression
 For example: alleq ((k, V) - > k.equals ("name"), {ID: 1, name: "Lao Wang", age:null})
As described above, in the key value of the parameter map on the right, only the name field is used as the filter criteria.
*/

Basic comparison operation

eq: equal to=
neq: not equal to < >
gt: greater than >
ge: greater than or equal to >=
lt: less than<
le: less than or equal to<=
between: BETWEEN 1 AND 2
notBetween: NOT BETWEEN 1 AND 2
In: field in (value. Get (0), value get(1), …)
notIn: field NOT IN (v0, v1,...)

Fuzzy query

like:
Equivalent to LIKE% value%
Example: like("name", "Wang") - > name like '% Wang%'

notLike:
Equivalent to NOT LIKE '% value%'
Example: notLike("name", "Wang") - > name not like '%, Wang%'

likeLeft:
Equivalent to LIKE '% value'
Example: likeLeft("name", "King") - > name like '% King'

likeRight:
Equivalent to LIKE 'value%'
Example: likereight ("name", "Wang") - > name like "Wang%"

sort

orderBy:
Sorting: ORDER BY field
Example: orderBy(true, true, "id", "name") - > order by id ASC, name ASC

orderByAsc
Sorting: ORDER BY field,... ASC
Example: orderByAsc("id", "name") - > order by id ASC, name ASC

orderByDesc
Sorting: ORDER BY field,... DESC
Example: orderByDesc("id", "name") - > order by id DESC, name desc

Logical query

or
Splice OR
Actively calling or means that the next method is not connected with and! (if or is not called, and connection is used by default.)

//SELECT id,user_name,password,name,age,email FROM tb_user WHERE name = ? OR age = ?
wrapper.eq("name","Li Si").or().eq("age", 24);

select

//SELECT id,name,age FROM tb_user WHERE name = ? OR age = ?
wrapper.eq("name", "Li Si")`Insert code slice here`
.or()
.eq("age", 24)
.select("id", "name", "age");

5, ActiveRecord

The main idea of ActiveRecord is:
1. Create a class for each database table, and each object instance of the class corresponds to a row of records in the database table; Generally, each Field of the table has a corresponding Field in the class;
2.ActiveRecord is also responsible for persisting itself. ActiveRecord encapsulates the access to the database, namely CURD;
3.ActiveRecord is a domain model that encapsulates some business logic;

Use of ActiveRecord:
You can use some defined CRUD operations by inheriting the entity object from the Model.

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User extends Model<User> {
private Long id;
private String userName;
private String password;
private String name;
private Integer age;
private String email;
}
@Test
public void testAR() {
//select
User user = new User();
user.setId(2L);
User user2 = user.selectById();

//insert
user.setName("Liu Bei");
user.setAge(30);
user.setPassword("123456");
user.setUserName("liubei");
user.setEmail("liubei@itcast.cn");
boolean insert = user.insert();

//update
user.setId(8L);
user.setAge(35);
boolean update = user.updateById();

//delete
user.setId(1L);
}

//Query by criteria
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
userQueryWrapper.le("age","20");
List<User> users = user.selectList(userQueryWrapper);

6, Plug in

Interceptor plug-in

Types of methods that interceptors can intercept:

  1. Method of intercepting actuator:
    Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)

  2. Processing of interception parameters:
    ParameterHandler (getParameterObject, setParameters)

  3. Processing of interception result set:
    ResultSetHandler (handleResultSets, handleOutputParameters)

  4. Processing of intercepting Sql syntax Construction:
    StatementHandler (prepare, parameterize, batch, update, query)

Use of interceptors:

@Intercepts({@Signature(
type= Executor.class,
method = "update",
args = {MappedStatement.class,Object.class})})
public class MyInterceptor implements Interceptor {
	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		//Interception method, location of specific business logic writing
		return invocation.proceed();
	}
	@Override
	public Object plugin(Object target) {
		//Create a proxy object for the target object to add the current interceptor to the object
		/*This method will be called four times, corresponding to the above four method types*/


		return Plugin.wrap(target, this);
	}
	@Override
	public void setProperties(Properties properties) {
		//Property settings
	}
}

Execute analysis plug-in

The MP provides a plug-in for the analysis of SQL execution, which can be used to block the operation of updating and deleting the whole table. When updating and deleting the whole table, the plug-in will block the operation and throw an exception to prevent misoperation.
be careful:
The plug-in is only applicable to the development environment, not the production environment.

to configure:

@Bean
public SqlExplainInterceptor sqlExplainInterceptor(){
SqlExplainInterceptor sqlExplainInterceptor = new SqlExplainInterceptor();
List<ISqlParser> sqlParserList = new ArrayList<>();
// Attack SQL, block parser and join parsing chain
sqlParserList.add(new BlockAttackSqlParser());
sqlExplainInterceptor.setSqlParserList(sqlParserList);
return sqlExplainInterceptor;
}

Performance analysis plug-in

The performance analysis interceptor is used to output each SQL statement and its execution time. The maximum execution time can be set. If it exceeds the time, an exception will be thrown.

<configuration>
<plugins>
<!-- SQL Perform performance analysis and use the development environment, which is not recommended online. maxTime refer to sql Maximum execution time -->
<plugin
interceptor="com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor">
<property name="maxTime" value="100" />
<!--SQL Format default false-->
<property name="format" value="true" />
</plugin>
</plugins>
</configuration>

Optimistic lock plug-in

Requirements: solve the problem of modifying the same data concurrently.

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
If the version is incorrect, the update fails

to configure:
xml configuration:

 <bean class="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor"/>

Annotation configuration:

@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}

use:
1. Add the version field on the table to be operated and set the initial value to 1
2. Add Version attribute on entity class and use @ Version annotation

@Version
private Integer version;

Auto fill function

Sometimes we may have such requirements. When inserting or updating data, we hope that some fields can be filled with data automatically, such as password and version
Wait.

1. Add @ TableField annotation

@TableField(fill = FieldFill.INSERT) //Populate when inserting data
private String password;

public enum FieldFill {
DEFAULT,
INSERT,
UPDATE,
INSERT_UPDATE
}

2. Write MyMetaObjectHandler

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
	Object password = getFieldValByName("password", metaObject);
			if(null == password){
			//The field is empty and can be filled in
			setFieldValByName("password", "123456", metaObject);
		}
	}
		@Override
		public void updateFill(MetaObject metaObject) {
	}
}

Logical deletion

When developing the system, sometimes when realizing the function, the deletion operation needs to realize logical deletion. The so-called logical deletion is to mark the data as deletion, rather than the real physical deletion (non DELETE operation). The status conditions need to be carried during the query to ensure that the marked data is not queried. The purpose of this is to prevent the data from being really deleted.

1. Add the delete field to the database table
2. Use @ TableLogic annotation for the corresponding fields in the entity class

@TableLogic
private Integer deleted;

application. Configuration in properties:

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

Keywords: Java Spring

Added by trollll on Sat, 26 Feb 2022 17:38:59 +0200