1. MyBatisPlus overview
Why learn it? MyBatisPlus can save us a lot of working time. All CRUD codes can be completed automatically!
JPA , tk-mapper,MyBatisPlus
Lazy!
- What is it? MyBatis is meant to simplify JDBC operations!
Official website: MyBatis-Plus (baomidou.com) MyBatis Plus, simplify MyBatis!
2. Get started quickly
Direction of using third-party components:
1. Import corresponding dependencies 2. Study how to configure dependencies 3. How to write code 4. Improve the ability of extension technology! b
step
1. Create database mybatis_plus
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) ); 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'); -- In real development, version(Le Guansuo) deleted(Logical deletion) gmt_create,gmt_modifie
3. Write project, initialize project! Initialize with SpringBoot!
4. Import dependency
<!-- Database driven --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!-- mybatis-plus --> <!-- mybatis-plus Developed by ourselves, not official! --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.0.5</version> </dependency>
Note: we can save a lot of code by using mybatis plus. Try not to import mybatis and mybatis plus at the same time! Version difference!
5. Connect to database! This step is the same as mybatis!
# mysql 5 drives different com mysql. jdbc. Driver # mysql 8 drives different com mysql. cj. jdbc. Driver. The configuration of time zone needs to be added serverTimezone=GMT%2B8 spring.datasource.username=root spring.datasource.password=123456 spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus? useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
6. After using mybatis plus
(traditional POJO Dao (connect to mybatis, configure mapper.xml file) - service controller)
pojo/User
@Data @AllArgsConstructor @NoArgsConstructor public class User { private Long id; private String name; private Integer age; private String email; }
mapper interface
package com.example.mybatisplus.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.example.mybatisplus.pojo.User; import org.springframework.stereotype.Repository; // Inherit the basic class BaseMapper on the corresponding Mapper @Repository // Represents the persistence layer public interface UserMapper extends BaseMapper<User> { // All CRUD operations have been written // You don't need a lot of files like the previous configuration! }
Note that we need to scan all interfaces under our mapper package on the main startup class
@MapperScan("com.example.mybatisplus.mapper")
Test in test class
package com.example.mybatisplus; //... import java.util.List; @SpringBootTest class MybatisPlusApplicationTests { // It inherits BaseMapper, and all methods use their own parent class // We can also write our own extension methods! @Autowired private UserMapper userMapper; @Test void contextLoads() { // The parameter is a Wrapper and a condition constructor. We don't need null here // Query all users List<User> users = userMapper.selectList(null); users.forEach(System.out::println); } }
- result
User(id=1, name=Jone, age=18, email=test1@baomidou.com) User(id=2, name=Jack, age=20, email=test2@baomidou.com) User(id=3, name=Tom, age=28, email=test3@baomidou.com) User(id=4, name=Sandy, age=21, email=test4@baomidou.com) User(id=5, name=Billie, age=24, email=test5@baomidou.com)
- Thinking?
1. Who wrote SQL for us?
Mybatis plus is all written
2. Where did the method come from?
Mybatis plus is all written
-
Configuration log
All our sql is invisible now. We want to know how it is executed, so we must look at the log!
# Configuration log mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImp
After configuring the log, you need to pay attention to the automatically generated SQL in later learning, and you will like mybatis plus!
[the external chain picture transfer fails, and the source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-NbkF90Ws-1642810783229)(E:\Project\Typora\Image\image-20220121115923755.png)]
The following are CRUD extensions
3. Insert operation
Insert insert
// Test insertion @Test public void testInsert(){ User user = new User(); user.setName("Zhang San"); user.setAge(3); user.setEmail("123456@qq.com"); int result = userMapper.insert(user); // Help us automatically generate id System.out.println(result); // Number of rows affected System.out.println(user); // If found, id will be backfilled automatically }
==> Preparing: INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? ) ==> Parameters: 1484376555403714561(Long), Zhang San(String), 3(Integer), 123456@qq.com(String) <== Updates: 1 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4e94669c] 1 User(id=1484376555403714561, name=Madness theory Java, age=3, email=24736743@qq.com)
4. Primary key generation strategy
Default ID_WORKER globally unique id
Generation of unique id of distributed system: https://www.cnblogs.com/haoxinyue/p/5208136.htm
Snowflake algorithm:
snowflake is Twitter's open source distributed ID generation algorithm, and the result is a long ID. Its core idea is to use 41bit as the number of milliseconds, 10bit as the machine ID (5 bits are the data center and 5 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!
Its source code interpretation
public enum IdType { AUTO(0), // Database id self increment NONE(1), // No primary key set INPUT(2), // Manual input ID_WORKER(3), // Default globally unique id UUID(4), // Globally unique id uuid ID_WORKER_STR(5); //ID_WORKER string representation }
5. Update operation
// Test update @Test public void testUpdate(){ User user = new User(); // Automatic splicing of dynamic sql through conditions user.setId(2L); user.setName("Li Si"); user.setAge(18); // Note: updateById, but the parameter is an object! int i = userMapper.updateById(user); System.out.println(i); }
All sql is automatically configured for you dynamically!
==> Parameters: Li Si(String), 18(Integer), 2(Long) <== Updates: 1
6. Auto fill
Creation time and modification time! These operations are completed automatically. We don't want to update them manually!
Alibaba Development Manual: all database tables: gmt_create,gmt_modified almost all tables should be configured! And need automation!
6.1 method 1: database level
(you are not allowed to modify the database at work)
1. Add a new field create in the table_ time, update_ time
ALTER TABLE `user` ADD `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER `email`; ALTER TABLE `user` ADD `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Update time' AFTER `create_time`;
2. To test the insertion method again, we need to synchronize the entity class first!
public class User { private Long id; private String name; private Integer age; private String email; private Date createTime; private Date updateTime; }
3. Just update and view the results again
6.2 mode 2: code level
1. Delete the default value and update the database!
ALTER TABLE `user` CHANGE `create_time` `create_time` DATETIME NOT NULL, CHANGE `update_time` `update_time` DATETIME NOT NULL COMMENT 'Update time';
2. Annotation needs to be added on the field attribute of entity class
// Add padding to fields @TableField(fill = FieldFill.INSERT) private Date createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime;
3. Write a processor to process this annotation!
package com.example.mybatisplus; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.reflection.MetaObject; import org.springframework.stereotype.Component; import java.util.Date; @Slf4j @Component // Don't forget to add the processor to the IOC container! public class MyMetaObjectHandler implements MetaObjectHandler { // Population policy at insertion @Override public void insertFill(MetaObject metaObject) { log.info("start insert fill....."); // setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject this.setFieldValByName("createTime",new Date(),metaObject); this.setFieldValByName("updateTime",new Date(),metaObject); } // Population policy when updating @Override public void updateFill(MetaObject metaObject) { log.info("start update fill....."); this.setFieldValByName("updateTime",new Date(),metaObject); } }
4. Test insertion
==> Preparing: INSERT INTO user ( id, name, age, email, create_time, update_time ) VALUES ( ?, ?, ?, ?, ?, ? ) ==> Parameters: 1484438577780649986(Long), Zhang San(String), 3(Integer), 123456@qq.com(String), 2022-01-21 16:11:51.136(Timestamp), 2022-01-21 16:11:51.136(Timestamp) <== Updates: 1 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1b3bec6c] 1 User(id=1484438577780649986, name=Zhang San, age=3, email=123456@qq.com, createTime=Fri Jan 21 16:11:51 CST 2022, updateTime=Fri Jan 21 16:11:51 CST 2022)
5. Test update and observation time is enough!
[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-x0xikS6A-1642810783237)(E:\Project\Typora\Image\image-20220121161127411.png)]
7. Optimistic lock
Optimistic lock in the interview process, we are often asked optimistic lock, pessimistic lock! This is actually very simple!
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 a problem occurs, 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! Do it again!
Here we mainly explain the optimistic lock mechanism! Implementation method of optimistic lock: when fetching a record, when obtaining the current version update, when carrying this version for update, set version = newVersion where version = oldVersion. If the version is wrong, the update fails
Optimistic lock: 1. Query first to obtain the version number version = 1 -- A update user set name = "kuangshen", version = version + 1 where id = 2 and version = 1 -- B The thread finishes first. At this time version = 2,Will cause A Modification failed! update user set name = "kuangshen", version = version + 1 where id = 2 and version = 1
Test MP's optimistic lock plug-in
1. Add version field to the database!
ALTER TABLE `user` ADD `version` INT NOT NULL AFTER `update_time`;
2. We add the corresponding fields to the entity class
@Version //Optimistic lock Version annotation private Integer version;
3. We add the corresponding fields to the entity class
Method of MyBatisPlusConfig configuration class
package com.example.mybatisplus.config; //... // Scan our mapper folder @MapperScan("com.example.mybatisplus.mapper") @EnableTransactionManagement @Configuration // Configuration class public class MyBatisPlusConfig { // Register optimistic lock plug-in @Bean public OptimisticLockerInterceptor optimisticLockerInterceptor() { return new OptimisticLockerInterceptor(); } }
4. Test it!
// Successful test! @Test public void testOptimisticLocker(){ // 1. Query user information User user = userMapper.selectById(1L); // 2. Modify user information user.setName("kuangshen"); user.setEmail("24736743@qq.com"); // 3. Perform update operation userMapper.updateById(user); }
// Failed to test optimistic lock! Multithreading @Test public void testOptimisticLocker2(){ // Thread 1 User user = userMapper.selectById(1L); user.setName("kuangshen111"); user.setEmail("24736743@qq.com"); // Simulate another thread to perform queue jumping User user2 = userMapper.selectById(1L); user2.setName("kuangshen222"); user2.setEmail("24736743@qq.com"); userMapper.updateById(user2); // Spin lock to multiple attempts to submit! userMapper.updateById(user); // If there is no optimistic lock, the value of queue jumping thread will be overwritten! }
==> Preparing: UPDATE user SET name=?, age=?, email=?, create_time=?, update_time=?, version=? WHERE id=? AND version=? ==> Parameters: kuangshen222(String), 18(Integer), 24736743@qq.com(String), 2022-01-21 16:00:20.0(Timestamp), 2022-01-21 16:51:51.046(Timestamp), 1(Integer), 1(Long), 0(Integer) <== Updates: 1
8. Query operation
// Test query @Test public void testSelectById(){ User user = userMapper.selectById(1L); System.out.println(user); } // Test batch query! @Test public void testSelectByBatchId(){ List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3)); users.forEach(System.out::println); } // Using map operations by one of the conditional queries @Test public void testSelectByBatchIds(){ HashMap<String, Object> map = new HashMap<>(); // Customize to query map.put("name","Madness theory Java"); map.put("age",3); List<User> users = userMapper.selectByMap(map); users.forEach(System.out::println); }
9. Paging query
Pagination is used as much as ten times in the website!
1. Paging the original limit
2. pageHelper third party plug-in
3. MP also has a built-in paging plug-in!
How to use!
1. Just configure the interceptor component
Method of MyBatisPlusConfig configuration class
package com.example.mybatisplus.config; //... // Scan our mapper folder @MapperScan("com.example.mybatisplus.mapper") @EnableTransactionManagement @Configuration // Configuration class public class MyBatisPlusConfig { // Register optimistic lock plug-in @Bean public OptimisticLockerInterceptor optimisticLockerInterceptor() { return new OptimisticLockerInterceptor(); } // Paging plug-in @Bean public PaginationInterceptor paginationInterceptor() { return new PaginationInterceptor(); } }
2. Directly use the Page object!
// Test paging query @Test public void testPage(){ // Parameter 1: current page // Parameter 2: page size // After using the paging plug-in, all paging operations become simple! Page<User> page = new Page<>(2,5); userMapper.selectPage(page,null); page.getRecords().forEach(System.out::println); System.out.println(page.getTotal()); }
10. Delete operation
1. Delete record by id
// Test delete @Test public void testDeleteById(){ userMapper.deleteById(1L); } // Batch delete by id @Test public void testDeleteBatchId(){ userMapper.deleteBatchIds(Arrays.asList(1L, 2L, 4L)); } // Delete by map @Test public void testDeleteMap(){ HashMap<String, Object> map = new HashMap<>(); map.put("name","Madness theory Java"); userMapper.deleteByMap(map); }
We will encounter some problems in the working group: logical deletion!
11. Logical deletion
Physical delete: remove directly from the database
Logical deletion: it is not removed from the database, but invalidated by a variable! deleted = 0 => deleted = 1
Administrators can view deleted records! Prevent data loss, similar to recycle bin! Test:
1. Add a deleted field in the data table
ALTER TABLE `user` ADD `deleted` INT(11) NOT NULL COMMENT 'Logical deletion' AFTER `version`;
2. Add attribute in entity class
@TableLogic //Logical deletion private Integer deleted;
3. Configuration!
Method of MyBatisPlusConfig configuration class
package com.example.mybatisplus.config; //... // Scan our mapper folder @MapperScan("com.example.mybatisplus.mapper") @EnableTransactionManagement @Configuration // Configuration class public class MyBatisPlusConfig { // Register optimistic lock plug-in @Bean public OptimisticLockerInterceptor optimisticLockerInterceptor() { return new OptimisticLockerInterceptor(); } // Paging plug-in @Bean public PaginationInterceptor paginationInterceptor() { return new PaginationInterceptor(); } // Delete components logically! @Bean public ISqlInjector sqlInjector() { return new LogicSqlInjector(); } }
# Configure logical deletion mybatis-plus.global-config.db-config.logic-delete-value=1 mybatis-plus.global-config.db-config.logic-not-delete-value=0
4. Test delete!
// Test delete @Test public void testDeleteById(){ userMapper.deleteById(2L); }
==> Preparing: UPDATE user SET deleted=1 WHERE id=? AND deleted=0 ==> Parameters: 2(Long) <== Updates: 1
[the external chain picture transfer fails, and the source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-jkjrvdhb-1642810783238) (E: \ project \ typora \ image \ image-20220121190408855. PNG)]
The record is still in the database, but the value has changed!
We must master all the above CRUD operations and their extensions! It will greatly improve the efficiency of your work and writing projects
12. Performance analysis plug-in
In our usual development, we will encounter some slow sql.
Test! druid,
Function: performance analysis interceptor, used to output each SQL statement and its execution time
MP also provides a performance analysis plug-in. If it exceeds this time, it will stop running!
1. Import plug-in
Method of MyBatisPlusConfig configuration class
/** * SQL Execution efficiency plug-in */ @Bean @Profile({"dev","test"})// Set the dev test environment on to ensure our efficiency public PerformanceInterceptor performanceInterceptor() { PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor(); performanceInterceptor.setMaxTime(100); // ms sets the maximum time for sql execution. If it exceeds, it will not be executed performanceInterceptor.setFormat(true); // Format code return performanceInterceptor; }
- Remember to configure the environment in SpringBoot as dev or test environment!
# Configuration environment spring.profiles.active=dev
2. Test use!
@Test void selectAllUser() { // The parameter is a Wrapper and a condition constructor. We don't need null here // Query all users List<User> users = userMapper.selectList(null); users.forEach(System.out::println); }
Time: 39 ms - ID: com.example.mybatisplus.mapper.UserMapper.selectList Execute SQL: SELECT id, name, age, email, create_time, update_time, version, deleted FROM user WHERE deleted=0
[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-jGSDQjKR-1642810783239)(E:\Project\Typora\Image\image-20220121192502504.png)]
Using the performance analysis plug-in can help us improve efficiency!
13. Conditional constructor
Very important: Wrapper we can use it instead of writing some complex sql
Conditional constructor | mybatis plus (baomidou. Com)
1. Test one, remember to view the output SQL for analysis
@Test void MyWrapper() { // Query users whose name is not empty and whose mailbox is not empty, and whose age is greater than or equal to 12 QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper .isNotNull("name") .isNotNull("email") .ge("age",12); userMapper.selectList(wrapper).forEach(System.out::println); // Compare it with the map we just learned }
2. As the test continues, remember to view the output SQL for analysis
@Test void test2(){ // Query name: Zhang San QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.eq("name","Zhang San"); User user = userMapper.selectOne(wrapper); // Query one data, and multiple results appear. Use List or Map System.out.println(user); }
@Test void test3(){ // Query users aged between 20 and 30 QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.between("age",20,30); // section Integer count = userMapper.selectCount(wrapper);// Number of query results System.out.println(count); }
// Fuzzy query @Test void test4(){ QueryWrapper<User> wrapper = new QueryWrapper<>(); // Left and right t% wrapper .notLike("name","e") .likeRight("email","t"); List<Map<String, Object>> maps = userMapper.selectMaps(wrapper); maps.forEach(System.out::println); }
// Fuzzy query @Test void test5(){ QueryWrapper<User> wrapper = new QueryWrapper<>(); // id is found in the sub query wrapper.inSql("id","select id from user where id<3"); List<Object> objects = userMapper.selectObjs(wrapper); objects.forEach(System.out::println); }
//Test six @Test void test6(){ QueryWrapper<User> wrapper = new QueryWrapper<>(); // Sort by id wrapper.orderByAsc("id"); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println); }
14. Automatic code generator
dao, pojo, service and controller are all written by myself!
AutoGenerator is the code generator of mybatis plus. Through AutoGenerator, you can quickly generate the code of Entity, Mapper, Mapper XML, Service, Controller and other modules, which greatly improves the development efficiency.
Test:
package com.example.mybatisplus; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; 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; // Automatic code generator public class KuangCode { 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"); gc.setOutputDir(projectPath+"/src/main/java"); gc.setAuthor("Madness 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.setDriverName("com.mysql.cj.jdbc.Driver"); dsc.setUsername("root"); dsc.setPassword("123456"); dsc.setDbType(DbType.MYSQL); mpg.setDataSource(dsc); //3. Package configuration PackageConfig pc = new PackageConfig(); pc.setModuleName("blog"); pc.setParent("com.kuang"); pc.setEntity("entity"); pc.setMapper("mapper"); pc.setService("service"); pc.setController("controller"); mpg.setPackageInfo(pc); //4. Policy configuration StrategyConfig strategy = new StrategyConfig(); strategy.setInclude("blog_tags","course","links","sys_settings","user_record","user_say"); // Set the table name to map strategy.setNaming(NamingStrategy.underline_to_camel); strategy.setColumnNaming(NamingStrategy.underline_to_camel); strategy.setEntityLombokModel(true); // Automatic lombok; 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 } }