Quickly master Mybaits in one day[1]

1. Set up the environment

Construction of Spring Initializr

insert image description here

insert image description here

The project structure after creation

[External link image transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the image and upload it directly (img-CLSvNTwT-1669084188543) (E:\localhost\mybatis\image-20221102131813833.png)]

[External link image transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the image and upload it directly (img-LdcrLAkQ-1669084188544) (E:\localhost\mybatis\image-20221102131911120.png)]

At this time, the suffix of application is renamed to yml, because in this way, it looks more concise and clear, but there is no difference in function

Construction of the database environment

new database

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-kUjMAhmT-1669084188546)(E:\localhost\mybatis\image-20221102132318426.png)]

Execute SQL statement

use `mybatis-demo`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `address` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
insert  into `user`(`id`,`username`,`age`,`address`) values (1,'UZI',19,'上海'),(2,'PDD',25,'上海');

insert image description here

insert image description here

id is set to automatically increment the primary key

insert image description here

yml configuration

server:
  port: 8098

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver     # msyql8 加cj mysql8以下去掉cj
    url: jdbc:mysql://localhost:3306/mybatis-demo?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=UTF-8
    username: root   # url是表示用于与mysql的进行一个连接 如果是本机 可以用localhost 如果不是要更换成ip
    password: 123456   #username表示SQL 账号 password表示密码

mybatis:
  mapper-locations: classpath:/Mapper/*.xml   #resources 目录下的 Mapper 目录下面的所有xml文件
  type-aliases-package: com.yhn.entity        #自动配置别名
  configuration:
    map-underscore-to-camel-case: true                      #开启驼峰命名
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl   #配置打印SQL语句


project structure

[External link image transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the image and upload it directly (img-5cZG0Z0F-1669084188552) (E:\localhost\mybatis\mybatis.assets\image-20221108112353481.png)]

2. Basic CRUD

General web development requires these levels

  • The Controller control plane is responsible for receiving the parameters passed from the front end
  • Service business processing layer is responsible for business processing
  • The Mapper/Dao data layer is responsible for data calls

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-VQsVu88T-1669084188556)(E:\localhost\mybatis\mybatis.assets\image-20221107235541022.png)]

structure building

Controller

package com.yhn.controller;

import com.yhn.entity.User;
import com.yhn.service.UserService;
import org.springframework.web.bind.annotation.*;
/**
 * CRUD
 * @Description
 * @Author YeHaoNan~
 * @Date 2/11/2022  23:37
 * @Version 1.0.0
 **/
@RestController
@RequestMapping("/user")
public class UserController {
    
    
    @Resource
    private UserService service;
}

Service

public interface UserService {
    
    
}

ServiceImpl

@Service
public class UserServiceImpl implements UserService {
    
    
    @Resource
    private UserMapper mapper;
}

Mapper

@Mapper
public interface UserMapper {
    
    
}

interview questions

@RestController is a compound annotation of which annotations

@Target({
    
    ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
    
    
    @AliasFor(
        annotation = Controller.class
    )
    String value() default "";
}

/*
最主要的就是
@Controller
@ResponseBody

@Controller :
spring会遍历上面扫描出来的所有bean,过滤出那些添加了注解@Controller的bean,将Controller中所有添加了注解@RequestMapping的方法解析出来封装成RequestMappingInfo存储到RequestMappingHandlerMapping中的mappingRegistry。后续请求到达时,会从mappingRegistry中查找能够处理该请求的方法。

@ResponseBody
加上 @ResponseBody 后返回结果不会被解析为跳转路径,而是直接写入 HTTP response body 中。 比如异步获取 json 数据,加上 @ResponseBody 后,会直接返回 json 数据。@RequestBody 将 HTTP 请求正文插入方法中,使用适合的 HttpMessageConverter 将请求体写入某个对象。 可以加方法上面也可以加在类上面,加在类上面的话,那么就表示所有的方法都会自动添加@RequestBody
*/

The difference between @Autowired and @Resource

1. Both @Autowired and @Resource can be used to assemble beans. Both can be written on the field or on the setter method.

2. @Autowired is assembled by type by default (this annotation belongs to spring). By default, the dependent object must exist. If you want to allow null values, you can set its required attribute to false, such as: @Autowired(required= false), if we want to use name assembly, we can use it in conjunction with the @Qualifier annotation

3. @Resource (this annotation belongs to J2EE), is assembled according to the name by default, and the name can be specified through the name attribute. If the name attribute is not specified, when the annotation is written on the field, the default field name is used to search for the installation name. If The annotation is written on the setter method, and the attribute name is used for assembly by default. Wiring is done by type when no bean matching the name is found. But it should be noted that if the name attribute is specified, it will only be assembled according to the name.

Recommended use: @Resource is annotated on the field, so that there is no need to write the setter method, and this annotation belongs to J2EE, which reduces the coupling with spring. This code looks more elegant.

Inquire

@RestController
@RequestMapping("/user")
public class UserController {
    
    

    @Resource
    private UserService service;

    /**
     *  查询所有
     * @author YeHaoNan~
     * @date 2/11/2022 23:37
     * @return List<User>
     */
    @GetMapping("/findAll")
    public List<User> findAll(){
    
    
        return service.findAll();
    }

    /**
     * 根据id进行查询
     * @author YeHaoNan~
     * @date 2/11/2022 23:38
     * @param id
     * @return User
     */
    @GetMapping("/findById")
    public User findById(Integer id){
    
    
        return service.findById(id);
    }
}
public interface UserService {
    
    

    /**
     *  查询所有
     * @author YeHaoNan~
     * @date 2/11/2022 23:38
     * @return List<User>
     */
    List<User> findAll();

    /**
     * 根据id进行查询
     * @author YeHaoNan~
     * @date 2/11/2022 23:38
     * @param id
     * @return User
     */
    User findById(Integer id);
}
@Service
public class UserServiceImpl implements UserService {
    
    
    @Resource
    private UserMapper mapper;


    @Override
    public List<User> findAll() {
    
    
        return mapper.findAll();
    }

    @Override
    public User findById(Integer id) {
    
    
        return mapper.findById(id);
    }
}
@Mapper
public interface UserMapper {
    
    

    /**
     *  查询所有
     * @author YeHaoNan~
     * @date 2/11/2022   23:38
     * @return List<User>
     */
    List<User> findAll();

    /**
     * 根据id进行查询
     * @author YeHaoNan~
     * @date 2/11/2022   23:38
     * @param id
     * @return User
     */
    // @Param 注解 后面会详细讲解  在当前你可以看做不存在
    User findById(@Param("id") Integer id);
}

mybatis mapping file suffix xml

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

    <select id="findAll" resultType="com.yhn.entity.User">
        select * from user
    </select>

    <select id="findById" resultType="com.yhn.entity.User">
        select * from user where id = #{id}
    </select>
</mapper>

Analysis: The namespace in the Mapper in Mybatis is used to bind the Dao/Mapper interface, that is, interface-oriented programming. Its function is equivalent to the implementation class Impl of the Dao interface, but it does not need to write the interface implementation class, through the namesapce (namespace) The binding directly finds the corresponding method through the id and executes the corresponding SQL statement.

For example, I currently write com.yhn.mapper.UserMapper, so it can be understood in a popular way that my mybatis mapping file is only
used by UserMapper under the com.yhn.mapper package.

How to look at it more clearly? You can download an idea plugin MybatisX plugin

[External link image transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the image and upload it directly (img-2shxlITd-1669084188558) (E:\localhost\mybatis\mybatis.assets\image-20221108124201519.png)]

The effect after installing the plug-in, the blue red bird takes the line as an example, and the namespese corresponds to the interface under the package

The meaning of mybatis label

<select></select> <!--表示这个是一个SQL查询<==> SELECT-->
<insert></insert> <!--表示这个是一个SQL新增<==> INSERT-->
<update></update> <!--表示这个是一个SQL修改<==> UPDATE-->
<delete></delete> <!--表示这个是一个SQL删除<==> DELETE-->
你就可以这里理解 你现在要执行什么类型的SQL 你就使用什么样的标签

select insert update delete tag attributes

id : represents the method of the interface bound by the namespace

resultType : Represents the returned type is generally the returned entity type

There will be more in the future, and I will continue to explain later

Why is there a @RequestParam annotation in the findById method under UserController?

First of all, to be clear, even if this place is not added, it has no effect, the program can still run and return values, everything is normal

So? Why do you need to add the @RequestParam annotation?

First introduce @RequestParam here

effect:

​ @RequestParam: Bind the request parameters to the method parameters of your controller (it is an annotation to receive ordinary parameters in springmvc)

grammar:

​ @RequestParam(value=”parameter name”, required=”true/false”, defaultValue=””)

​ value: parameter name

​required: Whether to include this parameter, the default is true, indicating that the request path must include this parameter, if not, an error will be reported.

​ defaultValue: The default parameter value. If this value is set, required=true will be invalid, and it will be false automatically. If this parameter is not passed, the default value will be used

With @RequestParam and without @RequestParam
1. If you add @RequestParam,
1.1 The defaultValue attribute can set the default value for the parameter,
1.2 required can set whether the parameter must be passed, the default is true
1.3 value can be the key of the value passed from the front end Bind to the parameter you use to receive the value, no need to care whether the parameter name is consistent
1.4 If the defaultValue attribute is set, then required is false by default
2. If you do not add @RequestParam
2.1 The key of the parameter passed from the front end must be accepted by your back end The parameter name of the value is the same, otherwise the value cannot be obtained.
2.2 If the type of the parameter set by the backend is a basic data type such as int long and other 8 basic types, and the front end does not pass this parameter, then an error will be reported "Optional
char parameter 'xxx' is present but cannot be translated into a null value due to being declared as a primitive type. Consider declaring it as object wrapper for the corresponding primitive type "This means that the
parameter xxx is optional, but itself It is a basic type of data, and there is no way to convert it into a null value. Let you consider converting it into the current basic type of wrapper class such as Long, Integer, etc., then you can convert it into the corresponding wrapper class. 2.3 Backend
settings If the type of the parameter is a wrapper class or a String or a custom class, then the front end can pass it or not, and if it does not pass it, it will get a null value

Why is there a @Param annotation in the findById method under UserMapper?

The role of @Param is to name the parameters, such as a method A (int id) in the mapper, when adding annotations A (@Param("userId") int id), that is to say, the outside wants to take out the incoming id value , you only need to take its parameter name userId. Pass the parameter value as in the SQL statement, and use #{userId} to assign the value to the SQL parameter.

In fact, there are many ways, but not recommended, but will be mentioned later

Test cases This document always uses ApiPost, of course other postman, Apifox can also be used

Because the findAll interface does not have any parameters, all request areas are empty

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-brZeYY1a-1669084188559)(E:\localhost\mybatis\mybatis.assets\image-20221108155039504.png)]

