How to Determine the Type of Mybatis Parameter Transmission

  • 2021-12-04 18:34:59
  • OfStack

Directory I. Environment configuration 1. Project configuration
2. Database tables
II. Determination of parameter transmission types 1. The parameter type is shaping
2. Specify jdbcType
3. The type of transmission is String
4. TypeHandler implements parameter replacement and forces quotation marks
5. Summary

Recently, when discussing the difference between # {} and ${}, some friends mentioned that # {} is replaced by string. As far as I personally understand, its main function is to occupy space, and the final replacement result is not necessarily string mode. For example, when our parameter transmission type is shaping, the final spliced sql should also be shaping, not string mode

Next, let's look at how different parameter types in the mapper interface are replaced in the final splicing sql

I. Environment Configuration

We use SpringBoot + Mybatis + MySql to build the instance demo

springboot: 2.2.0.RELEASE
mysql: 5.7.22

1. Project configuration


<dependencies>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.2.0</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
</dependencies>

The core depends on mybatis-spring-boot-starter. For version selection, go to the mvn repository and find the latest
The other one that is not available is db configuration information, appliaction. yml


spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/story?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password:

2. Database tables

Database for testing


CREATE TABLE `money` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL DEFAULT '' COMMENT ' User name ',
  `money` int(26) NOT NULL DEFAULT '0' COMMENT ' Money ',
  `is_deleted` tinyint(1) NOT NULL DEFAULT '0',
  `create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT ' Creation time ',
  `update_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT ' Update time ',
  PRIMARY KEY (`id`),
  KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=551 DEFAULT CHARSET=utf8mb4;

Test data, mainly the name field, is a string with a value of 1 number


INSERT INTO `money` (`id`, `name`, `money`, `is_deleted`, `create_at`, `update_at`)
VALUES
 (120, '120', 200, 0, '2021-05-24 20:04:39', '2021-09-27 19:21:40');

II. Determination of parameter transmission types

This article ignores the details of po, mapper interface and xml file in mybatis. Interested partners can directly view the bottom source code (or view the previous blog post)

1. The parameter type is shaping

For the above case, define an interface to query data according to name, but this name parameter type is integer
mapper interface:


/**
 * int Type, final sql The parameter in is also replaced by the parameter in int
 * @param name
 * @return
 */
List<MoneyPo> queryByName(@Param("name") Integer name);

The corresponding xml file is as follows


<select id="queryByName" resultMap="BaseResultMap">
    select * from money where `name` = #{name}
</select>

The above writing is very common. Our question now is, if the parameters are integers, will the final sql be name = 120 or name = '120'?
So how do you determine what the resulting sql looks like? This paper introduces a way to directly output mysql to execute sql log
Open the sql execution log by executing the following two commands on the mysql server


set global general_log = "ON";
show variables like 'general_log%';

When we access the above interface, we will find that the sql statement finally sent to mysql is still an integer after parameter replacement


select * from money where `name` = 120

2. Specify jdbcType

When you use # {}, ${}, you sometimes see that jdbcType is specified in addition to parameters, so will specifying this in xml affect the final sql generation?


<select id="queryByNameV2" resultMap="BaseResultMap">
    select * from money where `name` = #{name, jdbcType=VARCHAR} and 0=0
</select>

The generated sql is as follows


select * from money where `name` = 120 and 0=0

From the actual sql, this jdbcType does not affect the final sql parameter splicing, so what is it mainly used for? (This applies primarily to exceptions that may occur when an null is passed in.)

3. The type of transmission is String

When we pass the parameter type string, the final sql reasoning should be enclosed in quotation marks


spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/story?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password:
0

Corresponding xml


spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/story?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password:
1

The final sql generated above is as follows
select * from money where `name` = '120' and 1=1

4. TypeHandler implements parameter substitution and forces quotation marks

After reading the above sections, you can basically get a simple inference (of course, it needs to be analyzed from the source code)

sql parameter replacement is not simply replaced by string, but actually determined by the parameter type of java. If the parameter type of java is string, the spliced sql is string format; The pass parameter is an integer, and the spliced sql is also an integer

Then the question comes, why do you want to know this?

The key point lies in the problem of index failure

For example, an index is added to name in this example. When our sql is select * from money where name = 120, the index cannot be walked. If you want to walk the index, the passed parameters must be strings, and implicit type conversion cannot occur

Based on this, we have an application scenario. In order to avoid the inability to walk the index due to the problem of parameter transmission type, we hope that the parameter transmission of name, no matter what the actual parameter type is, the final spliced sql is in the format of string;

We implement this scenario with the help of a custom TypeHandler


spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/story?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password:
2

Then in xml, specify TypeHandler


/**
 *  Through the custom  TypeHandler  To realize  java <-> jdbc  Type, so that the real-time incoming is int/long , will also turn into String
 * @param name
 * @return
 */
List<MoneyPo> queryByNameV4(@Param("name") Integer name);

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/story?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password:
4

The sql output by the above writing method will carry a single quotation mark, which can solve the problem that the parameter type is wrong from the source and the index cannot be walked finally


spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/story?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password:
5

5. Summary

This paper uses a simple example to test the effect of different parameter types on the final sql generation in Mapper interface

When the parameter type is an integer, the final sql parameter replacement is also an integer (# {} is not a simple string replacement)
When the parameter type is a string, the final sql parameter replacement will automatically carry '' (${} Note that it will not be automatically enclosed with single quotation marks, so you need to add it manually)

When we hope that the final sql is a string replacement regardless of the type of reference, we can use the custom TypeHandler to realize it, which can avoid the index problem caused by implicit type conversion from the source
Finally, the question comes. Is the above conclusion reliable? Where is the final sql in mybatis spliced? What is the process of sql splicing?
About the whole process of sql splicing, the follow-up blog post will be launched soon. I am 1 gray. I will help you to praise, collect the price and give an evaluation


Related articles: