Mybatis and MybatisPlus3.4 Use
- Mybatis and MybatisPlus3.4 Use
- 1 RESTFUL
- 2 Reverse engineering
- 2.1 tkMybatis Reverse engineering
- 2.2 MybatisPlus Use the tutorial
- 2.2.1 stay mapper Add dependencies to subprojects
- 2.2.2 To configure application.yml
- 2.2.3 To configure @MapperScan
- 2.2.4 Write entity class Users
- 2.2.5 To write Mapper.java Inheritance template BaseMapper
- 2.2.6 Test whether... Can be called normally MP
- 2.2.7 Configuration log
- 2.2.8 CRUD Expand
- 2.2.9 Optimism lock
- 2.2.10 Inquire about
- 2.2.11 Delete
- 2.2.12 Performance analysis plug-ins ( The new version has been removed )
- 2.2.13 Conditional constructor wrapper
- 2.2.14 Code generator ,MP Reverse engineering
- 3 Solutions to common problems
1 RESTFUL
Front and back wind in the project you develop , Between the front and back end is the interface for request and response , When the back end provides a request to the front end, it will expose a URL;URL Your design cannot be arbitrary , Need to comply with certain design specifications ----RESTFUL.
RESTful It's a kind of web api Standards for , It's a kind of url Design style / standard
-
Every URL The request path represents the only resource on the server .
Conventional URL Design :
http://localhost:8080/goods/delete?goodsId=1 goods 1
http://localhost:8080/goods/delete?goodsId=2 goods 2
RESTful Design :
http://localhost:8080/goods/delete/1 goods 1
http://localhost:8080/goods/delete/1 goods 1
Example :
@DeleteMapping("/delete/{id}") public ResultVO deleteGoods(@PathVariable("id") Integer goodsId) { return new ResultVO(10003," The request is successful ",goodsId); }
-
Different requests are used to represent different operations , Ensure that the only URL Corresponding to a unique resource
- @GetMapping Inquire about
- @PutMapping modify
- @PostMapping add to
- @DeleteMapping Delete
according to id Delete a product :
//http://localhost:8080/goods/1 [delete] @DeleteMapping("/{id}") public ResultVO deleteGoods(@PathVariable("id") Integer goodsId) { return new ResultVO(10003," The request is successful ",goodsId); }
according to id Query a product :
//http://localhost:8080/goods/1 [get] @GetMapping("/{id}") public ResultVO getGoods(@PathVariable("id") Integer goodsId) { return new ResultVO(10003," The request is successful ",goodsId); }
-
The resource representation of the interface response uses JSON
- You can add... On the control class or the required interface method
@ResponseBody
The annotation says that the returned object is formatted as JSON - You can also use... On control classes
@RestController
Declare controller
- You can add... On the control class or the required interface method
-
front end (Android\ios\PC) Through stateless HTTP The protocol interacts with the back-end interface
2 Reverse engineering
mybatis The official provides a method to generate data from database tables mybatis Tools for executing code , This tool is a reverse engineering
Reverse engineering : For database single table —-> The generated code (
mapper.xml、mapper.java、pojo..
)What I started using here is
mybatis
Reverse engineering , Can generatemapper.xml、mapper.java、pojo
Later I want to try to use
MP
Do reverse engineering , So two ways are used , In terms of brevity , stillMP
It's more convenient .
2.1 tkMybatis Reverse engineering
Reverse engineer and automatically add swagger annotation , Note the need for beans Of pom Also add swagger rely on
2.1.1 Import dependence
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.1.5</version>
</dependency>
- Modify startup class annotation
@MapperScan
My bag , Because this annotation also has a package that isorg.mybatis.spring.annotation.MapperScan;

2.1.2 Add the plug-in
<build>
<plugins>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.5</version>
<configuration>
<verbose>true</verbose>
<overwrite>true</overwrite>
<configurationFile>${basedir}/src/main/resources/generator/generatorConfig.xml</configurationFile>
</configuration>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mariadb.jdbc/mariadb-java-client --><!-- https://mvnrepository.com/artifact/tk.mybatis/mapper -->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper</artifactId>
<version>4.1.5</version>
</dependency>
<dependency>
<groupId>com.github.misterchangray.mybatis.generator.plugins</groupId>
<artifactId>myBatisGeneratorPlugins</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
After the synchronization is successful, a