The findById test needs to pass in an id parameter and set the value

[External link image transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the image and upload it directly (img-DUFccShO-1669084188560) (E:\localhost\mybatis\mybatis.assets\image-20221108155709544.png)]

Add

Add in UserController

 	@PostMapping("/insert")
    public void insert(@RequestBody User user){
    
    
        service.insert(user);
    }

Add in UserService

/**
     * 新增一条数据
     * @author YeHaoNan~
     * @date 2/11/2022 23:40
     * @param user
     */
    void insert(User user);

Add in UserServiceImpl

  @Override
    public void insert(User user) {
    
    
        mapper.insert(user);
    }

Add in UserMapper

void insert(@Param("user") User user);

Add in UserMapper.xml

    <insert id="insert" >
        insert into user
        value (
            #{user.id},
            #{user.userName},
            #{user.age},
            #{user.address}
        )
    </insert>

test

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-Zw4hAPSu-1669084188561)(E:\localhost\mybatis\mybatis.assets\image-20221108160716423.png)]

Click send to add successfully

[External link image transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the image and upload it directly (img-fBIuJL9t-1669084188563) (E:\localhost\mybatis\mybatis.assets\image-20221108160812280.png)]

Because auto-increment is set, the id sequence will automatically increment

To develop knowledge, why should strength classes be sent in json format? Why should the parameters in the controller layer be annotated with @RequestBody when adding new ones?

For example, in a scenario, the user fills in the information on the page. When adding new information, the front end will convert the meaning and information of the corresponding information into a json string, send it to the back end, and the back end will receive it. However, the back end needs to It is unacceptable to receive json string directly, and it will cause an error, then you need to use @RequestBody annotation, add it to the parameter, you can process and accept the json string data passed from the front end

Revise

Add in UserController

	@PostMapping("update")
    public void update(@RequestBody User user){
    
    
        service.update(user);
    }

UserService

void update(User user);

UserserviceImpl

    @Override
    public void update(User user) {
    
    
        mapper.update(user);
    }

UserMapper

    void update(@Param("user")User user);

Usermapper.xml

<update id="update" >
        update user set
                        username = #{user.userName},
                        age = #{user.age},
                        address = #{user.address}
        where
            id = #{user.id}
    </update>

test

[External link image transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the image and upload it directly (img-ARb9SU0S-1669084188565) (E:\localhost\mybatis\mybatis.assets\image-20221108162229627.png)]

after modification

[External link image transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the image and upload it directly (img-k23ckpHD-1669084188566) (E:\localhost\mybatis\mybatis.assets\image-20221108162258307.png)]

delete

UserController

    @PostMapping("delete")
    public void delete(Integer id){
    
    
        service.delete(id);
    }

UserService

    void delete(Integer id);

UserServiceImpl

  @Override
    public void delete(Integer id) {
    
    
         mapper.delete(id);
    }

UserMapper

void delete(@Param("id") Integer id);

UserMapper.xml

  	<delete id="delete" >
        delete from user where id = #{
    
    id}
    </delete>

test

[External link image transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the image and upload it directly (img-1PFr2CJo-1669084188568) (E:\localhost\mybatis\mybatis.assets\image-20221108164337171.png)]

console log

==>  Preparing: delete from user where id = ?
==> Parameters: 20(Integer)
<==    Updates: 1

finished deleting

3. Two ways for MyBatis to obtain parameter values ​​(emphasis, often tested in interviews)

${} and #{}

The difference between ${} and #{}

Two ways for MyBatis to get parameter values: ${} and #{}

The essence of ${} is string concatenation, and the essence of #{} is placeholder assignment

${} uses string concatenation to concatenate sql. If it is a field of string type or date type, you need to manually add single quotation marks;

However, #{} uses the way of placeholder assignment to splice sql. At this time, when assigning a value to a field of string type or date type, single quotes can be added automatically

#{} is precompiled) processing, it is a placeholder, ${} is a string replacement, it is a splicing character

When Mybatis processes #{}, it will replace #{} in sql with? Number, call PreparedStatement to assign

demo

//Controller
@GetMapping("findByUserName")
public User findByUserName(@RequestParam("userName") String userName){
    
    
    return service.findByUserName(userName);
}

//Service 
    User findByUserName(String userName);

//ServiceImpl
    @Override
    public User findByUserName(String userName) {
    
    
        return mapper.findByUserName(userName);
    }

//Mapper
    User findByUserName(@Param("userName") String userName);

test

[External link image transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the image and upload it directly (img-nKT4ArLi-1669084188569) (E:\localhost\mybatis\mybatis.assets\image-20221108233433909.png)]

When using #{}

UserMapper.xml

<select id="findByUserName" resultType="com.yhn.entity.User">
        select * from user  where username = #{userName}
    </select>

Console log output:

