1. Set up the environment
Construction of Spring Initializr
The project structure after creation
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
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,'上海');
id is set to automatically increment the primary key
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
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
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
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
The findById test needs to pass in an id parameter and set the value
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
Click send to add successfully
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
after modification
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
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
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
When the user logs in, we use this sql to verify whether the account password is correct:
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
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!