2.1.3 Add configuration file
generatorConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!-- Import property configuration -->
<!-- <properties resource="db.properties"></properties>-->
<!-- Specify... For a specific database jdbc drive jar The location of the package -->
<!--<classPathEntry location="${jdbc.location}"/>-->
<context id="Mysql" targetRuntime="MyBatis3Simple" defaultModelType="flat">
<property name="beginningDelimiter" value="`"/>
<property name="endingDelimiter" value="`"/>
<!-- Combined with universal Mapper plug-in unit Specify generation Mapper Inheritance template -->
<plugin type="tk.mybatis.mapper.generator.MapperPlugin">
<property name="mappers" value="com.mymall.general.GeneralDao"/>
</plugin>
<!--pojo implements Serializable -->
<plugin type="org.mybatis.generator.plugins.SerializablePlugin" />
<!--pojo Class toString Method -->
<plugin type="org.mybatis.generator.plugins.ToStringPlugin" />
<!-- Overlay generation XML file Every time you execute , Put the old mapper.xml Overwrite instead of merge -->
<!-- <plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin" />-->
<!-- Automatically for entity Generate swagger2 file -->
<plugin type="mybatis.generator.plugins.GeneratorSwagger2Doc">
<property name="apiModelAnnotationPackage" value="io.swagger.annotations.ApiModel"/>
<property name="apiModelPropertyAnnotationPackage" value="io.swagger.annotations.ApiModelProperty"/>
</plugin>
<!-- Be careful , plugin It needs to be written in commentGenerator above -->
<commentGenerator>
<!-- Remove automatically generated comments or not true: yes : false: no -->
<property name="suppressAllComments" value="false" />
</commentGenerator>
<!--jdbc Database connection to -->
<jdbcConnection
driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mymall?useSSL=false&serverTimezone=GMT%2b8"
userId="root"
password="123456">
<property name="nullCatalogMeansCurrent" value="true"/>
</jdbcConnection>
<!-- Generate JavaBean Object rewriting toString Method -->
<!-- <plugin type="org.mybatis.generator.plugins.ToStringPlugin" />-->
<!-- Generate JavaBean Object inheritance Serializable class -->
<!-- <plugin type="org.mybatis.generator.plugins.SerializablePlugin" />-->
<!-- Generate JavaBean Object rewriting equals and hashCode Method -->
<!-- <plugin type="org.mybatis.generator.plugins.EqualsHashCodePlugin" /> -->
<!-- Corresponding generated pojo Location package -->
<javaModelGenerator targetPackage="com.mymall.entity" targetProject="src/main/java">
<!-- Whether the model add to Constructors -->
<property name="constructorBased" value="true"/>
</javaModelGenerator>
<!-- Corresponding generated mapper.xml In the directory -->
<sqlMapGenerator targetPackage="/" targetProject="src/main/resources/mappers"/>
<!-- To configure mapper Corresponding java mapping -->
<javaClientGenerator targetPackage="com.mymall.dao" targetProject="src/main/java"
type="XMLMAPPER"/>
<!-- Configuration needs to specify the generated database and tables ,% For all tables , Don't do this in development , Many useless tables may be generated -->
<!-- <table tableName="%"/>-->
<table tableName="category" />
<table tableName="index_img" />
<table tableName="order_item" />
<table tableName="orders" />
<table tableName="product" />
<table tableName="product_comments" />
<table tableName="product_img" />
<table tableName="product_params" />
<table tableName="product_sku" />
<table tableName="shopping_cart" />
<table tableName="user_addr" />
<table tableName="user_login_history" />
<table tableName="users" />
<!-- <table schema="" tableName="oauth_access_token" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false">
<domainObjectRenamingRule searchString="^Tb" replaceString="" />
</table>
<table schema="" tableName="oauth_approvals" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false">
<domainObjectRenamingRule searchString="^Tb" replaceString="" />
</table>-->
<!-- List all the tables you want to generate -->
</context>
</generatorConfiguration>
-
Adjust configuration information
-
establish
GeneralDao
Interfacepackage com.mymall.general; import tk.mybatis.mapper.common.Mapper; import tk.mybatis.mapper.common.MySqlMapper; /** * @author 18230 * @version 1.0.0 * @ClassName GereralDao.java * @Description * @createTime 2021 year 09 month 25 Japan 15:50:00 */ public interface GeneralDao<T> extends Mapper<T>, MySqlMapper<T> { }
<!-- To configure GeneralDao--> <plugin type="tk.mybatis.mapper.generator.MapperPlugin"> <property name="mappers" value="com.mymall.general.GneralDao"/> </plugin>
-
Configure the database connection information
<!--jdbc Database connection to ,url Do not modify the following configuration --> <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/mymall?useSSL=false&serverTimezone=GMT%2b8" userId="root" password="123456"> </jdbcConnection>
-
Configure the entity classpath
<!-- Corresponding generated pojo Location package --> <javaModelGenerator targetPackage="com.mymall.entity" targetProject="src/main/java"> <!-- Whether the model add to Constructors --> <property name="constructorBased" value="true"/> </javaModelGenerator>
-
To configure
mapper.xml
Catalog<!-- Corresponding generated mapper.xml In the directory --> <sqlMapGenerator targetPackage="/" targetProject="src/main/resources/mappers"/>
-
To configure dao The directory of and the name of the generated table
<!-- To configure mapper Corresponding java mapping --> <javaClientGenerator targetPackage="com.mymall.dao" targetProject="src/main/java" type="XMLMAPPER"/> <!-- Configuration needs to specify the generated database and tables ,% For all tables , Don't do this in development , Many useless tables may be generated --> <!-- <table tableName="%"/>--> <table tableName="category" /> <table tableName="index_img" /> <table tableName="order_item" /> <table tableName="orders" /> <table tableName="product" /> <table tableName="product_comments" /> <table tableName="product_img" /> <table tableName="product_params" /> <table tableName="product_sku" /> <table tableName="shopping_cart" /> <table tableName="user_addr" /> <table tableName="user_login_history" /> <table tableName="users" />
-
Set profile
generatorConfig.xml
Configuration to reverse engineering maven Plug in<groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.3.5</version> <configuration> <configurationFile>${basedir}/src/main/resources/generator/generatorConfig.xml</configurationFile> </configuration>
-
2.1.4 Reverse execution