==>  Preparing: select * from user where username = ?
==> Parameters: 武光职(String)
<==    Columns: id, username, age, address
<==        Row: 21, 武光职, 20, 湖北
<==      Total: 1

When using ${} plus ''

    <select id="findByUserName" resultType="com.yhn.entity.User">
        select * from user  where username =  '${userName}'
    </select>

console output

JDBC Connection [HikariProxyConnection@1631783826 wrapping com.mysql.cj.jdbc.ConnectionImpl@751e3ee7] will not be managed by Spring
==>  Preparing: select * from user where username = '武光职'
==> Parameters: 
<==    Columns: id, username, age, address
<==        Row: 21, 武光职, 20, 湖北
<==      Total: 1

When using ${} without ''

   <select id="findByUserName" resultType="com.yhn.entity.User">
        select * from user  where username =  ${userName}
    </select>

console output

threw exception [Request processing failed; nested exception is org.springframework.jdbc.BadSqlGrammarException: 
### Error querying database.  Cause: java.sql.SQLSyntaxErrorException: Unknown column '武光职' in 'where clause'
### The error may exist in file [G:xxx/xxx/xxx]
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: select * from user  where username =  武光职
### Cause: java.sql.SQLSyntaxErrorException: Unknown column '武光职' in 'where clause'
; bad SQL grammar []; nested exception is java.sql.SQLSyntaxErrorException: Unknown column '武光职' in 'where clause'] with root cause

java.sql.SQLSyntaxErrorException: Unknown column '武光职' in 'where clause'

It means SQL syntax error

Unknown column 'Wu Guangzhi' in 'where clause'

means not found

So why is there such a situation?

That's because #{} will automatically add '' around the value and ${} will not

That is, as mentioned earlier:

#{}Use placeholder assignment to splice sql. At this time, when assigning a value to a field of string type or date type, single quotes can be automatically added

And what if it is of type int?

To test the findById method under UserController

   <!-- User findById(@Param("id") Integer id);  -->
	<select id="findById" resultType="com.yhn.entity.User">
        select * from user where id = ${id}
    </select>

console output

==>  Preparing: select * from user where id = 1
==> Parameters: 
<==    Columns: id, username, age, address
<==        Row: 1, UZI, 19, 上海
<==      Total: 1

The result can still be output because it is an int type at this time. In the SQL statement, the int type data itself does not need '' but the date string type is required, otherwise an error will be reported

How to use ${} and #{}

performance considerations

Because the precompiled statement object can be reused , the PreparedStatement object generated after a sql precompilation is cached, and the cached PreparedStatement object can be used directly for the same sql next time. Mybatis precompiles all sql by default. In this case, the performance of the #{} processing method will be relatively high.

security considerations

If it is used as a condition variable, it is safer to use #{}

Performance is not a case, the following is a safety case

This is a user account and password data

img

When the user logs in, we use this sql to verify whether the account password is correct:

insert image description here

select * from user where username=${username} and password=${password}

Obviously, this sql can be checked out without any problem, but what if someone wants to log in to the account without knowing the password?

We don't need to fill in the correct password:

username=yyy; password=1 or 1=1, the sql execution is actually

select * from user where username='yyy' and password=1 or 1 =1

Note: The single quotes outside yyy here are not provided by the symbol. {} notation provided.symbols provided . _ {} does not have this function, it can be spliced ​​manually by sql, the logic here may not be strict, but the simplest example of sql entry is like this.

So #{} is safer because he will automatically add single quotes

select * from user where username=#{username} and password=#{password}

username=yyy; password=1 or 1=1, the sql execution is actually

insert image description here

At this time, the password is directly wrong, and others cannot enter

How to choose to use #{} and ${}?

When the table name and the sort field of order by are used as variables, use ${}.

Try to use #{} when you can use #{}

I am programmer Xiaomeng, welcome to like and follow! Keep updating dry goods!

Guess you like

Origin blog.csdn.net/mengchuan6666/article/details/127977946