MyBatis basic addition, deletion, modification and query


MyBatis

1. What is MyBatis?

MyBatis is a data persistence layer framework that supports custom SQL, stored procedures (rarely used) and advanced mapping. MyBatis removes almost all JDBC code and the work of setting parameters and obtaining result sets. MyBatis can configure and map primitive types, interfaces, and Java POJOs (Plain Old Java Objects, Plain Old Java Objects) as records in the database through simple XML or annotations.

To put it simply, MyBatista is a tool for simply completing program and data interaction, that is, a tool for simpler operation and reading of databases.

2. Why learn MyBatis

For Java back-end programmers, the program is nothing more than two parts

  1. program
  2. database

Back-end programmers are nothing more than CRUD of the database.

For these two important components to communicate, they must rely on database connection tools, typically JDBC. Why do we need to learn the MyBatis framework when we have JDBC? JDBC probably has several processes:

  1. Go to the Maven repository to download the JDBC jar package and import it
  2. Create a database, set the user name and password in the code create a DataSource to get the Connection connection
  3. ?Write SQL statements with placeholders
  4. Replace the placeholder ?with the name of the field to be operated and specify the type
  5. Obtain the Statement object through the connection
  6. Execute SQL through Statement to obtain ResultSet result set or affect the number of rows
  7. Process the result set
  8. release resources

Every time JDBC operates the database, it needs to repeat the operation again and again, establish a connection, assemble SQL, execute SQL, process the result set, and finally release resources.

In order to solve this series of troublesome operations, you can use MyBatis to operate the database more simply.

3. Build the first MyBatis environment

This is a simple framework interaction flowchart

insert image description here

  • Mapper is what we call the data persistence layer
  • Inteface is the interface we write in the class. The methods in the interface are not specifically implemented. An interface corresponds to a table. The methods in the table correspond to some operations
  • In xml, it is the implementation of the interface method, the writing of SQL, and xml is the fixed writing method provided by MyBatis
  • When the program is running, MyBatis will combine Inteface and xml into one, generate SQL and call JDBC
  • Then return the result from the Mapper to the Service layer

MyBatis is also an ORM framework, ORM (Object Relational Mapping), that is, object-relational mapping. In the object-oriented programming language, the data objects in the relational database establish a mapping relationship, and then automatically complete the conversion between data and objects:

  1. Map input data (that is, incoming objects) + SQL to native SQL
  2. Map the result set back to the object, which is the output object

The ORM maps the database to objects:

  • Database table (table) --> class (class)
  • Record (record, row data) --> Object (Object)
  • field (field) --> object's attribute (attribute)

A general ORM framework maps each table of the database model to a Java class. That is to say, using MyBatis can operate data tables like operating objects, and can realize the conversion between objects and databases.

1) Add MyBatis framework support

Add MyBatis to old projects

References to both frameworks need to be added

  1. MyBatis framework
  2. MySQL driver

insert image description here

2) Configure MyBatis related configuration files

1. Configure data connection information

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/blog_system?characterEncoding=utf8&useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver #mysql 8.0之前的写法
    #driver-class-name=com.mysql.cj.jdbc.Driver 这是8.0之后的写法

2. MyBatis XML file location

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/blog_system?characterEncoding=utf8&useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver #mysql 8.0之前的写法
    #driver-class-name=com.mysql.cj.jdbc.Driver 这是8.0之后的写法
mybatis:
  mapper-locations: classpath:mapper/**Mapper.xml

The location of the xml file in the configuration file should correspond to the name of the created folder

insert image description here

3) Add code

UserInfo object

Note: The attribute name here should correspond to the field name in the database

import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class UserInfo {
    
    
    private int userId;
    private String username;
    private String password;
}

insert image description here

UserMapper.xmldocument

<?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.example.demo.mapper.UserMapper">
    <select id="getAll" resultType="com.example.demo.model.UserInfo">
        select * from user
    </select>
</mapper>

insert image description here

controller code

@Controller
@RequestMapping("/mybatis")
@ResponseBody
public class UserController2 {
    
    

    @Autowired
    private UserService userService;

    @RequestMapping("/getAll")
    public List<UserInfo> getAll() {
    
    
        return userService.getAll();
    }
}

Service code

@Service
public class UserService {
    
    
    @Resource
    private UserMapper userMapper;
    public List<UserInfo> getAll() {
    
    
        return userMapper.getAll();
    }
}

define interface code

@Mapper
public interface UserMapper {
    
    
    // 方法定义
    List<UserInfo> getAll();
}

Access via browser

insert image description here

4. Solve the inconsistency between the attribute name of the class and the field name of the data table (resultMap)

Entity class

@Getter
@Setter
public class UserInfo {
    
    
    private int id;
    private String name;
    private String password;
}

data sheet

+----------+-------------+------+-----+---------+----------------+
| Field    | Type        | Null | Key | Default | Extra          |
+----------+-------------+------+-----+---------+----------------+
| userId   | int(11)     | NO   | PRI | NULL    | auto_increment |
| username | varchar(64) | YES  | UNI | NULL    |                |
| password | varchar(32) | YES  |     | NULL    |                |
+----------+-------------+------+-----+---------+----------------+

MyBatis configuration file

<?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.example.demo.mapper.UserMapper">
    <resultMap id="UserBean" type="com.example.demo.model.UserInfo">
        <!-- 映射主键的(表中主键和程序实体类中的主键) -->
        <id column="userId" property="id"></id>
        <!-- 普通列的映射 -->
        <result column="username" property="name"></result>
        <result column="password" property="password"></result>
    </resultMap>
    <select id="getAll" resultMap="UserBean">
        select * from user
    </select>
</mapper>

insert image description here

To resultMapsolve the inconsistency between the attribute name of the class and the field name in the data table

  • idlabel represents the primary key
  • resultLabels represent common fields

MyBatis query return type settings

  1. resultType (return result type)
  2. resultMap (return map)

resultTypeVSresultMap

  • What they have in common: their functions are the same, and they are all used to specify the result type
  • difference:
    • resultTypeThe usage is simple, but if the attribute name in the entity class is inconsistent with the field name in the table, the result will not be queried
    • resultMapThe usage is relatively troublesome (resultMap interface has multiple columns), but it can realize the mapping that does not correspond to the attribute name and the field name of the data table, and can also query the result

5. Add operations

1) Return the number of affected rows

Controller (controller) code:

@Controller
@RequestMapping("/mybatis")
@ResponseBody
public class UserController2 {
    
    

    @Autowired
    private UserService userService;

    public Integer addUser(UserInfo userInfo) {
    
    
        // 校验参数
        if (userInfo == null || userInfo.getName() == null || "".equals(userInfo.getName())
        || userInfo.getPassword() == null || "".equals(userInfo.getPassword())) {
    
    
            return 0;
        }

        return userService.addUser(userInfo);
    }
}

Service (service layer code):

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

    public int addUser(UserInfo userInfo) {
    
    
        // 服务(方法编排)
        return userMapper.addUser(userInfo);
    }
}

Mapper interface code:

@Mapper
public interface UserMapper {
    
    
    int addUser(UserInfo userInfo);
}

Write the xml configuration file of MyBatis

<?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.example.demo.mapper.UserMapper">
    <!-- 添加方法 -->
    <insert id="addUser">
        insert into user(username,password) values(#{name},#{password})
    </insert>
</mapper>

Tested by postman

insert image description here

2) Return the self-incrementing id

Controller (controller) code:

@Controller
@RequestMapping("/mybatis")
@ResponseBody
public class UserController2 {
    
    
    @Autowired
    private UserService userService;

    @RequestMapping("/add2")
    public Integer addUser2(UserInfo userInfo) {
    
    
        // 校验参数
        if (userInfo == null || userInfo.getName() == null || "".equals(userInfo.getName())
                || userInfo.getPassword() == null || "".equals(userInfo.getPassword())) {
    
    
            return 0;
        }
        // 调用数据库执行添加操作,执行完添加之后会将自增id设置到userinfo的id属性
        userService.addUser2(userInfo);
        return userInfo.getId();
    }
}

Service (service layer code):

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

    public int addUser2(UserInfo userInfo) {
    
    
        // 服务(方法编排)
        return userMapper.addUser2(userInfo);
    }
}

Mapper interface:

@Mapper
public interface UserMapper {
    
    
    int addUser2(UserInfo userInfo);
}

Write the xml configuration file of MyBatis

<?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.example.demo.mapper.UserMapper">


    <!-- 添加方法(返回自增id) -->
    <insert id="addUser2" useGeneratedKeys="true" keyProperty="id" keyColumn="userId">
        insert into user(username, password) values(#{name},#{password})
    </insert>
</mapper>
  • useGeneratedKeys : This will make MyBatis use JDBC's getGeneratedKeys method to retrieve
    the primary key generated internally by the database (for example: auto-
    increment ), default value: false
  • keyColumn
    : Set the name of the column in the table that generates the key value. In some databases (like PostgreSQL), it must be set when the primary key column is not the first column in the table. If there is more than one generated column, multiple attribute
    names can be separated by commas
  • keyProperty : Specifies the property that can uniquely identify the object. MyBatis will use the return value of getGeneratedKeys
    or the selectKey subelement of the insert statement to set its value. Default value: unset (unset).
    If there is more than one generated column , multiple attribute names can be separated by commas

Postman test results

insert image description here

6. Modify operation

Controller (controller code)

@Controller
@RequestMapping("/mybatis")
@ResponseBody
public class UserController2 {
    
    

    @Autowired
    private UserService userService;
    /**
     * 修改密码操作
     * @param id
     * @param password
     * @return
     */
    @RequestMapping(value = "/update")
    public Integer updateUserInfo(Integer id, String password) {
    
    
        if(id == null || id < 0 || password == null || "".equals(password)) {
    
    
            return 0;
        }

        return userService.updateUserInfo(id,password);
    }
}

