summary
Official website: MyBatis-Plus (baomidou.com)
characteristic
- No invasion: it is only enhanced without change, and its introduction will not affect the existing project, which is as smooth as silk
- Low loss: the basic CURD will be injected automatically upon startup, with basically no loss of performance and direct object-oriented operation
- Powerful crud operation: built-in general Mapper and general Service. Most CRUD operations of a single table can be realized only through a small number of configurations. There is also a powerful condition constructor to meet various use needs
- Support Lambda form call: through Lambda expression, it is convenient to write various query conditions without worrying about wrong fields
- Support automatic generation of primary key: support up to 4 primary key strategies (including distributed unique ID generator - Sequence), which can be configured freely to perfectly solve the problem of primary key
- Support ActiveRecord mode: support ActiveRecord formal calls. Entity classes only need to inherit Model classes to perform powerful CRUD operations
- Support custom global general operations: support global general method injection (Write once, use anywhere)
- Built in code generator: code or Maven plug-in can be used to quickly generate Mapper, Model, Service and Controller layer code, support template engine, and have more custom configurations for you to use
- Built in paging plug-in: Based on MyBatis physical paging, developers do not need to care about specific operations. After configuring the plug-in, writing paging is equivalent to ordinary List query
- The paging plug-in supports multiple databases: MySQL, MariaDB, Oracle, DB2, H2, HSQL, SQLite, Postgre, SQLServer and other databases
- Built in performance analysis plug-in: it can output SQL statements and their execution time. It is recommended to enable this function during development and testing to quickly find out slow queries
- Built in global interception plug-in: it provides intelligent analysis and blocking of full table delete and update operations, and can also customize interception rules to prevent misoperation
Quick start
Create a new springboot web project
Import dependency: try not to import mybatis and mybatis plus at the same time
<!--Database driven--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!--mybatis-plus---> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.1</version> </dependency>
Configure connection database:
# DataSource Config spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver #schema: classpath:db/schema-h2.sql #data: classpath:db/data-h2.sql url: jdbc:mysql://47.113.229.158:3306/mybatis_plus?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai username: yang password: 123456
Write entity class:
@Data @AllArgsConstructor @NoArgsConstructor public class User { private Long id; private String name; private Integer age; private String email; }
*Write mapper interface~~~~*
@Repository // Represents the persistence layer //Inherit BaseMapper on the corresponding mapper interface and pass in generics public interface UserMapper extends BaseMapper<User> { }
Start mapper scan @ MapperScan
@MapperScan("com.yang.mapper")//Scan mapper folder @SpringBootApplication public class SpringbootMybatisplusApplication { public static void main(String[] args) { SpringApplication.run(SpringbootMybatisplusApplication.class, args); } }
Test:
@Autowired private UserMapper userMapper; @Test void contextLoads() { List<User> userList = userMapper.selectList(null); for (User user : userList) { System.out.println(user); } }
Configuration log
Insert test
User user = new User(); user.setAge(3); user.setEmail("134679262@qq.com"); user.setName("123"); int insert = userMapper.insert(user); System.out.println(insert);
Insert succeeded, found automatically generated id!! (the table name is required to be consistent with the entity class name)
Primary key generation strategy
Snowflake generation algorithm: (default)
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 the number of milliseconds, 10bit as the machine ID (five bits are the data center and five bit machine ID), 12bit as the serial number within milliseconds (meaning that each node can generate 4096 IDS per millisecond), and finally there is a symbol bit, which is always 0. Can guarantee almost the only one in the world! I
Other policies: @ TableId
@Data @AllArgsConstructor @NoArgsConstructor public class User { @TableId(type = IdType.AUTO) private Long id; private String name; private Integer age; private String email; }
- AUTO primary key AUTO increment requires the database to set AUTO increment
- NONE no primary key set
- INPUT manual INPUT
Update test
@Test void testUpdate(){ User user = new User(); user.setId(3L); user.setAge(5); int update = userMapper.updateById(user); System.out.println(update); }
sql is dynamically configured according to parameters~~
Auto fill
Database level (not recommended)
)
And synchronize in the entity class
private Date creat_time; private Date update_time;
Code level
Remove default
Set @ TableField on the property of the entity class
@TableField(fill = FieldFill.INSERT) //Fill on insert private Date creat_time; @TableField(fill = FieldFill.UPDATE) //Fill on update private Date update_time;
Custom population policy
@Component @Slf4j public class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { log.info("start insert fill...."); this.setFieldValByName("creat_time",new Date(),metaObject); this.setFieldValByName("update_time",new Date(),metaObject); } @Override public void updateFill(MetaObject metaObject) { log.info("start update fill...."); this.setFieldValByName("update_time",new Date(),metaObject); } }
Optimistic lock
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 there is a problem, update the test value 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! Operate again|
Optimistic lock implementation method:
- When the record is fetched, the current version is obtained
- Carry version when updating
- When performing an update operation, version= new_verison where version = old_version
- When the version s do not match, the update fails
test
Add version field
Annotation for configuring version attribute @ Version MP
@Version private Integer version;
Register components:
@Configuration //@EnableTransactionManagement ??? Not on the official website @MapperScan("com.yang.mapper") public class MybatisPlusConfig { /** * new edition */ @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return mybatisPlusInterceptor; } }
Test:
- success
@Test void test1(){ User user = userMapper.selectById(1487730131458940930L); user.setAge(5); user.setName("Ah, ah, ah"); int update = userMapper.updateById(user); }
Version will be taken out first and then updated after version+1
- fail
@Test void test2(){ User user = userMapper.selectById(1487730131458940930L); user.setAge(5); user.setName("Ha ha ha ha"); //Simulate multithreading being cut in line User user2 = userMapper.selectById(1487730131458940930L); user2.setAge(5); user2.setName("1111"); int update2 = userMapper.updateById(user2); int update = userMapper.updateById(user); }
When there is no optimistic lock, this data will be overwritten by "hahaha", but under the action of optimistic lock, the subsequent update statement fails
be careful:
- The only supported data types are: int,Integer,long,Long,Date,Timestamp,LocalDateTime
- newVersion = oldVersion + 1 under integer type
- newVersion will be written back to entity
- Only updateById(id) and update(entity, wrapper) methods are supported
- Under the update(entity, wrapper) method, the wrapper cannot be reused!!!
query
Multi Id query
@Test void testquery(){ List<User> userList = userMapper.selectBatchIds(Arrays.asList(1, 2, 3)); for (User user : userList) { System.out.println(user); } }
map conditional query cannot realize fuzzy query
@Test void testquery1(){ HashMap<String, Object> map = new HashMap<>(); map.put("name","1111"); List<User> userList = userMapper.selectByMap(map); for (User user : userList) { System.out.println(user); } }
Paging query
// the latest version @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2)); return interceptor; }
use:
@Test void testpage(){ Page<User> page = new Page<>(1,3); //Page number, page size userMapper.selectPage(page, null); page.getRecords().forEach(System.out::println); }
Logical deletion
Physical delete: delete from database
Logical deletion: in the database, a variable is used to invalidate it to prevent data loss
@TableLogic //Logical deletion private Integer deleted;
mybatis-plus: global-config: db-config: logic-delete-field: flag # Global logically deleted entity field name (since 3.3.0, can be ignored after configuration, step 2 is not configured) logic-delete-value: 1 # Logical deleted value (default = 1) logic-not-delete-value: 0 # Logical undeleted value (default is 0)
The actual operation is to update. Later, the query criteria of deleted=0 will be spliced automatically during query, and only the columns that have not been deleted logically will be queried
Performance analysis plug-in?????
Do not use in the production environment
This function relies on p6spy components to output and print SQL perfectly and the execution time is long
<dependency> <groupId>p6spy</groupId> <artifactId>p6spy</artifactId> <version>Latest version</version> </dependency>
- application.yml modification:
spring: datasource: driver-class-name: com.p6spy.engine.spy.P6SpyDriver url: jdbc:p6spy:mysql://47.113.229.158:3306/mybatis_plus?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
-
spy.properties configuration:
driverlist=com.mysql.cj.jdbc.Driver logMessageFormat=com.p6spy.engine.spy.appender.MultiLineFormat #logMessageFormat=com.p6spy.engine.spy.appender.SingleLineFormat databaseDialectDateFormat=yyyy-MM-dd HH:mm:ss appender=com.p6spy.engine.spy.appender.StdoutLogger
#3.2.1 use of the above modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory #3.2.1 the following are used or not configured: #modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory # Custom log printing logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger #Log output to console appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger # Use the logging system to record sql #appender=com.p6spy.engine.spy.appender.Slf4JLogger # Set p6spy driver agent deregisterdrivers=true # Remove JDBC URL prefix useprefix=true # Log exceptions for configuration records. The result sets that can be removed include error,info,batch,debug,statement,commit,rollback,result,resultset excludecategories=info,debug,result,commit,resultset # Date format dateformat=yyyy-MM-dd HH:mm:ss # The actual drive can be multiple #driverlist=org.h2.Driver # Enable slow SQL logging outagedetection=true # Slow SQL record standard 2 seconds outagedetectioninterval=2
Conditional constructor
- isNotNull ge
@Test void test1(){ QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper .isNotNull("name") .isNotNull("email") .ge("age",18); // name and email are not empty and age > = 18 userMapper.selectList(wrapper).forEach(System.out::println); }
- eq
@Test void test2(){ QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.eq("name","1111"); User user = userMapper.selectOne(wrapper); System.out.println(user); }
- between
@Test void test3(){ QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.between("age",18,23); Long aLong = userMapper.selectCount(wrapper); System.out.println(aLong); }
- notLike likeLeft
@Test void test4(){ QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.notLike("name","J") .likeLeft("name","3"); // %3 userMapper.selectMaps(wrapper).forEach(System.out::println); }