table of Contents
Use XML files to configure SQL statements
Questions about multiple parameters
#{} and ${} placeholders in MyBatis
MyBatis
Use XML files to configure SQL statements
Download http://doc.canglaoshi.org/config/Mapper.xml.zip
and unzip to get SomeMapper.xml .
Create a mappers folder under the project's src/main/resources , copy SomeMapper.xml to this folder, and rename it to UserMapper.xml .
The name of the folder created in this step is customized and related to the subsequent configuration.
The name of the XML file in this step is customized and has nothing to do with any other configuration.
The UserMapper.xml added above is the file used to configure SQL statements, usually called the mapping file ! The following codes in this file are fixed and indispensable:
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
The root node of the file is a <mapper>
node, namespace
a property that must be configured , and the value of this property is the full name of the corresponding MyBatis interface file, for example:
< namespace="cn.tedu.mybatis.UserMapper">
</mapper>
Next, according to the type of the SQL statement to be executed, choosing <insert>
, <delete>
, <update>
, <select>
four nodes in a certain configuration to the SQL statement, the nodes must be configured with id
attribute, the attribute value is the name of an abstract method interface , And then, you can write SQL statements inside the node:
<?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">
<!-- namespace属性:接口的全名 -->
<mapper namespace="cn.tedu.mybatis.UserMapper">
<!-- id属性:抽象方法的名称 -->
<insert id="insert">
INSERT INTO t_user (
username, password, age, phone, email
) VALUES (
#{username}, #{password}, #{age}, #{phone}, #{email}
)
</insert>
</mapper>
At present, the MyBatis framework does not know that there is a mappers folder, let alone which file configures the SQL statement! The location of the XML file that configures the SQL statement can be configured in jdbc.properties :
mybatis.mapper-locations=classpath:mappers/*.xml
The above code is used to indicate that " all XML files in the mappers folder under src/main/resouces are used to configure SQL statements". In subsequent use, you must also ensure that you will not add other files to the mappers folder. The role of the XML file!
Next, you should also read the above configuration information:
@Value("${mybatis.mapper-locations}")
private Resource[] mapperLocations;
And applied to SqlSessionFactoryBean
the properties of the object:
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setMapperLocations(mapperLocations);
return bean;
}
Finally, before running or testing, you need to pay attention: each abstract method can only configure SQL statements in one way, either using annotations or using XML files, not at the same time! Otherwise, an error will be reported. The key information of the error prompt is for example:
Caused by: java.lang.IllegalArgumentException:
Mapped Statements collection already contains value for
cn.tedu.mybatis.UserMapper.insert. please check file
[D:\eclipse-workspace-202003\mybatis\target\classes\mappers\UserMapper.xml]
and cn/tedu/mybatis/UserMapper.java (best guess)
The above prompt Mapped Statements collection already contains value for cn.tedu.mybatis.UserMapper.insert.
means "the cn.tedu.mybatis.UserMapper.insert
method is mapped to the configuration of multiple SQL statements", and it is also recommended to check the UserMapper.xml and UserMapper.java files!
If you are configuring a <insert>
node, and you need to obtain the ID value of the automatic number, you <insert>
can continue to configure the attributes in the node, for example:
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
INSERT INTO t_user (
username, password, age, phone, email
) VALUES (
#{username}, #{password}, #{age}, #{phone}, #{email}
)
</insert>
When the data access that needs to be implemented is of the query type, one of the attributes (choose one) of or <select>
must be configured in the node . If none is specified, the following error will occur:resultType
resultMap
Caused by: org.apache.ibatis.executor.ExecutorException:
A query was run and no Result Maps were found for the Mapped Statement 'cn.tedu.mybatis.UserMapper.count'.
It's likely that neither a Result Type nor a Result Map was specified.
Among them, it resultType
refers to the "type of the data that encapsulates the query result", which can also be understood as the "type of the return value of the abstract method". For example, it can be configured as:
<select id="count" resultType="java.lang.Integer">
SELECT COUNT(*) FROM t_user
</select>
If the return value of an abstract method of a query is a List
collection type, for example:
List<User> findAll();
When configuring <select>
the resultType
attribute, the attribute value must be the type of the element in the collection, for example:
<select id="findAll" resultType="cn.tedu.mybatis.User">
SELECT * FROM t_user ORDER BY id
</select>
As for the resultMap
attributes, they will be introduced later.
Note: After using this approach, you need to add a requirement "overloading is not allowed" to the definition of the abstract method name!
Questions about multiple parameters
When there is more than one parameter in the parameter list of the abstract method, the #{参数名称}
parameter value cannot be accessed by using it directly when configuring the SQL statement !
Because the Java source file needs to be compiled into a bytecode file ( .class file ) before running , it will lose all partial names when compiling. Therefore, it will cause the problem that the original "parameter name" cannot be used at runtime. !
MyBatis allows you to use arg
as a prefix and add 0
a name from the beginning (for example arg0
,arg1
etc.) to indicate the name of the first parameter. Later, when configuring SQL statements, you can use, for example, #{arg0}
to indicate the value of the first parameter of the abstract method. Use #{arg1}
the value of the second parameter of the abstract method...and so on! In addition, you can also use param
as a prefix and add 1
a name from the beginning (for example param1
,param2
etc.). In specific use, arg
the name of the param
series and the name of the series can be used!
However, it is not convenient to use the names of the arg
and param
series to express the semantics, and when the parameter list of the abstract method changes, the serial numbers in these names may also need to be adjusted!
@Param
annotation
If the annotation is @Param("person"), then the parameter will be named #{person} .
MyBatis provides @Param
annotations . This annotation is added before each parameter of the abstract method. You can specify the name in the annotation. Later, when configuring the SQL statement, the placeholder uses the name configured in the annotation!
When the @Param annotation is not used, the function parameter can only be one, and only #{} can be used in the query statement value , and the class to which it belongs must be Javabean,
While using @Param annotation, you can use multiple parameters, and you can use #{} or ${} when you use it in a query statement
For example, the code here @Param
After using @Param, the order of parameters in the interface can also be disrupted, as long as the id is unique.
This annotation can be omitted when there is only one parameter
/**
* 根据用户的id 修改用户的邮箱
* UPDATE t_user set email=#{email} WHERE id=#{id};
*/
//编译时-->局部变量的参数会丢失
//@Update("UPDATE t_user SET email=#{arg0} WHERE id=#{arg0}")
//@Update("UPDATE t_user SET email=#{param1} WHERE id=#{param2}")
//Integer updateEmailById(String email,Integer id);
//Integer updateEmailById(String arg0,Integer arg1);
//Integer updateEmailById(String param1,Integer param2);
@Update("UPDATE t_user SET email=#{email} WHERE id=#{id}")
Integer updateEmailById(@Param("email") String email, @Param("id")Integer id);
Dynamic SQL - foreach
Suppose there is a demand: delete user data in batches (delete several pieces of user data at once);
The SQL statement that needs to be executed is roughly:
DELETE FROM t_user WHERE id=? OR id=? OR id=?;
DELETE FROM t_user WHERE id IN (?,?,?);
Value! Only the data type and meaning of the above parameters can be determined!
The above functions will ultimately be up to the user (the user of the software) to determine the number of data to be deleted (the number of question marks), and which pieces of data are to be deleted (parameter values corresponding to the question marks)! It will lead to "when the user's operations are different (the selected data to be deleted is different), the final SQL statement that needs to be executed is different"! The MyBatis framework provides a "dynamic SQL" mechanism to solve this problem!
Dynamic SQL : According to the different parameter values provided by the user, the final SQL statement that needs to be executed can be different!
When it is necessary to achieve the above requirements for batch deletion, the abstract method can be designed as:
Integer deleteByIds(List<Integer> ids);
Or, it can be designed as (this case uses this)
Integer deleteByIds(Integer[] ids);
It can even be designed as:
Integer deleteByIds(Integer... ids);
When a variable parameter is processed, it is essentially data.
When configuring the SQL statement, you need <foreach>
to configure the part of the SQL statement that needs to be generated through a loop through the node:
<delete id="deleteByIds">
DELETE FROM t_user WHERE id IN (
<foreach collection="array" item="id" separator=",">
#{id}
</foreach>
)
</delete>
About <foreach>
node configuration:
collection
:
Objects that need to be traversed, when the abstract method has only one parameter and no @Param
annotations are added , if the parameter type is a List
collection, the value is taken list
; if the parameter type is an array , the value is taken array
; when the abstract method has more than one parameter , An @Param
annotation must be added , and the value is @Param
the parameter value of the annotation configuration;
item
:
For each element data in the traversal process, the current attribute can be a custom value to represent the name of the element data. When <foreach>
using a #{}
placeholder at the child level of a node , you can use this name to represent the data;
separator
:
Traverse the generated code fragments, the separator between each element data;
Exercise: Set the password of several users to a certain value according to their ids.
The SQL statement that needs to be executed is roughly:
UPDATE t_user SET password=? WHERE id IN (?,?,?)
The abstract method can be designed as:
Integer updatePasswordByIds(
@Param("ids") List<Integer> ids,
@Param("password") String password
);
Then, configure the SQL statement (configuration mapping):
<update id="updatePasswordByIds">
UPDATE t_user SET password=#{password} WHERE id IN (
<foreach collection="ids" item="id" separator=",">
#{id}
</foreach>
)
</update>
Dynamic SQL - if
When configuring SQL statements, you can add <if>
nodes to determine parameter values, so as to determine whether a certain SQL statement fragment is included in the final executed SQL statement.
For example, there is:
List<User> find(
@Param("where") String where,
@Param("orderBy") String orderBy,
@Param("offset") Integer offset,
@Param("count") Integer count
);
It can be configured as:
<select id="find" resultType="cn.tedu.mybatis.User">
SELECT * FROM t_user
<if test="where != null">
WHERE ${where}
</if>
<if test="orderBy != null">
ORDER BY ${orderBy}
</if>
<if test="offset != null and count != null">
LIMIT #{offset}, #{count}
</if>
</select>
Note: The above case is just a hypothetical code. In actual development, you must not use it like this!
Note: In dynamic SQL, the <if>
node does not have a matching else
part! If you must need to achieve if...else
the grammatical effect, you can write two <if>
nodes with completely opposite conditions , or you can configure through the <choose>
,, <when>
and <otherwise>
nodes. The basic format is:
<choose>
<when test="">
满足条件时的SQL语句片段
</when>
<otherwise>
不满足条件时的SQL语句片段
</otherwise>
</choose>
#{} and ${} placeholders in MyBatis
MyBatis allows SQL statements used in configuring #{}
and ${}
placeholders these two formats is represented by a parameter value.
Simple principle :
In the original programming using JDBC technology, when writing SQL statements, you can write the position of the question mark ( ?
) , all use the #{ }
format placeholder, and you cannot write the position of the question mark, you must use the ${ }
format placeholder!
Use #{}
formatted placeholders to only represent a certain value! When MyBatis is processed, it will be processed by pre-compilation, that is: first use the question mark to place the value represented by the placeholder, and submit the entire SQL statement to MySQL for compilation-related processing (including lexical analysis, semantic analysis) , Compile), when the compilation is completed, the value is substituted into the successfully compiled SQL statement and executed together. Simply put, when using #{}
format placeholders, the final processing mechanism is precompiled! Therefore, when using this format of placeholders, you do not need to care about the data type of the value when writing SQL , and there is no risk of SQL injection !
Using ${}
format placeholders, you can represent any fragment in the SQL statement! When MyBatis is processing, it will first splice${}
the value corresponding to the format placeholder into the SQL statement, and then submit the SQL statement to MySQL for compilation-related processing, that is to say, the value of the format placeholder has been substituted before compilation In the SQL statement! Obviously, there is no (and it is impossible) to use precompilation when dealing with format placeholders! Therefore, when using this format of placeholders, you need to consider the data type in the SQL statement yourself . For example, the value of the string type needs to be enclosed in a pair of single quotes! In addition, there is the risk of SQL injection !${}
${}
the difference:
- In sql, when the incoming parameter is a character type, the # sign will be enclosed in single quotation marks, which will not cause sql injection
- In sql, when the incoming parameter is a character type, the $ sign will not be enclosed with single quotation marks, which will cause sql injection
<select id="find" resultType="cn.tedu.mybatis.User">
SELECT * FROM t_user
<if test="where !=null">
WHERE ${where}
</if>
<if test="orderBy != null">
ORDER BY ${orderBy}
</if>
<if test="offset != null and count != null">
LIMIT #{offset}, #{count}
</if>
</select>