Service service layer code:

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

    public int updateUserInfo(Integer id, String password) {
    
    
        return userMapper.updateUserInfo(id,password);
    }
}

Mapper interface method definition

@Mapper
public interface UserMapper {
    
    
    int updateUserInfo(Integer id, String password);
}

MyBatis configuration file implements the interface

<?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.example.demo.mapper.UserMapper">

    <!-- 更新操作 -->
    <update id="updateUserInfo">
        update user set password=#{password} where userId=#{id}
    </update>
</mapper>

7. Delete operation

Controller controller code:

@Controller
@RequestMapping("/mybatis")
@ResponseBody
public class UserController2 {
    
    

    @Autowired
    private UserService userService;

    @RequestMapping("/delete")
    public Integer deleteUser(Integer id) {
    
    
        if (id == null || id < 0) {
    
    
            return 0;
        }
        return userService.deleteUser(id);
    }
}

Service service layer code

@Service
public class UserService {
    
    
    @Resource
    private UserMapper userMapper;
    public int deleteUser(int id) {
    
    
        return userMapper.deleteUser(id);
    }
}

Mapper interface method definition

@Mapper
public interface UserMapper {
    
    
    int deleteUser(int id);
}

MyBatisj configuration file interface implementation

<?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.example.demo.mapper.UserMapper">
    <!-- 删除操作 -->
    <delete id="deleteUser">
        delete from user where userId=#{id}
    </delete>
</mapper>

8. Two ways of parameter assignment

  • #{}: precompiled processing
  • ${}: character direct replacement

Precompilation processing means: MyBatis will replace the number #{}in the SQL with the number when processing , and use the set method of PreparedStatement to assign the value. Direct replacement: When MyBatis is processing , it is directly replaced with the value of the variable.#{}?${}${}

${}scenes to be used:

