Differences and relations between Mybatis and MybatisPlus
Mybatis plus is an enhancement tool for mybatis. It is only enhanced on the basis of mybatis without change. Mybatis plus supports all the native features of mybatis. Therefore, the introduction of mybatis plus will not have any impact on the existing mybatis architecture. Mybatis plus (MP) is designed to simplify development and improve development efficiency. As the official website said,
Click here to enter the Official Learning Website
Get started quickly integrating the basics with SpringBoot
Import must depend on
- MybatisPlus integrates the scene launcher jar of SpringBoot
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.3</version> </dependency>
- Connect mysql driver jar
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>
Note that when the MySQL connector Java jar package version is not specified here, SpringBoot will specify a version for us by default
Configure data sources
#---------------Database connection configuration-------------- # user name spring.datasource.username=root # password spring.datasource.password=root # Connection url spring.datasource.url=jdbc:mysql://localhost:3306/school?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&autoReconnect=true # Drive name spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
Simple CRUD
Write entity class and database mapping
The entity class student corresponds to the database table student
package cn.soboys.springbootmybatisplus.bean; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.activerecord.Model; import lombok.Data; /** * @author kenx * @version 1.0 * @date 2021/6/25 10:08 */ @TableName("student") public class Student extends Model { @TableId(value = "student_id",type = IdType.AUTO) private Long studentId; @TableField("student_name") private String studentName; @TableField("age") private int age; @TableField("phone") private String phone; @TableField("addr") private String addr; public Long getStudentId() { return studentId; } public void setStudentId(Long studentId) { this.studentId = studentId; } public String getStudentName() { return studentName; } public void setStudentName(String studentName) { this.studentName = studentName; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getAddr() { return addr; } public void setAddr(String addr) { this.addr = addr; } }
Write mapper(dao) to interact with database
The interface StudentMapper is implemented by mybatis agent
package cn.soboys.springbootmybatisplus.mapper; import cn.soboys.springbootmybatisplus.bean.Student; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; import org.mybatis.spring.annotation.MapperScan; /** * @author kenx * @version 1.0 * @date 2021/6/25 10:53 */ @Mapper public interface StudentMapper extends BaseMapper<Student> { }
Write a service to implement specific business
- Interface IStudentService
package cn.soboys.springbootmybatisplus.service; import cn.soboys.springbootmybatisplus.bean.Student; import com.baomidou.mybatisplus.extension.service.IService; import org.springframework.stereotype.Service; /** * @author kenx * @version 1.0 * @date 2021/6/25 10:59 */ public interface IStudentService extends IService<Student> { }
- Implementation class StudentServiceImpl
package cn.soboys.springbootmybatisplus.service.impl; import cn.soboys.springbootmybatisplus.bean.Student; import cn.soboys.springbootmybatisplus.mapper.StudentMapper; import cn.soboys.springbootmybatisplus.service.IStudentService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; /** * @author kenx * @version 1.0 * @date 2021/6/25 13:35 */ @Service public class StudentServiceImpl extends ServiceImpl<StudentMapper,Student> implements IStudentService { }
Write controller main program
package cn.soboys.springbootmybatisplus.controller; import cn.soboys.springbootmybatisplus.bean.Student; import cn.soboys.springbootmybatisplus.service.IStudentService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.List; /** * @author kenx * @version 1.0 * @date 2021/6/25 11:09 */ @RestController @RequestMapping("/student") public class StudentController { @Autowired private IStudentService studentService; /** * Add student * * @param student * @return */ @PostMapping("/add") public boolean addStudent(@RequestBody Student student) { boolean flag = studentService.save(student); return flag; } /** * Update student information according to id * * @param student * @return */ @PutMapping("/update") public boolean updateStudent(@RequestBody Student student) { //Update student based on student id boolean flag = studentService.updateById(student); return flag; } /** * Find all student information * * @return */ @GetMapping("/list") public List<Student> list() { return studentService.list(); } /** * Delete student information according to id * * @param studentId * @return */ @DeleteMapping("/del/{studentId}") public boolean del(@PathVariable long studentId) { boolean flag = studentService.removeById(studentId); return flag; } /** * Get student information according to id * @param studentId * @return */ @GetMapping("{studentId}") public Student getStudentInfo(@PathVariable long studentId){ return studentService.getById(studentId); } }
Add a student to the database
We see that the returned result is true, indicating that the addition is successful
Modify the student information just added according to the student id
We can see that true is returned after the modification is successful. Note that when modifying here, an additional studentId parameter is passed, that is, the corresponding student is found through the student id to modify.
Query all student information
Delete student information according to student id
We see that the return of true indicates that the deletion is successful
Get a student's information according to id
Here, the most basic crud functions of a single table can be used normally
Advanced use of SpringBoot integration
We can see that the most basic integration has been completed, and many places can be further optimized
Simplify entity bean s
We can see that the Student entity class in the above integration method contains many getters, setters and unnecessary mapping annotations, which can be appropriately simplified
- Import the jar package lombok. There is no version written here. We use the version specified by springboot by default
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
lombok can automatically generate getters and setters by annotating @ Data. We only need to add this annotation to the corresponding entity class to remove redundant getters and setters in the code.
Simplified entity bean and database mapping annotation
We can see that the Student entity class in the above integration method contains @ TableName annotation and many @ TableField annotations. In fact, it complies with the mapping rules between java entity class and database in MybatisPlus, which can be appropriately simplified. By default, MybatisPlus will convert the big hump naming method (Pascal naming method) to the underline naming method corresponding to the database
For example, the entity class name is OwnUser, which will give you the corresponding own in the database_ User table
The field StudentId will give you the student in the corresponding database table_ Field of ID
Therefore, the final entity class can be simplified into the following code
package cn.soboys.springbootmybatisplus.bean; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.activerecord.Model; import lombok.Data; /** * @author kenx * @version 1.0 * @date 2021/6/25 10:08 */ @TableName @Data public class Student extends Model { @TableId(type = IdType.AUTO) private Long studentId; private String studentName; private int age; private String phone; private String addr; }
Simplify mapper scanning
The above integration method will add @ mapper annotation to each mapper interface class for scanning, which will cause redundancy. We can directly add @ MapperScan batch scanning mapper package on the SpringBoot startup class. Of course, we can also add @ MapperScan batch scanning mapper package on any other configuration class, However, it is generally added to the SpringBoot startup class (essentially, the SpringBoot startup class is also a configuration class),
This configuration is more centralized and meaningful, and there is no need to write an unintentional configuration class
package cn.soboys.springbootmybatisplus; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ApplicationContext; @SpringBootApplication @MapperScan({"cn.soboys.springbootmybatisplus.mapper"}) public class SpringbootMybatisplusApplication { private static ApplicationContext applicationContext; public static void main(String[] args) { applicationContext = SpringApplication.run(SpringbootMybatisplusApplication.class, args); //displayAllBeans(); } /** * Print all loaded bean s */ public static void displayAllBeans() { String[] allBeanNames = applicationContext.getBeanDefinitionNames(); for (String beanName : allBeanNames) { System.out.println(beanName); } } }
In this way, you can scan without adding @ Mapper annotation to each Mapper interface class separately
Database connection pool configuration
We only have simple database connection configuration above, but in real practical applications, we will use database connection pool to improve data connection efficiency and reduce unnecessary database resource overhead. The specific configuration is as follows
#---------------Database connection configuration-------------- #Data source type spring.datasource.type=com.zaxxer.hikari.HikariDataSource # user name spring.datasource.username=root # password spring.datasource.password=root # Connection url spring.datasource.url=jdbc:mysql://localhost:3306/school?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&autoReconnect=true # Drive name spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver #---------------Database connection pool HikariCP configuration-------------- #The minimum idle connection is 10 by default. If it is less than 0 or greater than maximum pool size, it will be reset to maximum pool size spring.datasource.hikari.minimum-idle=10 #The maximum number of connections, less than or equal to 0, will be reset to the default value of 10; Greater than zero and less than 1 will be reset to the value of minimum idle spring.datasource.hikari.maximum-pool-size=20 #Idle connection timeout. The default value is 600000 milliseconds (10 minutes), # If it is greater than or equal to Max lifetime and Max lifetime > 0, it will be reset to 0; If it is not equal to 0 and less than 10 seconds, it will be reset to 10 seconds. spring.datasource.hikari.idle-timeout=500000 #The maximum connection lifetime, which is not equal to 0 and less than 30 seconds, will be reset to the default value of 30 minutes The setting should be shorter than the timeout set by mysql spring.datasource.hikari.max-lifetime=540000 #Connection timeout: ms, less than 250 ms, otherwise it will be reset to the default value of 30 seconds spring.datasource.hikari.connection-timeout=60000 #A query statement used to test whether a connection is available spring.datasource.hikari.connection-test-query=SELECT 1
MybatisPlus configuration
We can see that the above integration is only a simple crud, single table operation. Our service and mapper do not write any methods. They only inherit the general Mapper,BaseMapper, general service interface IService of MybatisPlus and realize ServiceImpl. They have the basic crud methods. However, when encountering multi table complex condition query, they need to write sql separately, In this case, mapper needs to be configured separately XML file
#--------------------mybatisPlus configuration------------------ #mapper.xml file location mybatis-plus.mapper-locations=classpath:mapper/*.xml #Alias package scanning path. This property allows you to register aliases for classes in the package mybatis-plus.type-aliases-package=cn.soboys.springbootmybatisplus.bean #Print mybatisPlus LOGO on the console mybatis-plus.global-config.banner=true
MybatisPlus more detailed configuration
Paging plug-in usage
In MybatisPlus, we have also done relevant processing for paging. We need to do relevant configuration before we can use it normally
SpringBoot configuration class
package cn.soboys.springbootmybatisplus.config; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.springframework.boot.SpringBootConfiguration; import org.springframework.context.annotation.Bean; /** * @author kenx * @version 1.0 * @date 2021/6/28 10:19 */ @SpringBootConfiguration public class MyBatisCfg { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }
StudentMapper class
/** * Paging query of student information of each class * @param page Paging object, from which values can be obtained in xml. Pass the parameter Page, that is, automatic paging, which must be put in the first place (you can inherit Page to realize your own paging object) * @param gradeId Class id * @return Paging object */ IPage<Student> findStudentPage(Page<?> page, long gradeId);
studentMapper.xml
<!-- Equivalent to writing a common list Query, mybatis-plus Automatically page for you--> <select id="findStudentPage" resultType="Student"> select * from student ,grade g where g.grade_id=#{gradeId} </select>
IStudentService interface
/** * Paging query * @param page * @param gradeId Class id * @return */ IPage<Student> getStudentPage(Page<Student> page,long gradeId);
StudentServiceImpl implementation class
@Override public IPage<Student> getStudentPage(Page<Student> page,long gradeId) { // Without count sql optimization, you can solve the problem that MP cannot automatically optimize SQL. At this time, you need to query the count part yourself // page.setOptimizeCountSql(false); // When the total is less than 0 or setSearchCount(false) is set, the paging plug-in will not query the count // main points!! The object returned by paging is the same as the object passed in return this.baseMapper.findStudentPage(page,gradeId); }
StudentController main program call
/** * Page to get student details * * @return */ @GetMapping("listDetailPage") public IPage<Student> getStudentDetailPage(PageRequest request) { Page<Student> page = new Page<>(); //Set how many items are displayed on each page page.setSize(request.getPageSize()); //Set page page.setCurrent(request.getPageNum()); return studentService.getStudentPage(page, 1); }
Here, you need to transfer paging and other related information. You can encapsulate a paging query general object PageRequest
package cn.soboys.springbootmybatisplus; import lombok.Data; import java.io.Serializable; /** * @author kenx * @version 1.0 * @date 2021/6/28 10:41 * Paging query */ @Data public class PageRequest implements Serializable { private static final long serialVersionUID = -4869594085374385813L; /** * Current page data volume */ private int pageSize = 10; /** * Current page number */ private int pageNum = 1; /** * sort field */ private String field; /** * Collation, asc ascending, desc descending */ private String order; }
We see that the normal paging query displays 2 items on page 1 per page
Page 2
Code generator
We know that Mybatis can generate basic entity mapping beans through configuration, which simplifies our development time. There is no need to write cumbersome mapping beans, including a pile of attributes. MybatisPlus also has its own code generator AutoGenerator. Through simple configuration, we can quickly generate a complete model, service and mapper. We don't need to write it ourselves and inherit the general mapper, The original words of the service official website are as follows
Add dependency
<!--Generator dependency--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.4.1</version> </dependency> <!--MyBatis-Plus From 3.0.3 After that, the default dependencies of the code generator and the template engine are removed, and the related dependencies need to be added manually:--> <!--Add template engine dependencies, MyBatis-Plus support Velocity(Default) Freemarker,Beetl,Users can choose their familiar template engine, If it does not meet your requirements, you can use a custom template engine.--> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.31</version> </dependency>
Custom generator code
package cn.soboys.springbootmybatisplus; import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException; import com.baomidou.mybatisplus.core.toolkit.StringPool; import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.baomidou.mybatisplus.generator.AutoGenerator; import com.baomidou.mybatisplus.generator.InjectionConfig; import com.baomidou.mybatisplus.generator.config.*; import com.baomidou.mybatisplus.generator.config.po.TableInfo; import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine; import java.util.ArrayList; import java.util.List; import java.util.Scanner; /** * @author kenx * @version 1.0 * @date 2021/6/28 11:31 * Automatic code generator */ public class MyBatisGeneratorCode { /** * <p> * Read console content * </p> */ public static String scanner(String tip) { Scanner scanner = new Scanner(System.in); StringBuilder help = new StringBuilder(); help.append("Please enter" + tip + ": "); System.out.println(help.toString()); if (scanner.hasNext()) { String ipt = scanner.next(); if (StringUtils.isNotBlank(ipt)) { return ipt; } } throw new MybatisPlusException("Please enter the correct" + tip + "!"); } public static void main(String[] args) { // Code generator AutoGenerator mpg = new AutoGenerator(); // Global configuration GlobalConfig gc = new GlobalConfig(); String projectPath = System.getProperty("user.dir"); gc.setOutputDir(projectPath + "/src/main/java"); gc.setAuthor("kenx"); gc.setOpen(false); // gc.setSwagger2(true); Entity attribute Swagger2 annotation mpg.setGlobalConfig(gc); // Data source configuration DataSourceConfig dsc = new DataSourceConfig(); dsc.setUrl("jdbc:mysql://localhost:3306/school?useUnicode=true&useSSL=false&characterEncoding=utf8"); // dsc.setSchemaName("public"); dsc.setDriverName("com.mysql.jdbc.Driver"); dsc.setUsername("root"); dsc.setPassword("root"); mpg.setDataSource(dsc); // Package configuration PackageConfig pc = new PackageConfig(); pc.setModuleName(scanner("Module name")); pc.setParent("cn.soboys.springbootmybatisplus.generator"); mpg.setPackageInfo(pc); // Custom configuration InjectionConfig cfg = new InjectionConfig() { @Override public void initMap() { // to do nothing } }; // If the template engine is freemaker String templatePath = "/templates/mapper.xml.ftl"; // If the template engine is velocity // String templatePath = "/templates/mapper.xml.vm"; // Custom output configuration List<FileOutConfig> focList = new ArrayList<>(); // Custom configuration will be output first focList.add(new FileOutConfig(templatePath) { @Override public String outputFile(TableInfo tableInfo) { // Customize the output file name. If you set the Prefix suffix for Entity, note that the name of xml will change!! return projectPath + "/src/main/resources/mapper/generator/" + pc.getModuleName() + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML; } }); /* cfg.setFileCreate(new IFileCreate() { @Override public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) { // Determine whether custom folders need to be created checkDir("The directory created by calling the default method, and the user-defined directory is marked with ""); if (fileType == FileType.MAPPER) { // The mapper file has been generated. It is judged that it exists. If you do not want to regenerate it, false is returned return !new File(filePath).exists(); } // Allow template files to be generated return true; } }); */ cfg.setFileOutConfigList(focList); mpg.setCfg(cfg); // Configuration template TemplateConfig templateConfig = new TemplateConfig(); // Configure custom output templates //Specify the path of custom template. Be careful not to bring it ftl/.vm, which will be automatically identified according to the template engine used // templateConfig.setEntity("templates/entity2.java"); // templateConfig.setService(); // templateConfig.setController(); templateConfig.setXml(null); mpg.setTemplate(templateConfig); // Policy configuration StrategyConfig strategy = new StrategyConfig(); strategy.setNaming(NamingStrategy.underline_to_camel); strategy.setColumnNaming(NamingStrategy.underline_to_camel); //strategy.setSuperEntityClass("your own parent entity, no need to set it!"); strategy.setEntityLombokModel(true); strategy.setRestControllerStyle(true); // Public parent class //strategy.setSuperControllerClass("your own parent controller, you don't need to set it if you don't have it!"); // Public fields written in the parent class strategy.setSuperEntityColumns("id"); strategy.setInclude(scanner("Table name, separated by multiple English commas").split(",")); strategy.setControllerMappingHyphenStyle(true); strategy.setTablePrefix(pc.getModuleName() + "_"); mpg.setStrategy(strategy); mpg.setTemplateEngine(new FreemarkerTemplateEngine()); mpg.execute(); } }
Post run results
We see that the operation is successful and the directory structure we need has been generated normally
This template is a general template. You only need to change it a little. You need to generate databases, packages and directories
For more information, please refer to the official website
SpringBoot integrates high-level use
Debug and print sql
During development, we often need to debug the code and check whether the generated sql is correct. At this time, we need to print the sql on the console
Import dependency
<!-- https://mvnrepository.com/artifact/p6spy/p6spy --> <dependency> <groupId>p6spy</groupId> <artifactId>p6spy</artifactId> <version>3.9.0</version> </dependency>
Profile configuration
#Change the url to the connection url starting with p6spy spring.datasource.url=jdbc:p6spy:mysql://localhost:3306/school?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&autoReconnect=true # Drive name # You need to debug the print sql driver to p6spy intercept spring.datasource.driver-class-name=com.p6spy.engine.spy.P6SpyDriver
spy profile
#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
We see that the running sql is successfully printed out through the simple configuration console