springboot integrates mybatis plus to realize one to one of one to many query function based on annotations

  • 2021-11-13 07:52:57
  • OfStack

Because the current version of mybatis-plus is 3.1. 1, it feels like a semi-finished product. All annotations on entity classes can only support single table, without 1-to-1 and 1-to-many relational mapping, and this function is still under development. I believe the mybatis-plus development team should realize this function in the near future.

Because of my development habits, I really hate a large number of xml flooding the whole project, especially the mapper. xml of the table. Although there are code generators that can generate it, some complex queries still need the dynamic sql in the handwritten configuration file, which is quite disgusted (as for why it is disgusted, there are many reasons).

However, it is possible that a large number of java developers have been abused. I am used to all kinds of configuration files. Although there are code generators, I think this is not the real way. It stands to reason that what is open source can be used by others as simply as possible, instead of relying on a large number of tools to use it (different people have different opinions).

Because I use spring-boot for development, and springboot advocates automatic configuration without configuration, I sincerely hope that mybatis (not mybatis-plus) needs to continue to work hard.

Based on this, mybatis-plus has been used in the implementation of the good method to take advantage of the operation, nonsense not to say, directly on the code.

The database is mysql.

The idea of demo is as follows: Student table (Student) and student class table (StudentClass), which are related to each other through class Id in students' entity classes, mainly through mapper interface, based on the annotations in @ Results, @ Result, @ One (or @ Many) and @ ResultMap

BaseMapper, QueryWrapper in mybatis-plus < ChannelEntity > Combined with the implementation, so we have to write 1 some code.

If the mybatis-plus team mapped relational 1 and implemented annotations on entity objects, it would save a lot of code, and we look forward to their early implementation.

pom file


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.lyb</groupId>
    <artifactId>spring-mybatis-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>spring-mybatis-demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!--
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.0.0</version>
        </dependency>
        -->

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.1.1</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus</artifactId>
            <version>3.1.1</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

You can see that database operations only depend on mybatis-plus-boot-starter

File application. yml


spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
    username: root
    password: liuyabin
    driver-class-name: com.mysql.jdbc.Driver
mybatis-plus:
  type-aliases-package: com.lyb.springmybatisdemo.entity
  type-aliases-super-type: java.lang.Object

Student entity class code, you can see that the entity class is annotated with mybatis-plus, and the annotation of @ Data lombok is also added here to save more code:


package com.lyb.springmybatisdemo.entity;

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 lombok.*;

@Data
@Builder
@ToString
@EqualsAndHashCode
@NoArgsConstructor
@AllArgsConstructor
@TableName(value = "student")
public class Student {
    @TableId(value = "Id",type = IdType.AUTO)
    private int id;
    @TableField(value = "SName",exist = true,select = true)
    private String name;
    @TableField(value = "Age")
    private int age;
    @TableField(value = "ClassId")
    private int classId;
    @TableField(exist = false)
    private StudentClass studentClass;
}

StudentClass class code:


package com.lyb.springmybatisdemo.entity;

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 lombok.*;

@Data
@Builder
@ToString
@EqualsAndHashCode
@NoArgsConstructor
@AllArgsConstructor
@TableName(value = "stuClass")
public class StudentClass {
    @TableId(value = "ClassId",type = IdType.AUTO)
    private int classId;
    @TableField(value = "ClassName")
    private String className;
}

The specific database structure will not be put, and it can be easily built with reference to the annotations on the entity class, because there are only two tables.

StudentClassMapper class code:


package com.lyb.springmybatisdemo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lyb.springmybatisdemo.entity.StudentClass;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface StudentClassMapper extends BaseMapper<StudentClass> {
}

This mapper is very simple, because BaseMapper in mybatis-plus has already done the basic single table operation, and this table does not have a 1-to-many requirement. If there is a 1-to-many requirement in reality, you can refer to the following 1-to-1 method.

StudentMapper code:


package com.lyb.springmybatisdemo.mapper;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lyb.springmybatisdemo.entity.Student;
import org.apache.ibatis.annotations.*;

import java.util.List;

@Mapper
public interface StudentMapper extends BaseMapper<Student> {
    @Results(id="stuMap",value = {
            @Result(property = "id",column = "Id"),
            @Result(property = "name",column = "SName"),
            @Result(property = "age",column = "Age"),
            @Result(property = "classId",column = "ClassID"),
            @Result(property = "studentClass",column = "ClassID",one = @One(select = "com.lyb.springmybatisdemo.mapper.StudentClassMapper.selectById"))
    })
    @Select("SELECT * FROM STUDENT WHERE ID=#{id}")
    Student findStudentById(int id);

    @Select("select * from Student where 1=1 and " +
            "${ew.sqlSegment}")
    @ResultMap(value = "stuMap")
    List<Student> selectStudents(@Param("ew") QueryWrapper<Student> wrapper);


}

Focus on the code for the selectStudents method. The 1-to-1 relationship is defined in @ Results of id= "stuMap", and you can see that there is a definition of @ One (select = "com. lyb. springmybatisdemo. mapper. StudentClassMapper. selectById"), which is not in the

StudentClassMapper, but mybatis-plus in BaseMapper to help us achieve, that can be directly and conveniently taken over to use, save us thank a method of code.

Parameter QueryWrapper passed in by selectStudents method < Student > wrapper can take advantage of lambda to build various where conditions of its own, and pay attention to how the @ Select class SQL of this method is written so that there is no error.

The next step is to insert multiple pieces of data into two tables, and then test the code:


package com.lyb.springmybatisdemo;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.lyb.springmybatisdemo.entity.Student;
import com.lyb.springmybatisdemo.mapper.StudentMapper;
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 java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringMybatisDemoApplicationTests {

    @Autowired
    private StudentMapper studentMapper;


    @Test
    public  void testByWrapper(){
        QueryWrapper<Student> queryWrapper = new QueryWrapper<Student>();
        queryWrapper.lambda().eq(Student::getAge,2)
                            .eq(Student::getClassId,1);
        List<Student> students = studentMapper.selectStudents(queryWrapper);
    }
}

Finally, the startup class of springboot


package com.lyb.springmybatisdemo;


import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.lyb.springmybatisdemo.mapper")
public class SpringMybatisDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringMybatisDemoApplication.class, args);
    }

}

If you run the test class and insert multiple pieces of data according to the query conditions, that is, the age is 2, the class Id is 1, and the class table is also inserted with data, the result will be queried, and the studentClass attribute of the Student object in the result has been assigned a value.


Related articles: