Basic CRUD of Mybatis operating database and detailed analysis of query operations

Table of contents

1. What is MyBaits?

2. Build MyBaits environment

3. Understand the MyBaits design pattern

MyBaits Operations Database:

Pre-work:

(1) Build database and table

(2) Add entity class

(3) Add Mapper interface

(4) Add UserMapper.xml 

Understand two return types:

(1)resultType

(2)resultMap

1. Query operation:

1.1 Simple query

1.2 Conditional query

1.3 like fuzzy query

1.4 Multi-table query

2. Insert operation

3. Delete operation

4. Modify operation



The knowledge about MyBaits is deeper and more detailed, so in order to ease the reading pressure, it is divided into two articles:

        1. Mybatis operates the basic CRUD of the database (this article);

        2. The five commonly used tags of dynamic SQL in Mybaits;


1. What is MyBaits?

        MyBaits is an extremely powerful persistence layer framework that supports custom SQL, stored procedures, and advanced mapping . Mybaits is based on JDBC , but it eliminates almost all of JDBC and the work of setting parameters and getting result sets . MyBaits can configure and map primitive types, interfaces and java objects as records in the database through simple XML or annotations .

        In short: MyBaits can interact between programs and databases more concisely.

Mybaits learning path:

        Understand what is MyBaits → learn to add Mybaits framework to java projects → initialize MyBaits (connect to database, configure XML, etc.) → learn basic database CRUD operations → understand dynamic SQL (the key of MyBaits) → master several commonly used dynamic SQL tags


2. Build MyBaits environment:

2.1 Create a Spring project and add Mybaits framework dependencies:

 2.2 Set MyBaits configuration information:

        (1) First connect to the database in the application.properties configuration file:

                Since the database driver MySQL Driver is specially introduced when introducing dependencies, it is necessary to set the class name for the driver here, but it is very simple, because as long as it is MySQL, the class name is as follows:

#Set MySQL driver class name 
spring.datasource.driver-class-name= com.mysql.cj.Driver

                If MyBaits needs to map database data through XML configuration, it must have a corresponding XML file, and set the path of the XML file in the MyBaits configuration file: mapper-locatins. Create the corresponding XML file in the resource directory. If the unified file name is: xxxMapper.xml, then write it as: *Mapper.xml when setting the path


#Set the XML path of MyBaits = the root directory of all classes: /mybatis directory/all XML files whose names end with Mapper.xml are mybatis.mapper-locations= classpath:/mybatis/*Mapper.xml to be mapped by current mybatis


3. Understand the MyBaits design pattern:

        First of all, the main tool of Mybaits consists of two parts: interface + xml;

  • interface : Since MyBaits is a tool for the persistence layer, it must accept interfaces, objects, etc. injected by other layers in order to comply with the standard layering;
  • xml : implement specific sql statements in the xml file;

        MyBaits combines and encapsulates interface and xml, and turns the interface that cannot be injected into a proxy object that can be injected. This process is transparent to users.

        So it can be realized: the data in the database and the object are mapped, and then the mutual conversion between the data and the object is completed.

for example:

  • Database table <——> class;
  • record (row data) <——> object;
  • Field <——> the attribute of the object;

MyBaits Operations Database:

        Next, start to operate the database through MyBaits; 

Pre-work:

(1) Build database and table:

        Preparations: first create a mycnblog database in MySQL, and then add a few tables:

-- 创建数据库
drop database if exists mycnblog;
create database mycnblog DEFAULT CHARACTER SET utf8mb4;

-- 使用数据数据
use mycnblog;

-- 创建表[用户表]
drop table if exists  userinfo;
create table userinfo(
    id int primary key auto_increment,
    username varchar(100) not null,
    password varchar(32) not null,
    photo varchar(500) default '',
    createtime timestamp default current_timestamp,
    updatetime timestamp default current_timestamp,
    `state` int default 1
) default charset 'utf8mb4';

-- 创建文章表
drop table if exists  articleinfo;
create table articleinfo(
    id int primary key auto_increment,
    title varchar(100) not null,
    content text not null,
    createtime timestamp default current_timestamp,
    updatetime timestamp default current_timestamp,
    uid int not null,
    rcount int not null default 1,
    `state` int default 1
)default charset 'utf8mb4';

-- 创建视频表
drop table if exists videoinfo;
create table videoinfo(
  	vid int primary key,
  	`title` varchar(250),
  	`url` varchar(1000),
		createtime timestamp default current_timestamp,
		updatetime timestamp default current_timestamp,
  	uid int
)default charset 'utf8mb4';

-- 添加一个用户信息
INSERT INTO `mycnblog`.`userinfo` (`id`, `username`, `password`, `photo`, `createtime`, `updatetime`, `state`) VALUES 
(1, 'admin', 'admin', '', '2021-12-06 17:10:48', '2021-12-06 17:10:48', 1);

-- 文章添加测试数据
insert into articleinfo(title,content,uid)
    values('Java','Java正文',1);
    
-- 添加视频
insert into videoinfo(vid,title,url,uid) values(1,'java title','http://www.baidu.com',1);

(2)  Add entity class:

        To operate the database through objects, you must first have the corresponding entity class: here, add a user entity class USer, which corresponds to the userinfo table.

        According to the field information in the userinfo table, set the one-to-one attribute with the entity class:

package com.example.demo.entity;
import lombok.Data;
import java.time.LocalDateTime;

@Data
public class User {
    private Integer id;
    private String username;
    private String password;
    private String photo;
    private LocalDateTime createtime;
    private LocalDateTime updatetime;
    private Integer state;
}

(3) Add Mapper interface:

        The Mapper interface is used to receive the interface, method, and object injected by other layers, and complete the mapping with the database data by combining xml; the creation of the Mapper interface is placed in a special mapper directory;

        Here is specially used to operate the userinfo table, its entity class is User, then first create a UserMapper interface:

       Note: Add the @Mapper annotation as soon as the MMapper interface is created! ! ! !

package com.example.demo.mapper;
import org.apache.ibatis.annotations.Mapper;

@Mapper // 一定要加 Mapper 注解!!!!
public interface UserMapper {
}

(4) Add UserMapper.xml:

        This is also the second of the two major tools of MyBaits mentioned above: the xml file of MyBaits, that is, the xml file to be used in conjunction with the Mapper interface (the xml file has many types, so it must be clearly distinguished), it is exactly The specific implementation of the data persistence layer. The path of all such xml files must be consistent with the mybatis-locations path configured at the beginning;

        First it has its fixed format:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybati
s.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">

</mapper>

  •  <mapper><mapper> tag: you need to specify the namespace attribute, which means the namespace, and its value is the full package name and class name of the Mapper interface ;
  • The sub-tags inside the mapper tag: that is, <select>, <insert>, <update> and other tags in the yellow box are used to implement specific SQL
  • Points to note about subtags:
    • The id should correspond to the method name in the Mapper interface;
    • The return type is filled in as required;

Understand two return types:

        There are two return types in xml: resultType and resultMap ;

        The function of the return type is that MyBatis does result mapping;

        If it is a query operation, the return type must be set;

        If it is an operation such as adding, deleting, changing, etc., the return type is not mandatory;

(1)resultType:

        This is the type with the most usage scenarios. The advantage is that it is very convenient. It can be defined directly from the full package name to the class name.

(2)resultMap:

        Return the dictionary mapping, there are specific usage scenarios:

  • If the field name is different from the attribute name of the entity class in the program, you can configure the resultMap mapping;
  • One-to-one and one-to-many relationships can be mapped using resultMap;

Demonstrate the first type: the field name and attribute name are different

The password in the database is password, and the attribute name in the UserMapper entity class is indeed pwd

 The query result will report an error: pwd cannot be detected

 Use resultMap to set the mapping relationship:

<mapper namespace="com.example.demo.mapper.UserMapper">
    <resultMap id="baseMap" type="com.example.demo.entity.User">
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="password" property="pwd"></result>
    </resultMap>
    
    <select id="getByPwd" resultMap="com.example.demo.mapper.UserMapper.baseMap">
        select * from userinfo where password=#{pwd}
    </select>
</mapper>

 The result of running here can be found out:

         (Big details) But if you rename the attribute name to be the same as the field name when using @Param() to pass parameters, you don’t have to go to great lengths to set the resultMap mapping;

The principle of resultMap setting mapping:

         In fact, this process is divided by querying the results. When the interface gets the parameters, pass the parameters to {} in the xml for matching, and then splice SQL with it and pass it to the database for implementation. When the database queries When the value is returned to MyBatis after the end, the resultMap will match the fields and attributes at this time;

