一、标签内容
功能 | 标签名称 | |
定义sql | select | |
insert | ||
delete | ||
update | ||
动态sql | if | |
连用标签 | choose | |
when | ||
otherwise | ||
trim | ||
where | ||
set | ||
foreach | ||
定义常量 | sql | |
表信息定义 | resultMap |
Mybatis中mapper.xml
注意事项:sql结尾不用加;号
<?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.wounler.dao.UserInfoMapper">
<!-- 表定义信息 -->
<resultMap id="BaseResultMap" type="com.wounler.pojo.UserInfo">
<id column="user_id" jdbcType="VARCHAR" property="userId"/>
<result column="user_name" jdbcType="VARCHAR" property="userName"/>
<result column="sex" jdbcType="VARCHAR" property="sex"/>
<result column="age" jdbcType="NUMERIC" property="age"/>
<result column="create_date" jdbcType="DATE" property="createDate"/>
</resultMap>
<!-- 定义常量 -->
<sql id="Base_Column_List">
USER_ID,USER_NAME,SEX,AGE,CREATE_DATE
</sql>
<sql id="userInfoMap">
<where>
<if test="userId != null and userId != ''">
user_id = #{userId}
</if>
<if test="userId != null and userId != ''">
and user_name = #{userName}
</if>
</where>
</sql>
<!--select标签查看所有数据-->
<select id="getUserList" resultMap="BaseResultMap">
select * from user_info
</select>
<!--select标签查看指定条件的数据-->
<select id="userList" parameterType="com.wounler.pojo.UserInfo" resultMap="BaseResultMap">
select
<include refid="Base_Column_List"/>
from user_info where user_name = #{userName}
</select>
<!--update标签更新指定条件的数据-->
<update id="updateUserInfo" parameterType="java.util.Map">
update user_info set user_name = #{userName},age = #{age} where user_id=#{userId}
</update>
<!--update标签和set标签where标签的连用-->
<!--where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
但是第一个判断我们明知道时第一个数据,前面就不用加“AND” 或 “OR”-->
<!--set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)
但是最后一个判断我们明知道时最后一个数据,后面就不用加逗号了-->
<update id="updateUserInfoByTag" parameterType="java.util.Map">
update user_info
<set>
<if test="sex != null and sex != ''">
user_name = #{sex,jdbcType=VARCHAR},
</if>
<if test="age!= null and age!= ''">
age = #{age,jdbcType=NUMERIC}
</if>
</set>
<where>
<if test="userId!= null and userId!= ''">
user_id <![CDATA[<>]]> #{userId,jdbcType=VARCHAR}
</if>
<if test="userName != null and userName != ''">
and user_name = #{userName,jdbcType=VARCHAR}
</if>
</where>
<!--此处where也可以用 <include refid="userInfoMap"/> -->
</update>
</mapper>
二、标签解读
select 标签的使用 | |
属性 | 描述 |
id | 在空间命名中唯一的标识符,可以被用来引用这条语句。如:id=”key” |
parameterType | 将要传入这条语句的参数类的完全限定名或别名 例:com.test.poso.User或user。这个属性是可选的,因为mybatis可以通过TypeHandler推断出具体传入语句的参数,默认值是unset(“未设置”或者解释成“依赖驱动”)。如:parameterType=”java.lang.String” |
resultType | 语句返回值类型或别名。注意,如果是集合,那么这里填写的是集合的泛型,而不是集合本身(resultType 与resultMap 不能并用)。如resultType=”java.lang.String” |
resultMap | 外部resultMap的命名引用。如:resultMap=”BaseResultMap” |
Insert、update、delete 标签的使用 | |
属性 | 描述 |
id | 在空间命名中唯一的标识符,可以被用来引用这条语句。如:id=”key” |
parameterType | 将要传入这条语句的参数类的完全限定名或别名 例:com.test.poso.User或user。这个属性是可选的,因为mybatis可以通过TypeHandler推断出具体传入语句的参数,默认值是unset(“未设置”或者解释成“依赖驱动”)。如:parameterType=”java.lang.String” |
keyProperty | 仅对insert和update有用,唯一标记一个属性,mybatis会通过getGeneratedKeys的返回值或者通过insert语句的select Key子元素设置它的键值,默认为unset。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表 |
foreach 标签的使用 | |
属性 | 描述 |
item | 表示本次迭代获取的元素,若collection为List、Set或者数组,则表示其中的元素;若collection为map,则代表key-value的value,该参数为必选。item 的值是本次迭代获取到的元素,需要与#{}中的字符保持一致 |
open | 表示该语句以什么开始,最常用的是左括弧’(’,注意:mybatis会将该字符拼接到整体的sql语句之前,并且只拼接一次,该参数为可选项 |
close | 表示该语句以什么结束,最常用的是右括弧’)’,注意:mybatis会将该字符拼接到整体的sql语句之后,该参数为可选项 |
separator | mybatis会在每次迭代后给sql语句append上separator属性指定的字符,该参数为可选项。设置foreach生成的多条记录之间的分割符,可以根据自己的需要设置,比如“,”,"and"之类的 |
index | 在list、Set和数组中,index表示当前迭代的位置,在map中,index代指是元素的key,该参数是可选项。索引(index)代表变量,index 是当前迭代的序号 |
collection | 请看下面有关collection的描述 |
三、实例讲解
1、#{}和${}区别
1)、#和$两者含义不同
#{} 占位符、${} 拼接符
#会把传入的数据都当成一个字符串来处理,会在传入的数据上面加上双引号,变量替换后,#{} 对应的变量自动加上单引号#{} 能防止sql 注入
而$则是把传入的数据直接显示在sql语句中,不会添加双引号。变量替换后,${} 对应的变量不会加上单引号${} 不能防止sql 注入
2)、举例说明
其中如果传入的username类型为字符型,比如输入zhangsan,那么username=#{username}#表示的就是username=”zhangsan”,如果传入的username类型为数值类型,比如输入11,那么username=#{username}#表示的就是username=”11”。
其中如果传入的username类型为整型类型,那么在执行sql语句时就不会出错,但是如果传入的username类型为字符串型,比如输入zhangsan,那么username=${username}就会变成username=zhangsan,执行会报错,所以sql语句必须写成下面这样。
#{} 和 ${} 的实例:假设传入参数为 1
(1)开始
1)#{}:select * from t_user where uid=#{uid}
2)${}:select * from t_user where uid= '${uid}'
(2)然后
1)#{}:select * from t_user where uid= ?
2)${}:select * from t_user where uid= '1'
(3)最后
1)#{}:select * from t_user where uid= '1'
2)${}:select * from t_user where uid= '1'
3)、#{} 和 ${} 在使用中的技巧和建议
(1)不论是单个参数,还是多个参数,一律都建议使用注解@Param("")
(2)能用 #{} 的地方就用 #{},不用或少用 ${}
(3)表名作参数时,必须用 ${}。如:select * from ${tableName}
(4)order by 时,必须用 ${}。如:select * from t_user order by ${columnName}
(5)使用 ${} 时,要注意何时加或不加单引号,即 ${} 和 '${}'
2、foreach 也就是遍历迭代,在SQL中通常用在 in 这个关键词的后面
foreach元素的属性主要有 item,index,collection,open,separator,close。
分别代表:
item表示集合中每一个元素进行迭代时的别名,要和#{}中的名字保持一致
index用于表示在迭代过程中,每次迭代到的位置,
open表示该语句以什么开始,
separator表示在每次进行迭代之间以什么符号作为分隔符,
close表示以什么结束
关于collection属性
首先需要知道mybatis怎么处理参数的,传递给XXXMapper接口方法的所有参数会被放到一个map中(后面叫这个map为M),假设存在参数properties:
- 传递List类型的参数,则会在M里有一条 {"list" : properties },所以此时collection设置为“list”就等于拿出M中key="list"的value,然后遍历它。
- 传递数组类型参数, 则会在M里有一条{"array", properties},所以此时需要设置collection="array".
- 传递Map类型的参数, 不会做任何转换,假设你的Map类型的参数中包含的是{"china" :"beijing", "usa":"w.d.c"}, 那么M中就有两条映射:{"china" :"beijing", "usa":"w.d.c"} 。
- 如果传入的是一个bean,那么的bean中的属性作为key,属性值作为value放到M中。
- 如果传入的是一个基本类型变量,那么M中就会存在一条key是变量名,value是变量值(由于jdk7之前反射无法拿到参数名,可以使用下面介绍的注解)。
综上,collection能够指定的值就是M中最终存在的key,<foreach>标签从M中拿到key的value,然后遍历value,所以这个value必须是能够被遍历的对象。
以上都是假设你没有在Mapper的接口方法上使用mybatis提供的注解org.apache.ibatis.annotations.Param
注解参数名时collection的默认值,如果你在参数上使用了这个注解,那么最终M中的key是注解名,value是参数值,如下:
public interface PersonMapper {
void insertPerson1(@Param("map") Map<String, Person> persons);
}
使用注解时M中就存在一条"map" -> persons的映射,而不是上面介绍的把persons的key,value直接方到M中
那么可以在PersonMapper.xml中:
<insert id="insertPerson1">
INSERT INTO mybatis.person VALUES
<foreach collection="map" index="key" item="person" separator=",">
(#{person.name}, #{person.age})
</foreach>
</insert>
这里collection="map", 相当于拿到M.get("map")的值,也就是persons,
然后遍历persons, 遍历的结果是index是persons的key, item是对应的value
而最为重要的就是collection属性了,既然是迭代就表示传入的参数是多个,这时候传入的参数就有以下几种可能:
1. 传入的参数为list(set的话,替换掉list就行了)的时候
<!-- 对应的Dao中的Mapper文件是: -->
public List<User> selectByIds(List<Integer> ids);
<!-- 如果Mapper文件参数中增加@Param(vale="ages") ,则下面需要这样写collection="ages"-->
<!-- xml文件代码片段: -->
<select id="selectByIds" resultType="com.wounler.pojo.User">
select * from user where id in
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
假设接口中传递的list如下所示:
List<String> list = new ArrayList<>();
list.add("zhangsan");
list.add("lisi");
list.add("wangwu");
可以看到的是foreach标签指定了逗号作为分隔符,那么mybatis将会解析出foreach标签里面的内容作为一个整体然后再其后面拼接上逗号分隔符,拼接后的过程如下所示:
( //第一步,拼接open指定的开始字符
('zhangsan' //第二步,迭代集合,拼接对应的item
('zhangsan', //第三步,拼接separator指定的分隔符
('zhangsan','lisi' //第四步,迭代集合,拼接对应的item
('zhangsan','lisi', //第五步,拼接separator指定的分隔符
('zhangsan','lisi','wangwu' //第六步,迭代集合,拼接对应的item
('zhangsan','lisi','wangwu') //第七步,拼接close指定的闭合字符
最终结果是:
('zhangsan','lisi','wangwu')
如果在foreach标签前面加上select … from table where … in ,将会变形成
SELECT * FROM user WHERE user_name in ('zhangsan','lisi','wangwu')
2. 传入的参数为Array的时候
<!-- 对应的Dao中的Mapper文件是: -->
public List<User> selectByIds(int[] ids);
<!-- 如果Mapper文件参数中增加@Param(vale="ages") ,则下面需要这样写collection="ages"-->
<!-- xml文件代码片段: -->
<select id="selectByIds" resultType="com.wounler.pojo.User">
select * from user where id in
<foreach collection="array" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
3. 传入的参数为Map的时候
map的时候需要注意的是:collection的值“ids”是存储在map中的key(比如:map.put("ids",ids));尤其需要注意;
<!-- 对应的Dao中的Mapper文件是: -->
<!-- params.add("ids",list) -->
public List<User> selectByIds(Map<String, Object> params);
<!-- xml文件代码片段: -->
<select id="selectByIds" resultType="com.wounler.pojo.User">
select * from user where id in
<foreach collection="ids" index="index" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
四、注意事项
1、split方法:colleation=”prodNum.split(‘,’)”
2、<sql id=”Base_Column_LIst”></sql> <include refid=”Base_Column_LIst”/>需要结合使用
3、以下标签需要结合使用<choose><when></when><otherwise></otherwise></choose>
4、对象.属性的形式:If(test=”person.name != null and person.name != ‘’”)
5、size方法:list.size > 0
6、toString方法,判断条件为等于的时候,常量需要加 .toString() 来转换,这种方法是稳定的,推荐使用:age == '0'.toString()
7、不等于号:!=、<![CDATA[<>]]>
术语 CDATA 指的是不应由 XML 解析器进行解析的文本数据(Unparsed Character Data)。
在 XML 元素中,"<" 、">" 和 "&" 是非法的。
"<" 会产生错误,因为解析器会把该字符解释为新元素的开始。">",解析器会把该字符解释为新元素的结束
"&" 也会产生错误,因为解析器会把该字符解释为字符实体的开始。
<![CDATA[ ]]> 是什么,这是XML语法。在CDATA内部的所有内容都会被解析器忽略。
因此"<"、“>”、“<>”,需要用<![CDATA[<]]>、<![CDATA[>]]>、<![CDATA[<=]]>、<![CDATA[>=]]>、<![CDATA[<>]]>
8、括号的运用:test="(grtrList != null and grtrList.size > 0) or (grteList != null and grteList.size > 0)"