1. Why learn MyBatisPlus?
- It can save us a lot of time
- All crud code can be generated automatically
- JPA, TK mapper and MyBatisPuls can automatically generate CRUD
2. Introduction to mybatis
Official website: https://baomidou.com/guide/
MyBatis-Plus (opens new window) (MP) is a MyBatis (opens new window) On the basis of MyBatis, the enhancement tool is only enhanced without change, and is born to simplify development and improve efficiency.
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
3.MybatisPlus quick start
1. Add data
DROP TABLE IF EXISTS user; CREATE TABLE user ( id BIGINT(20) NOT NULL COMMENT 'Primary key ID', name VARCHAR(30) NULL DEFAULT NULL COMMENT 'full name', age INT(11) NULL DEFAULT NULL COMMENT 'Age', email VARCHAR(50) NULL DEFAULT NULL COMMENT 'mailbox', PRIMARY KEY (id) ); -- implement SQL script DELETE FROM user; INSERT INTO user (id, name, age, email) VALUES (1, 'Jone', 18, 'test1@baomidou.com'), (2, 'Jack', 20, 'test2@baomidou.com'), (3, 'Tom', 28, 'test3@baomidou.com'), (4, 'Sandy', 21, 'test4@baomidou.com'), (5, 'Billie', 24, 'test5@baomidou.com');
2. Initialization project
have access to Spring lnitializer Quickly initialize a Spring Boot engineering
3. Add dependency
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--add to mybatis-plus--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.0.5</version> </dependency> <!--add to mysql rely on--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies>
4. Write entity class
package com.xjggb.entity; import lombok.Data; @Data public class User { private Long id; private String name; private Integer age; private String email; }
5. Write Mapper interface
package com.xjggb.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.xjggb.entity.User; /* * If you don't want to add package scanning in the startup class, you can add this annotation @ Repository / / to represent the persistence layer * CRUD function has been implemented * */ public interface UserMapper extends BaseMapper<User> { }
6. Write the service business layer
import com.xjggb.mapper.UserMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class UserServlce { @Autowired private UserMapper userMapper; /* * Query all data * */ public List<User> selectList(){ return userMapper.selectList(null); } }
7. Write controller layer
package com.xjggb.controller; import com.xjggb.entity.User; import com.xjggb.service.UserServlce; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController public class UserCotroller { @Autowired private UserServlce userServlce; /* * Query all data * */ @GetMapping("/hello") public List<User> selectList(){ return userServlce.selectList() ; } }
Summary:
- The CRUD function of the User table is realized through the above simple steps,
- You don't even need to write an XML file
- As can be seen from the above steps, integrating mybatis plus is very simple. You only need to introduce the configuration path scanning of the dependent configuration mapper and inherit basemapper < >
- MybatisPlus is more powerful than that. If you want to understand its powerful functions in detail, look down slowly
4. Configure log
#Configuration log mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
Summary:
- After configuring the log, you will fall in love with mybatis plus
5.CRUD extension
1. Insert data
@Test public void show01(){ User user = new User(); user.setName("Xingjian good bully"); user.setAge(18); user.setEmail("132456@qq.com"); // insert data mapper.insert(user); }
Note: the default value of database insert id is snowflake id
2. Generate policy column from primary key
-
Automatic growth
advantage: 1)Simple, convenient code, acceptable performance. 2)number ID Natural sorting is very helpful for paging or sorting results. Disadvantages: 1)The syntax and implementation of different databases are different. It needs to be handled during database migration or multi database version support. 2)In the case of single database, read-write separation or one master and multiple slaves, only one master database can be generated. Risk of single point of failure. 3)When the performance fails to meet the requirements, it is difficult to expand. (not applicable to massive and high concurrency) 4)If you encounter multiple systems that need to be merged or involve data migration, it will be quite painful. 5)There will be trouble when dividing tables and libraries. 6)Not necessarily continuous, similar MySQL,When generating new ID If the transaction is rolled back, subsequent transactions will not use this ID Yes. This is a compromise between performance and continuity. In order to ensure continuity, it must be generated after the transaction ends ID,Then there will be performance problems. 7)In the distributed database, if the self increasing primary key is adopted, it may bring tail hot spots. Distributed databases are often used range When a large number of new records are added, IO It will concentrate on one partition, resulting in hot data.
-
UUID
advantage: 1)Simple and convenient code. 2)generate ID Very good performance, basically no performance problems. 3)It is the only one in the world. It can deal with data migration, system data consolidation, or database change calmly Disadvantages: 1)Without sorting, the trend cannot be guaranteed to increase. 2)UUID String storage is often used, and the efficiency of query is relatively low. 3)The storage space is relatively large. If it is a massive database, the storage capacity needs to be considered. 4)Large amount of transmitted data 5)Unreadable.
-
Redis generated id
advantage: 1)It does not depend on the database, is flexible and convenient, and its performance is better than the database. 2)number ID Natural sorting is very helpful for paging or sorting results. Disadvantages: 1)If not in the system Redis,New components need to be introduced to increase the complexity of the system. 2)The workload of coding and configuration is relatively large.
-
Twitter's snowflake algorithm (distributed id: snowflake id)
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. For the specific implementation code, see https://github.com/twitter/snowflake . The TPS supported by snowflake algorithm can reach about 4.19 million (2 ^ 22 * 1000).
advantage: 1)It does not depend on the database, is flexible and convenient, and its performance is better than the database. 2)ID It is incremented on a single machine according to time. Disadvantages: 1)It is incremental on a single machine, but due to the distributed environment, the clock on each machine cannot be fully synchronized. In the algorithm, the problem of time callback should be solved Question.
-
Generate unique ID with zookeeper
zookeeper Mainly through its znode The data version is used to generate the serial number, which can generate 32-bit and 64 bit data version numbers. The client can use this version number as the unique serial number. Rarely used zookeeper To generate unique ID. Mainly due to the need to rely on zookeeper,And it is a multi-step call API,If the competition is large, it is necessary to consider using distributed locks. Therefore, the performance is not ideal in the distributed environment with high concurrency.
3. Self increment of primary key
1. Modify entity class
@Data public class User { // The primary key in the corresponding database (UUID, auto increment id, redis zookeeper id) @TableId(type = IdType.AUTO) //Configure primary key auto increment private Long id; private String name; private Integer age; private String email; }
2. Modify database self increment
3. Test
@Test public void show01(){ User user = new User(); user.setName("Xingjian good bully"); user.setAge(18); user.setEmail("132456@qq.com"); // insert data mapper.insert(user); }
4. Results
5.IdType source code analysis
public enum IdType { AUTO(0),//Self increment of database ID NONE(1),//The type is not set with primary key INPUT(2),//User input ID //This type can be filled by registering the auto fill plug-in //The following three types are automatically filled only when the inserted object ID is empty. ID_WORKER(3),//The globally unique ID (idWorker) is also the default id type UUID(4),//Globally unique ID (UUID) ID_WORKER_STR(5);//String globally unique ID (string representation of idworker)
Summary:
- Understand the advantages and disadvantages of primary key policy columns
- Master the integration of primary key by mybatis plus
4. Update data
1. Test code
/* * Test update * */ @Test public void show02(){ User user = new User(); user.setId(1403046980736827394L); user.setName("I'm a good bully"); // Note that the updateById parameter is an object mapper.updateById(user); }
Summary:
- The update of sql is dynamic, and it will be spliced according to the parameters
5. Auto fill
- Implementation of meta object processor interface: com baomidou. mybatisplus. core. handlers. MetaObjectHandler
- The annotation filling field @ TableField(.. fill = FieldFill.INSERT) generator policy can also be configured!
1. Add fields to the database
2. Add entity class
// When adding fields for automatic filling, be sure to use the DATE under util package @TableField(fill = FieldFill.INSERT) private Date creatTime; @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime; }
3. Write a class to implement com baomidou. mybatisplus. core. handlers. Metaobjecthandler interface
@Slf4j @Component //Leave it to the Spring container for management public class MyMetaObjecHandler implements MetaObjectHandler { //Insert fill policy column @Override public void insertFill(MetaObject metaObject) { log.info("start insert Auto fill started"); this.setFieldValByName("creatTime",new Date(),metaObject); this.setFieldValByName("updateTime",new Date(),metaObject); } //Update fill policy column @Override public void updateFill(MetaObject metaObject) { log.info("start update Auto fill started "); this.setFieldValByName("updateTime",new Date(),metaObject); } }
4. Test
/* * insert data * */ @Test public void show01(){ User user = new User(); user.setName("Xingjian good bully"); user.setAge(18); user.setEmail("132456@qq.com"); // insert data mapper.insert(user); } /* * Test update * */ @Test public void show02(){ User user = new User(); user.setId(1403046980736827394L); user.setName("I'm a good bully"); user.setAge(23); user.setEmail("test5@baomidou.com"); // Note that the updateById parameter is an object mapper.updateById(user); }
5. Results
- Source code analysis of FieldFill
public enum FieldFill { /** * Do not process by default */ DEFAULT, /** * Insert fill field */ INSERT, /** * Update fill field */ UPDATE, /** * Insert and update populated fields */ INSERT_UPDATE }
matters needing attention:
1. The filling principle is to directly set the value for the attribute of entity!!!
2. Annotation specifies that the attribute must have a value in the corresponding case. If there is no value, the receipt will be null
3. The policies of the default methods provided by metaobjecthandler are: if the attribute has a value, it will not be overwritten; if the filling value is null, it will not be filled
4. The field must declare a TableField annotation, and the attribute fill selects the corresponding policy. This declaration tells mybatis plus that SQL fields need to be reserved and injected
5. The filling processor MyMetaObjectHandler needs to declare @ Component or @ Bean injection in Spring Boot
6. If you want to use the annotation fieldfill XXX is distinguished by field name and field type. The strictInsertFill or strictUpdateFill methods of the parent class must be used
7. There is no need to distinguish the fillStrategy method that can use the parent class according to any
Summary:
-
Understand the automatic filling of time
-
Add annotation @ tablefield in attribute (fill = fieldfill. Insert)
-
Implement interface com baomidou. mybatisplus. core. handlers. MetaObjectHandler
-
Rewrite two methods: insertFill(MetaObject metaObject) updateFill(MetaObject metaObject)
6. Logical deletion
1. Add field
2. Add field to entity class
//Logical deletion @TableLogic private Integer deleted;
3. Add profile
mybatis-plus: global-config: db-config: logic-not-delete-value: 0 #Logic and delete (1 by default) logic-delete-value: 1 # Logical delete (0 by default)
4. Register logical deletion
@Configuration public class MyLogicDeleteHandler { // Register deletion logic @Bean public ISqlInjector sqlInjector(){ return new LogicSqlInjector(); } }
5. Test
/* * Logical deletion * */ @Test public void show04(){ int i = mapper.deleteById(1403046980736827394L); System.out.println("i = " + i); } /* * Query by id * */ @Test public void show05(){ User user = mapper.selectById(1403046980736827394L); System.out.println(user); }
6. Results
Summary:
Logical deletion is a false deletion. Change the deleted field status to the deleted status, and the database still has this data
7. Query operation
/* * Query by id * */ @Test public void show05(){ User user = mapper.selectById(1403046980736827394L); System.out.println(user); } /* * Test batch query * */ @Test public void show06(){ List<Long> longs = Arrays.asList(1403046980736827395L, 1403046980736827396L, 1403046980736827393L); List<User> users = mapper.selectBatchIds(longs); users.forEach(System.out::println); } /* * Query by query criteria * */ @Test public void show(){ HashMap<String, Object> map = new HashMap<>(); // Add condition map.put("name","Xiaoguo theory java"); map.put("age","18"); List<User> users = mapper.selectByMap(map); users.forEach(o-> System.out.println("o = " + o)); }
8 paging query
1. Register paging plug-in
// Register paging plug-in @Bean public PaginationInterceptor paginationInterceptor() { PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); return paginationInterceptor; }
2. Test
@Test public void show07(){ Page<User> userPage = new Page<>(2,5); mapper.selectPage(userPage,null); List<User> records = userPage.getRecords(); records.forEach(o-> System.out.println("o = " + o)); }
3. Results
9. Optimistic lock
When you want to update a record, you want it not to be updated by others
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
1. Register lock assembly
// Register optimistic lock plug-in @Bean public OptimisticLockerInterceptor optimisticLockerInterceptor() { return new OptimisticLockerInterceptor(); }
2. Add attribute to entity class
@Version // version annotation of optimistic lock private Integer version;
3. Test
// Failed to test optimistic lock! Multithreading @Test public void testVersionFall(){ // Thread 1 User user1 = mapper.selectById(1L); user1.setName("fan111"); user1.setAge(14); // Thread 2 User user2 = mapper.selectById(1L); user2.setName("fan222"); user2.setAge(24); mapper.updateById(user2); //Spin lock to multiple attempts to submit! mapper.updateById(user1); //If there is no optimistic lock, it will override the value of the queue jumping thread }
6. Performance analysis plug-in
We usually encounter some slow sql in development
Mybatis plus provides performance plug-ins, which will stop running after this time
1. Injection plug-in
//Performance analysis plug-in @Bean @Profile({"dev","test"}) //Set dev and test environment on public PerformanceInterceptor performanceInterceptor(){ PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor(); performanceInterceptor.setMaxTime(1); //The unit is milliseconds (ms) performanceInterceptor.setFormat(true); return performanceInterceptor; }
2. Prepare configuration file
#Set up development environment profiles: active: dev
3. Test
@Test public void show06(){ List<Long> longs = Arrays.asList(1403046980736827395L, 1403046980736827396L, 1403046980736827393L); List<User> users = mapper.selectBatchIds(longs); users.forEach(System.out::println); }
4. Results
5.sql execution is too long. Please perform optimization
//get data public List<T> getRecords() { return this.records; } //Total records after public long getTotal() { return this.total; } public long getSize() { return this.size; } public long getCurrent() { return this.current; }
7. Conditional constructor
@Test public void show9(){ // Query users whose mailbox is not empty query users whose age is greater than 18 QueryWrapper<User> wrapper = new QueryWrapper<>(); // Add condition QueryWrapper<User> ge = wrapper.isNotNull("name").isNotNull("email").ge("age", 18); mapper.selectList(ge).forEach(o-> System.out.println("o = " + o)); } /* * Query by name * */ @Test public void show10(){ QueryWrapper<User> wrapper = new QueryWrapper<>(); QueryWrapper<User> ge = wrapper.ge("name", "Xiaoguo theory java"); List<User> users = mapper.selectList(ge); System.out.println("users = " + users); } /* * The inquiry age is between 16 and 30 * */ @Test public void show11(){ QueryWrapper<User> userQueryWrapper = new QueryWrapper<>(); // Add condition userQueryWrapper.between("age",16,30); Integer integer = mapper.selectCount(userQueryWrapper); System.out.println("=============="+integer); } /* * Fuzzy query * */ @Test public void show12(){ QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.likeRight("email","test"); List<User> users = mapper.selectList(wrapper); users.forEach(p-> System.out.println("p = " + p)); }
8. Code generator
package com.xjggb; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.generator.AutoGenerator; import com.baomidou.mybatisplus.generator.config.DataSourceConfig; import com.baomidou.mybatisplus.generator.config.GlobalConfig; import com.baomidou.mybatisplus.generator.config.PackageConfig; import com.baomidou.mybatisplus.generator.config.StrategyConfig; import com.baomidou.mybatisplus.generator.config.po.TableFill; import com.baomidou.mybatisplus.generator.config.rules.DateType; import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; import java.util.ArrayList; public class Test { public static void main(String[] args) { // You need to build an automatic code generator object AutoGenerator mpg = new AutoGenerator(); // Configuration policy // 1. Global configuration GlobalConfig gc = new GlobalConfig(); // String projectPath = System.getProperty("user.dir"); String projectPath = "D:\\mybatis-plus\\hello-mybatis-plus-02"; gc.setOutputDir(projectPath+"/src/main/java"); gc.setAuthor("Xiaoguo theory"); gc.setOpen(false); gc.setFileOverride(false); // Overwrite gc.setServiceName("%sService"); // I prefix to Service gc.setIdType(IdType.ID_WORKER); gc.setDateType(DateType.ONLY_DATE); gc.setSwagger2(true); mpg.setGlobalConfig(gc); //2. Set data source DataSourceConfig dsc = new DataSourceConfig(); // dsc.setUrl("jdbc:mysql://localhost:3306/kuang_community? useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8"); dsc.setUrl("jdbc:mysql://192.168.93.222:3306/user_day?useSSL=false&useUnicode=true&characterEncoding=utf-8"); dsc.setDriverName("com.mysql.jdbc.Driver"); dsc.setUsername("root"); dsc.setPassword("root"); dsc.setDbType(DbType.MYSQL); mpg.setDataSource(dsc); //3. Package configuration PackageConfig pc = new PackageConfig(); //Just change the entity class name, package name and database configuration pc.setModuleName("blog"); pc.setParent("com.xjggb"); pc.setEntity("entity"); pc.setMapper("mapper"); pc.setService("service"); pc.setController("controller"); mpg.setPackageInfo(pc); //4. Policy configuration StrategyConfig strategy = new StrategyConfig(); // Set the table name to map. You can add multiple tables strategy.setInclude("user"); strategy.setNaming(NamingStrategy.underline_to_camel); strategy.setColumnNaming(NamingStrategy.underline_to_camel); // Automatic Lombok strategy.setEntityLombokModel(true); strategy.setLogicDeleteFieldName("deleted"); // Auto fill configuration TableFill gmtCreate = new TableFill("gmt_create", FieldFill.INSERT); TableFill gmtModified = new TableFill("gmt_modified", FieldFill.INSERT_UPDATE); ArrayList<TableFill> tableFills = new ArrayList<>(); tableFills.add(gmtCreate); tableFills.add(gmtModified); strategy.setTableFillList(tableFills); /* // Optimistic lock strategy.setVersionFieldName("version"); strategy.setRestControllerStyle(true); strategy.setControllerMappingHyphenStyle(true);*/ // localhost:8080/hello_id_2 mpg.setStrategy(strategy); mpg.execute(); //implement } }
9. Mybatis plus XML configuration
mybatis-plus: mapper-locations: mapper/*.xml global-config: db-config: # Primary key policy id-type: auto # table prefix table-prefix: t # Whether to use underline interval for table name. Default: Yes table-underline: true # Add mybatis profile path config-location: mybatis-config.xml # Configure entity class package address type-aliases-package: org.ywb.demo.pojo # Hump turn configuration: map-underscore-to-camel-case: true
Summary:
- Simplify development with mybatis plus
- Greatly improve the development speed