The second and third types: one-to-one table mapping and one-to-many table mapping (just understand, and the follow-up articles will be specially explained, in order not to increase unnecessary space)


1. Query operation:

1.1 Simple query:

The following demonstrates a simple query function:

(1) Implement related methods in the Mapper interface:

@Mapper // 一定要加 Mapper 注解!!!!
public interface UserMapper {
    // 查询所有用户
    List<User> getAllUser();
}

(2) Implement specific SQL in the UserMapper.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybati
s.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
    <select id="getAllUser" resultType="com.example.demo.entity.User">
        select * from userinfo
    </select>
</mapper>

(3) Implement the UserService class and UserController class:

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    public List<User> getAllUser() {
        return userMapper.getAllUser();
    }
}
@RequestMapping("/user")
@RestController
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping("/getAllUser")
    private List<User> getAllUSer() {
        return userService.getAllUser();
    }
}

Check the query results after startup:

         In view of the fact that there are many kinds of SQL execution to be introduced, it would be very troublesome to access and view them all through url, so a once-and-for-all method is adopted: set and print SQL records, and execute unit tests;

Print the SQL executed by mybatis:

Continue to configure in the application.properties file, adding the following two sentences:

#打印 MyBaits 执行的 SQL
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
logging.level.com.example/demo=debug

unit test:

        In the Mapper interface, right-click - Generate - Test... - check the test method - generate test classes and test methods - add annotations to the test class @SpringBootTest - inject UserMapper objects - implement specific test methods

 Go here to do all the configuration and simplified operations, and continue to introduce operations such as adding, deleting, modifying, and checking;

1.2 Conditional query:

        All conditional queries involve conditional matching. From the perspective of users, it is necessary to pass parameters to methods, and SQL to match parameters;

        There are two methods of dynamic parameter parameter matching :

  1. #{paramName} - placeholder pattern;
  2. ${paramName} - direct replacement;

        The following demonstrates examples using these two matches:

#{} form:

@Mapper // 一定要加 Mapper 注解!!!!
public interface UserMapper {
    // 按照姓名查询
    User getUserByName(@Param("username") String username);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybati
s.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
    <select id="getUserByName" resultType="com.example.demo.entity.User">
        select * from userinfo where username=#{username}
    </select>
</mapper>
@SpringBootTest //声明测试类是运行在 SpringBoot 环境中的
class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    void getUserByName() {
        String username = "zhangSan";
        User user = userMapper.getUserByName(username);
        System.out.println(user);
    }
}

${} form: 

        Others do not need to be changed, only modify the SQL statement part in UserMapper.xml: 

<select id="getUserByName" resultType="com.example.demo.entity.User">
        select * from userinfo where username='${username}'
    </select>

        As shown in the result, because ${} is the logic of direct replacement, that is to say, we cannot forget to add single quotes when writing strings, and #{} is the logic of placeholders, which will automatically replace the parameters we pass make adaptive adjustments;

1.3 like fuzzy query:

        Special case: If you want to perform like fuzzy query, which of the two should you use?

If you use #{}: an error will be reported, because it will automatically add a pair of single quotes to the matched parameters

 If you use ${}: Although it can be found out, it cannot be used directly, in order to prevent the danger of SQL injection! ! !

SQL injection:

        In the following example, the user name and password must be matched correctly when querying, but the input of password at this time is very special. It realizes SQL injection, just like taking a key that does not belong to this door, but because of the size Like that, he opened the door and saw all the information inside. 

        Why was it found out? There is also an or after the and, as long as the conditions of the latter or are met, all will be found out;

<<< The correct fuzzy query should use the built-in concat splicing function for character splicing: >>>

<select id="getUserByLike" resultType="com.example.demo.entity.User">
        select * from userinfo where username like concat('%',#{username},'%')
    </select>


1.4 Multi-table query:

        In order to demonstrate multi-table query, entity classes of other tables are required. Here, the Article class corresponding to the articleinfo table in the current library is selected as its entity class;

        First add the Article entity class:

@Data
public class Article {
    private int id;
    private String title;
    private String content;
    private LocalDateTime createtime;
    private LocalDateTime updatetime;
    private int uid;
    private int rcount;
    private int state;
}

        Considering that there is no author information in the article table, we add another ArticleVO entity class as an extension class, inheriting the Article class, that is, when the desired article details are found, not only the column fields in the article table are displayed, but also the corresponding The author is also shown;

public class ArticleVO extends Article { 
    private String username; // 表示查询出来的文章是哪个作者写的
}

        The above is also decoupling. Imagine that in an enterprise, if a certain business performs multi-table query, there are many fields to be added to each other. It is impossible to add all the required attributes inside each entity class, so use the extension class De-inheritance can reduce redundancy and coupling, and improve development efficiency;

Let's start a multi-table query:

        Query the articleinfo table and userinfo table in the mycnblog library. The goal is to find out the detailed description of the article and its corresponding author. The article details are in the articleinfo table, and the author information is in the userinfo table;

        First of all, it is clear that for multi-table query, the main table should be the articleinfo table, and the username field of the userinfo table should be the outer connection part, so this time the query method and SQL must be completed on the basis of the articleinfo table;

(1) Add the ArticleMapper interface and add a multi-table query method:

@Mapper // 一定不要忘记注解
public interface ArticleMapper {
    // 多表查询
    ArticleVO getFromTwoTables(@Param("id") int id);
}

(2) Implement the SQL in ArticleMapper.xml:

<mapper namespace="com.example.demo.mapper.ArticleMapper">
    <select id="getFromTwoTables" resultType="com.example.demo.entity.vo.ArticleVO">
        select a.*, u.username from articleinfo a
        join userinfo u on a.uid=u.id
        where a.id=#{id}
    </select>
</mapper>

(3) Add test method:

@SpringBootTest
class ArticleMapperTest {
    @Autowired
    private ArticleMapper articleMapper;

    @Test
    void getFromTwoTables() {
        int id = 1;
        ArticleVO articleVO = articleMapper.getFromTwoTables(id);
        System.out.println("文章详情:" + articleVO);
    }
}

Results of the:

        If you have mastered the above series of query operations, then you can easily add, delete, and modify the following~


2. Insert operation:

       Adding, deleting, and modifying operations from here may affect the content of the data table. If the simple test does not modify it, you can add the @Transactional annotation to the unit test method, which means adding transaction operations and rolling back after the data in the table is manipulated.

        Add, delete, modify the return type in the xml of these operations;

@Mapper // 一定要加 Mapper 注解!!!!
public interface UserMapper {
    // 新增用户
    int addUser(User user);
}
<insert id="addUser">
        insert into userinfo (username,password) values(#{username}, #{password})
    </insert>
@SpringBootTest //声明测试类是运行在 SpringBoot 环境中的
class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    void addUser() {
        String username = "zhaoLiu";
        String password = "666666";
        User user = new User();
        user.setUsername(username);
        user.setPassword(password);
        int ret = userMapper.addUser(user);
        System.out.println("新增了 " +  ret + " 行");
    }
}


 3. Delete operation:

@Mapper // 一定要加 Mapper 注解!!!!
public interface UserMapper {
    // 删除用户
    int deleteUserByName(@Param("username") String username);
}
<delete id="deleteUserByName">
        delete from userinfo where username=#{username}
    </delete>
@SpringBootTest //声明测试类是运行在 SpringBoot 环境中的
class UserMapperTest {
    @Autowired
    private UserMapper userMapper;


    @Test
    void deleteUserByName() {
        String username = "zhaoLiu";
        int ret = userMapper.deleteUserByName(username);
        System.out.println("删除了 " + ret + " 行");
    }
}


4. Modify operation:

@Mapper // 一定要加 Mapper 注解!!!!
public interface UserMapper {
    // 修改操作
    int update(@Param("username")String username, @Param("password")String password);
}
<update id="update">
        update userinfo set username=#{username}
            where password=#{password}
    </update>
@SpringBootTest //声明测试类是运行在 SpringBoot 环境中的
class UserMapperTest {
    @Autowired
    private UserMapper userMapper;
    
    @Test
    void update() {
        String username = "张三";
        String password = "111111";
        int ret = userMapper.update(username,password);
        System.out.println("修改了 " + ret + " 行");
    }
}

 

Guess you like

Origin blog.csdn.net/m0_65190367/article/details/131383358