2.1.5 Generate successfully

-
The generated entity Cut to beans In subprojects
The generated entity Move to beans An error will appear after the directory , Because of the use of tkMapper Annotations , So we need to tkMapper The dependency of is cut directly to beans in ,mapper Project references beans So we can no longer pom In a statement tkMapper Rely on the .
2.1.6 Use tkMybatis
package com.qc.dao;
import com.qc.TkMapperDemoApplication;
import com.qc.entity.Category;
import org.apache.ibatis.session.RowBounds;
import org.junit.Assert;
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 tk.mybatis.mapper.entity.Example;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
/**
* @author 18230
* @version 1.0.0
* @ClassName CategoryDaoTest.java
* @Description
* @createTime 2021 year 09 month 05 Japan 20:40:00
*/
@SpringBootTest(classes = TkMapperDemoApplication.class)
@RunWith(SpringRunner.class)
public class CategoryDaoTest {
@Autowired
private CategoryDao categoryDao;
@Test
public void testInsert() {
Category category = new Category(0,"test02",1,0,"01.png","hehe","111.jpg","black");
// Insert data into the table , Return results ,1, success
//int i = categoryDao.insert(category);
// After the data is inserted, the generated primary key is returned to the object for saving
int i = categoryDao.insertUseGeneratedKeys(category);
System.out.println(category.getCategoryId());
assertEquals(1,i);
}
@Test
public void testUpdate() {
Category category = new Category(13,"test03",1,0,"01.png","hehe","111.jpg","black");
// Modify the data according to the primary key
int i = categoryDao.updateByPrimaryKey(category);
assertEquals(1,i);
}
@Test
public void testDelete() {
// Delete data according to the primary key
int i = categoryDao.deleteByPrimaryKey(13);
assertEquals(1,i);
}
@Test
public void testSelect1() {
// Query all
List<Category> categories = categoryDao.selectAll();
for (Category category : categories) {
System.out.println(category);
}
}
@Test
public void testSelect2() {
// Query according to the primary key
Category category = categoryDao.selectByPrimaryKey(13);
System.out.println(category);
}
@Test
public void testSelect3() {
// Conditions of the query
// 1. Create a example encapsulation , Category category Query criteria
Example example = new Example(Category.class);
Example.Criteria criteria = example.createCriteria();
//criteria.andEqualTo("categoryLevel", 1);
criteria.andLike("categoryName", "% dry %");
List<Category> categories = categoryDao.selectByExample(example);
for (Category category : categories) {
System.out.println(category);
}
}
@Test
public void testSelect4() {
// Paging query
int pageNum = 2;
int pageSize= 5;
int start =(pageNum-1)*pageSize;
RowBounds rowBounds = new RowBounds(start,pageSize);
List<Category> categories = categoryDao.selectByRowBounds(new Category(), rowBounds);
for (Category category : categories) {
System.out.println(category);
}
// Total number of records queried
int i = categoryDao.selectCount(new Category());
System.out.println(i);
}
@Test
public void testSelect5() {
// Preparation conditions
Example example = new Example(Category.class);
Example.Criteria criteria = example.createCriteria();
criteria.andEqualTo("categoryLevel", 1);
// Prepare paging conditions
int pageNum = 1;
int pageSize= 3;
int start =(pageNum-1)*pageSize;
RowBounds rowBounds = new RowBounds(start,pageSize);
// Conditional pagination display
List<Category> categories = categoryDao.selectByExampleAndRowBounds(example, rowBounds);
for (Category category : categories) {
System.out.println(category);
}
// Query the number of records that meet the criteria
int i = categoryDao.selectCountByExample(example);
System.out.println(i);
}
}
2.2 MybatisPlus Use the tutorial
2.2.1 stay mapper Add dependencies to subprojects
Creating mapper Sub projects have been added
mybatis-plus-boot-starter
, So there is no need to add additional dependencies
2.2.2 To configure application.yml
Then used
mysql8
when , need mysql The drive is the same as :com.mysql.cj.jdbc.Driver
, At the same time, you need to add time zone settings :serverTimezone=GMT%2b8
datasource:
druid:
# Database connection driver
driver-class-name: com.mysql.cj.jdbc.Driver
# Database connection address
url: jdbc:mysql://localhost:3306/mymall?serverTimezone=GMT%2b8&useSSL=false&allowPublicKeyRetrieval=true
# Database connection user name and password
username: root
password: 123456
2.2.3 To configure @MapperScan
package com.mymall;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import springfox.documentation.oas.annotations.EnableOpenApi;
@SpringBootApplication
@MapperScan("com.mymall.dao")
@EnableOpenApi
public class ApiApplication {
public static void main(String[] args) {
SpringApplication.run(ApiApplication.class, args);
}
}
2.2.4 Write entity class Users
package com.mymall.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Users {
Integer userId;
String username;
String password;
}
2.2.5 To write Mapper.java
Inheritance template BaseMapper
package com.mymall.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mymall.entity.Users;
import org.springframework.stereotype.Repository;
@Repository
public interface UsersMapper extends BaseMapper<Users> {
}
2.2.6 Test whether... Can be called normally MP
package com.mymall;
import com.mymall.entity.Users;
import com.mymall.dao.UsersMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
class ApiApplicationTests {
@Autowired
private UsersMapper usersMapper;
@Test
void contextLoads() {
List<Users> users = usersMapper.selectList(null);
for (Users user : users) {
System.out.println(user);
}
System.out.println(users);
}
}
Test success !
2.2.7 Configuration log
mybatis-plus:
configuration:
# Configuration log
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
According to the effect

2.2.8 CRUD Expand
2.2.8.1 Database insert id The default value of : The only one in the world id
-
Generation strategy : Distributed systems are unique ID Generate scheme summary - nick hao - Blog Garden (cnblogs.com)
-
Snowflake algorithm :snowflake yes Twitter Open source distributed ID generating algorithm , The result is a long Type ID. The central idea is this : Use 41bit As milliseconds ,10bit As a machine ID(5 individual bit It's the data center ,5 individual bit Machine ID),12bit As a serial number in milliseconds ( It means that every node can produce 4096 individual ID), And finally, there's a sign bit , Forever 0. The specific implementation code can be seen in https://github.com/twitter/snowflake. Snowflake algorithm supports TPS You can achieve 419 All around (2^22*1000).
-
Be careful :
Use snowflakes or uuid The fields in the data cannot be self incremented , Otherwise it won't work .
-
Set requirements :
-
The primary key needs to be set to auto increment
-
Add... To the entity class field
MP
annotation@TableId(type = IdType.ASSIGN_ID)
-
IdType
Type source codepackage com.baomidou.mybatisplus.annotation; import lombok.Getter; /** * Generate ID Type enumeration class * * @author hubin * @since 2015-11-10 */ @Getter public enum IdType { /** * database ID Self increasing * <p> Please make sure that the database is set with ID Self increasing Otherwise it will not work </p> */ AUTO(0), /** * The type is not set as primary key type ( The annotation follows the whole situation , Global Rio equals INPUT) */ NONE(1), /** * User input ID * <p> This type can be filled by registering the auto fill plug-in </p> */ INPUT(2), /* following 2 Types 、 Only when inserting objects ID It's empty , To automatically fill in . */ /** * Distribute ID ( The primary key type is number or string), * Default implementation class {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}( Snowflake algorithm ) * * @since 3.3.0 */ ASSIGN_ID(3), /** * Distribute UUID ( The primary key type is string) * Default implementation class {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(UUID.replace("-","")) */ ASSIGN_UUID(4), private final int key; IdType(int key) { this.key = key; } }
-
-
Insert Automatic generation id
@Test// Test insert public void insertTest(){ User user = new User(); user.setName("wsk"); user.setEmail("[email protected]"); Integer result = userMapper.insert(user); // It will help us automatically generate id System.out.println(result); // Rows affected System.out.println(user); // Log discovery id It will automatically backfill }

2.2.8.2 Auto fill
Creation time 、 Change the time ! These operations are generally automated , We don't want to manually update
Alibaba Development Manual ︰ Almost all tables need to be configured gmt_create、gmt_modified ! And it needs to be automated
-
Mode one : Database level ( It is not allowed to modify the database level in the work )
1、 Add fields... To the table :create_time,update_time
-- auto-generated definition create table mp_user ( user_id bigint auto_increment comment ' user id' primary key, username varchar(32) not null comment ' user name ', password varchar(32) not null comment ' password ', create_time datetime default CURRENT_TIMESTAMP not null comment ' Creation time ', update_time datetime default CURRENT_TIMESTAMP not null comment ' Update time ' );
2、 Update the member variables in the entity class
package com.mymall.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.util.Date; @Data @AllArgsConstructor @NoArgsConstructor public class MpUser { @TableId(type = IdType.ASSIGN_ID) Long userId; String username; String password; Date createTime; Date updateTime; }
3、 The code that inserts or updates a piece of data before running again shows the successful automatic insertion time
-
Mode two : Code level
1、 Delete the default value of the database , update operation !
2、 You need to add annotation to the field attribute of entity class
@Data @AllArgsConstructor @NoArgsConstructor public class MpUser { @TableId(type = IdType.ASSIGN_ID) Long userId; String username; String password; // Comments on insertion @TableField(fill = FieldFill.INSERT) Date createTime; // Comments when updating @TableField(fill = FieldFill.UPDATE) Date updateTime; }
Annotation details
package com.baomidou.mybatisplus.annotation; /** * Field fill policy enumeration class * <p> * Judge the injected insert and update Of sql Whether the script ignores the field in the corresponding case if Tag generation * <if test="...">......</if> * Judge priority ratio {@link FieldStrategy} high * </p> * @author hubin * @since 2017-06-27 */ public enum FieldFill { /** * Default not to handle */ DEFAULT, /** * Fill in fields when inserting */ INSERT, /** * Fill in fields when updating */ UPDATE, /** * Fill in fields when inserting and updating */ INSERT_UPDATE }
3、 Write a processor to handle the annotation !
@Slf4j @Component public class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { log.info("start insert fill ...."); this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); // Starting version 3.3.0( Recommended ) // perhaps this.strictInsertFill(metaObject, "createTime", () -> LocalDateTime.now(), LocalDateTime.class); // Starting version 3.3.3( recommend ) // perhaps this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); // You can also use (3.3.0 This method has bug) } @Override public void updateFill(MetaObject metaObject) { log.info("start update fill ...."); this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // Starting version 3.3.0( recommend ) // perhaps this.strictUpdateFill(metaObject, "updateTime", () -> LocalDateTime.now(), LocalDateTime.class); // Starting version 3.3.3( recommend ) // perhaps this.fillStrategy(metaObject, "updateTime", LocalDateTime.now()); // You can also use (3.3.0 This method has bug) } }
matters needing attention :
- The filling principle is to give directly to
entity
Property setting value of !!! - Annotation specifies that the attribute must have a value in the corresponding case , If there is no value, the entry will be
null
MetaObjectHandler
The policies of the default methods provided are : If the property has a value, it does not override , If the filling value isnull
It doesn't fill in- Fields must declare
TableField
annotation , attributefill
Choose the corresponding strategy , The statement informedMybatis-Plus
Need to reserve InjectionSQL
Field - Fill the processor
MyMetaObjectHandler
stay Spring Boot You need to state@Component
or@Bean
Inject - According to the notes
FieldFill.xxx
andField name
as well asField type
To distinguish between... That must use a parent classstrictInsertFill
perhapsstrictUpdateFill
Method - You don't need to distinguish by anything that can use a parent class
fillStrategy
Method
4. Test run insert or update statements
- The filling principle is to give directly to
2.2.9 Optimism lock
During the interview, I am often asked about optimism / Pessimistic locking , This is very simple
Optimism lock : As the name suggests, very optimistic , He always thought there would be no problem , No matter what you do, don't lock it ! If something goes wrong , Update the value test again
Pessimistic locking : As the name suggests, very pessimistic , He always thinks there's a problem , Whatever you do, it's locked ! To operate again !
When a record is to be updated , I hope this record hasn't been updated by others
Optimistic lock implementation :
-
When taking out the record , Get current version
-
update , Take this with you version
-
On update ,set version = newVersion where version = oldVersion
-
If version incorrect , Failed to update
Optimism lock : First query , Get version number -- A update user set name = "wsk",version = version+1 where id = 1 and version = 1 -- B (B The thread finished first , here version=2, It can lead to A Thread modification failed !) update user set name = "wsk",version = version+1 where id = 1 and version = 1
-
Update the database , add to
version
Field-- auto-generated definition create table mp_user ( user_id bigint auto_increment comment ' user id' primary key, username varchar(32) not null comment ' user name ', password varchar(32) not null comment ' password ', version int null comment ' Optimism lock ', create_time datetime default CURRENT_TIMESTAMP not null comment ' Creation time ', update_time datetime default CURRENT_TIMESTAMP not null comment ' Update time ' );
-
Add corresponding fields and annotations to the entity class
@Version Integer version;
-
Certified components
// scanning mapper Folder @MapperScan("com.mymall.dao")// hand mybatis It's done , You can scan this configuration class @EnableTransactionManagement// Manage transactions automatically @Configuration// Configuration class public class MyBatisPlusConfig { // Register optimistic lock plugin @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return interceptor; } }
-
test
-
Test optimistic lock successfully
@Test void testOptimisticLocker1() { //1、 Query user information MpUser mpUser = mpUserMapper.selectById(1L); //2、 Modify user information mpUser.setUsername("qq"); //3、 Perform an update operation int update = mpUserMapper.updateById(mpUser); System.out.println(mpUser); }
-
Simulated multithreading test optimistic lock insert data failed
@Test void testOptimisticLocker2() { // Threads 1 MpUser mpUser = mpUserMapper.selectById(1L); mpUser.setUsername("aa"); mpUser.setPassword("666666"); // Simulate another thread performing queue jumping operation MpUser mpUser1 = mpUserMapper.selectById(1L); mpUser1.setUsername("bb"); mpUser1.setPassword("12344444"); mpUserMapper.updateById(mpUser1); // Spinlock to multiple attempts to commit ! mpUserMapper.updateById(mpUser);// If there is no optimistic lock, the value of the queue skipping thread will be overridden }
-
2.2.10 Inquire about
-
adopt id Querying a single user
@Test public void testSelectById(){ User user = userMapper.selectById(1L); System.out.println(user); }
-
adopt id Querying multiple users
@Test public void testSelectBatchIds(){ List<User> users = userMapper.selectBatchIds(Arrays.asList(1L, 2L, 3L)); users.forEach(System.out::println); }
-
Conditions of the query adopt map encapsulation
@Test public void testMap(){ HashMap<String, Object> map = new HashMap<>(); // Customize the query map.put("name","www"); map.put("age",18); List<User> users = userMapper.selectByMap(map); users.forEach(System.out::println); }
-
Paging query
Pagination is used as much as ten times in websites !
1、 The original limit Pagination
2、PageHelper Third party plug-ins
3、MybatisPlus In fact, it also has built-in paging plug-ins !
Use steps :
-
Configure interceptor components
package com.mymall.config; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.mybatis.spring.annotation.MapperScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.transaction.annotation.EnableTransactionManagement; @Configuration @MapperScan("com.mymall.dao") @EnableTransactionManagement public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // Add optimistic lock interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); // New paging plug-in , One is to ease and the other to follow mybatis The rules of , // Need to set up MybatisConfiguration#useDeprecatedExecutor = false // Avoid cache problems ( This property will be removed after the old plug-in is removed ) // Or not DbType.MYSQL, If it is empty, it will pass URL Determine the database type interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } @Bean public ConfigurationCustomizer configurationCustomizer() { return configuration -> configuration.setUseDeprecatedExecutor(false); } }
-
Test paging query
@Test public void testPage(){ // Parameter one current: The current page Parameter two size: Page size // After using the paging plug-in , All paging operations have become simple Page<User> page = new Page<>(2,5); // The second parameter is the advanced query , Temporarily set to null userMapper.selectPage(page,null); page.getRecords().forEach(System.out::println); System.out.println(" Total number of pages ==>"+page.getTotal()); }
-
2.2.11 Delete
-
Basic delete operations
@Test public void testDeleteById(){ userMapper.deleteById(1); } @Test public void testDeleteBatchIds(){ userMapper.deleteBatchIds(Arrays.asList(1,2)); } @Test public void testD(){ HashMap<String, Object> map = new HashMap<>(); map.put("age","18"); map.put("name","lol"); userMapper.deleteByMap(map); }
-
Logical deletion
Physical delete : Delete directly from the database
Logical deletion : Not deleted in the database , It's a variable that invalidates it ! deleted=0 ==> deleted=1
Administrators can view deleted records ! Prevent data loss , It's like a recycle bin !
Implementation steps :
-
Add... To the database
deleted
Fielddeleted int default 0 null comment ' Logical deletion :0 Show 1 Delete ',
-
Add the configuration
application.yml
mybatis-plus: global-config: db-config: logic-delete-field: deleted # The name of the entity field for global logical deletion (since 3.3.0, After configuration, you can ignore the non configuration steps 2) logic-delete-value: 1 # Logical deleted value ( The default is 1) logic-not-delete-value: 0 # Logical undeleted value ( The default is 0)
-
Add... To the entity class
deleted
Field and add@TableLogic
annotation ( It's configuredapplication.yml
No comments can be added after , howeverdeleted
Fields must be added )@TableLogic private Integer deleted;
-
Test whether the data still exists after deleting a piece of data , test result , It's just
deleted
Set up in order to 1@Test void testLogicDelete() { // Delete id by 2 The data of int i = mpUserMapper.deleteById(2); MpUser mpUser = mpUserMapper.selectById(2); System.out.println(mpUser); }
-
view the database , Found the record still ,deleted Turn into 1
Test the deleted user again , The query was found to be empty
2.2.12 Performance analysis plug-ins ( The new version has been removed )
In our usual development , There will be some slow Sql. test 、druid···
MybatisPlus Performance analysis plug-ins are also provided , If it exceeds this time, it stops running !
2.2.13 Conditional constructor wrapper
Warning :
Don't support and disapprove of in RPC Call the Wrapper transmitted
- wrapper It's heavy
- transmission wrapper It can be compared to your controller use map Receives the value ( Development fun , Maintenance of crematoria )
- Correct RPC Call pose is to write a DTO transmitted , The callee then uses DTO Perform the corresponding operation
-
Commonly used api Please go to the web page to view Conditional constructor | MyBatis-Plus (baomidou.com)
-
Examples of use
-
Query data that is not empty and larger than a certain value
@Test void testWrapper() { // The parameter is one wrapper , Conditional constructor , And just now map Comparative learning ! // Inquire about username Not empty ,password Not empty ,user_id Greater than 18 Users of // Notice the column The parameter must be the field name , Not a member variable in an entity class QueryWrapper<MpUser> wrapper = new QueryWrapper<>(); wrapper .isNotNull("username") .isNotNull("password") .ge("user_id",2); List<MpUser> userList = mpUserMapper.selectList(wrapper); userList.forEach(System.out::println); }
-
Query the data whose field value is the determined value , The returned result has one or more possibilities
@Test public void testWrapper2() { // Inquire about name=wsk Users of QueryWrapper<MpUser> wrapper = new QueryWrapper<>(); wrapper.eq("username","MPInsertTest1"); // Query a data selectOne, If more than one is found, an error will be reported //Expected one result (or null) to be returned by selectOne(), but found: * // If there are multiple results, use list or map MpUser mpUser = mpUserMapper.selectOne(wrapper);// Query a data , If there are multiple results, use list or map System.out.println(mpUser); List<MpUser> mpUsers = mpUserMapper.selectList(wrapper); }
-
Query the data whose field value range is in a certain range
@Test public void testWrapper3() { // Inquire about age stay 10-20 Number of users between QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.between("age", 10, 20);// Section Integer count = userMapper.selectCount(wrapper);// Number of output queries selectCount System.out.println(count); }
-
Fuzzy query ,
notLike,likeRight,likeLeft
@Test public void testWrapper4() { // Fuzzy query QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper .notLike("name","s") .likeRight("email","t");//qq% left and right ? List<Map<String, Object>> maps = userMapper.selectMaps(wrapper); maps.forEach(System.out::println); }
-
Subquery
@Test public void testWrapper5() { // SELECT id,name,age,email,version,deleted,create_time,update_time //FROM user //WHERE deleted=0 AND id IN //(select id from user where id<5) QueryWrapper<User> wrapper = new QueryWrapper<>(); //id Find out in the subquery wrapper.inSql("id","select id from user where id<5"); List<Object> objects = userMapper.selectObjs(wrapper); objects.forEach(System.out::println); }
-
adopt id Sort
@Test public void testWrapper6() { QueryWrapper<User> wrapper = new QueryWrapper<>(); // adopt id Sort in descending order wrapper.orderByDesc("id"); List<User> userList = userMapper.selectList(wrapper); userList.forEach(System.out::println); }
-
2.2.14 Code generator ,MP
Reverse engineering
-
Add dependency
MyBatis-Plus from
3.0.3
After that, the default dependency between code generator and template engine is removed , You need to manually add generator and template engine dependenciesSo let's try to use 3.5.1 edition ( The following tutorials apply only to 3.5.1 Above version , Incompatibility with historical versions )
// Be careful !! The current package does not pass dependencies mp package , Need to introduce <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>Latest Version</version> </dependency>
add to template engine rely on ,MyBatis-Plus Support Velocity( Default )、Freemarker、Beetl, Users can choose their own familiar template engine , If they don't meet your requirements , You can use a custom template engine . Here, according to the official documents
freemarker
Velocity( Default ): <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-core</artifactId> <version>latest-velocity-version</version> </dependency> Freemarker: <!-- https://mvnrepository.com/artifact/org.freemarker/freemarker --> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.31</version> </dependency> Beetl: <dependency> <groupId>com.ibeetl</groupId> <artifactId>beetl</artifactId> <version>latest-beetl-version</version> </dependency>
-
stay
mpper
Create a code generator configuration class in a subprojectpackage com.mymall; import com.baomidou.mybatisplus.generator.FastAutoGenerator; import com.baomidou.mybatisplus.generator.config.OutputFile; import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine; import java.util.Collections; /** * @author 18230 * @version 1.0.0 * @ClassName CodeGenerator.java * @Description * @createTime 2021 year 09 month 30 Japan 22:37:00 */ public class CodeGenerator { public static void main(String[] args) { /* * url jdbc route jdbc:mysql://127.0.0.1:3306/mybatis-plus * username Database account root * password Database password 123456 */ FastAutoGenerator.create("jdbc:mysql://localhost:3306/mymall?serverTimezone=GMT%2b8&useSSL=false&allowPublicKeyRetrieval=true", "root", "123456") .globalConfig(builder -> { builder.author("QC") // Set the author .enableSwagger() // Turn on swagger Pattern .fileOverride() // Overwrite generated file // Prohibit opening Directory .disableOpenDir() // Specify output directory , The absolute path is used here .outputDir("F:\\JavaProjcet\\MyMallPractice2\\mapper\\src\\main\\java"); // If you use /src/main/java The file will be created in the root directory , That is, it didn't succeed // Source code :this.outputDir = System.getProperty("os.name").toLowerCase().contains("windows") ? "D://" : "/tmp"; //System.getProperty("os.name") Get the operating system name , If the name contains windows Just "D://" Otherwise, "/tmp" // Judgment is windows System , Otherwise, it would be linux System , So you can only use absolute addresses //.outputDir("classpath:/src/main/java"); }) .packageConfig(builder -> { builder.parent("com.mymall") // Set the parent package name //.moduleName("mapper") // Set the parent package module name , That is, add a package to the parent package name // But setting the relative path here succeeded once , But the root directory is generated later , So use the absolute path //.pathInfo(Collections.singletonMap(OutputFile.mapperXml, "/src/main/resources/mapper")); // Set up mapperXml Path is generated .pathInfo(Collections.singletonMap(OutputFile.mapperXml, "F:\\JavaProjcet\\MyMallPractice2\\mapper\\src\\main\\resources\\mapper")); // Set up mapperXml Path is generated }) .strategyConfig(builder -> { builder.addInclude("users") // Set the table name to be generated .addInclude("category") .addInclude("index_img") .addInclude("mp_user") .addInclude("product") .addInclude("product_sku") .addInclude("product_img") .addInclude("orders") .addInclude("product_comments") .addInclude("product_params") //.setEntityLombokModel(true) // Turn on lombook Support , The new version is gone .addTablePrefix("mp_"); // Set filter table prefix , That is, remove the prefix , Only the content facing back is retained as the entity name }) .templateEngine(new FreemarkerTemplateEngine()) // Use Freemarker Engine templates , The default is Velocity Engine templates .execute(); } }
Generate successfully
3 Solutions to common problems
3.1 database url Medium SSL problem
terms of settlement : take gerneratorConfig.xml
Medium url Change to useSSL=false
connectionURL="jdbc:mysql://localhost:3306/mymall?useSSL=false&serverTimezone=GMT%2b8"&useUnicode=true&characterEncoding=utf-8
3.2 Plug in not found
solve : adjustment mybatis-generator-maven-plugin
edition
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.5</version>
3.3 All other tables in the database are generated
solve : stay gerneratorConfig.xml
Just add the table name that needs to be generated
<table tableName="category" />
3.4 users Table generates other tables

terms of settlement :
-
Change my table name
-
Try not to let MySql Keeping tables affects my Reverse Engineering
Make sure that only your own specified database Medium User surface , In the first
Medium connectionURL Specify the instance name of the database in , And then in Add related configuration information to , namely , You can ensure that only what you need User class .
The configuration is as follows :<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/xxx" userId="xxx" password="xxx"> <property name="nullCatalogMeansCurrent" value="true"/> </jdbcConnection>