Suppose we want to sort users in descending order by id, and the variable order is passed asc or desc

@Mapper
public interface UserMapper {
    
    
    // 方法定义
    List<UserInfo> sortAllUser(String order);
}
<!-- ${}使用场景 -->
    <select id="sortAllUser" resultMap="UserBean">
        select * from user order by userId ${order}
    </select>

Assuming that desc is passed , if ${}it is used, ${order}it will be replaced directly desc, and the result will be returned in normal sorting. And if #{}it is used, it will be replaced with ‘desc’, 'desc'which is a string at this time, and an error will occur when executing SQL.

-- 使用${}
select * from user order by userId desc;
-- 使用#{}
select * from user order by userId 'desc';

But${} there is a problem of SQL injection

SQL injection problem

Suppose to do a simple login

Controller controller code

@Controller
@RequestMapping("/mybatis")
@ResponseBody
public class UserController2 {
    
    

    @Autowired
    private UserService userService;

    /**
     * 登录
     * @param username
     * @param password
     * @param request
     * @return
     */
    @RequestMapping("/login")
    public Object logIn(String username, String password, HttpServletRequest request) {
    
    
        Map<String,Object> result = new HashMap<>();
        result.put("status",200);// 响应状态码
        String message = null;
        int state = -1; // 登录状态码
        if (username != null && !"".equals(username) && password != null && !"".equals(password)) {
    
    
            UserInfo userInfo = userService.logIn(username,password);
            if (userInfo != null) {
    
    
                message = "登录成功";
                state = 1;
                // 把用户信息存储到session
                HttpSession session = request.getSession(true);
                session.setAttribute("userInfo",userInfo);
            } else {
    
    
                message = "用户名或密码错误";
            }
        } else {
    
    
            message = "用户名或密码错误";
        }
        result.put("message",message);
        result.put("state",state);

        return result;
    }
}

UserService service layer code

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

    public UserInfo logIn(String username, String password) {
    
    
        return userMapper.logIn(username,password);
    }
}

Mapper interface mapping

@Mapper
public interface UserMapper {
    
    
    // 方法定义
    List<UserInfo> getAll();
    UserInfo logIn(String username, String password);
}

The xml configuration file that implements the interface

 <!-- 登录用户查询 -->
    <select id="logIn" resultMap="UserBean">
        select * from user where username='${username}' and password='${password}'
    </select>

If you use ${}the method to directly replace the parameters, there will be a risk of SQL injection

Postman mock request

http://127.0.0.1:8080/mybatis/login?username=admin&password=' or userId='1''

insert image description here

No matter what password you enter, you can log in successfully. The final SQL executed is as follows. That is to say, you can log in without knowing the password through SQL injection, and even perform table deletion operations.

mysql> select * from user where username='admin' and password='' or userId='1';

If you ${}replace #{}the achievement, there will be no SQL injection problem

<select id="logIn" resultMap="UserBean">
        select * from user where username=#{username} and password=#{password}
    </select>

If it is used , it will replace the number #{}in SQL with the number, and use the set method of PreparedStatement to assign the value. Think of the whole as a string.#{}?

The SQL executed using the SQL injection just now will be as follows

mysql> select * from user where username="admin" and password="' or userId='1";

Therefore, ${}you must use it with caution. If you must use it, you must filter the front-end parameters for security .

Safe fuzzy query (like)

ike uses #{} to report an error

This is an example of an error

<!-- 过滤查询 -->
    <select id="getLike" resultMap="UserBean">
        select username from user where username like '#{keyName}%';
    </select>

The SQL equivalent to execute is

select username from user where username like '"张"%';

This is not possible to use ${} directly, you can consider using mysql's built-in function concat() to deal with, the implementation code is as follows:

<!-- 过滤查询 -->
    <select id="getLike" resultMap="UserBean">
        select username from user where username like concat(#{keyName},'%')
    </select>

Guess you like

Origin blog.csdn.net/weixin_53946852/article/details/130115364