参数处理、查询返回与动态 SQL
# 1. Mybatis 参数处理
这里讲的参数是指的 Mapper 接口中 int insertCar(Car car);
的 car
这样的参数。
# 1.1 单个简单类型参数
简单类型包括:
- byte short int long float double char
- Byte Short Integer Long Float Double Character
- String
- java.util.Date
- java.sql.Date
Mapper 接口方法:
List<Student> selectByName(String name);
xml 中:
<select id="selectByName" resultType="Student">
select * from t_student where name = #{name}
</select>
2
3
# 1.2 Map 参数
手动封装 Map 集合,将每个条件以 KV 的形式存放到 map 中。然后在使用的时候通过 #{map 中的key}
来取值。
Mapper 接口方法:
List<Student> selectByParamMap(Map<String,Object> paramMap);
xml 中:
<select id="selectByParamMap" resultType="Student">
select * from t_student where name = #{nameKey} and age = #{ageKey}
</select>
2
3
# 1.3 实体类参数
#{}
里面写的是属性名字。这个属性名其本质上是:set/get 方法名去掉 set/get 之后的名字。
Mapper 接口方法:
int insert(Student student);
xml 中:
<insert id="insert">
insert into t_student values(null,#{name},#{age},#{height},#{birth},#{sex})
</insert>
2
3
# 1.4 多参数
假如有下面这个 Mapper 方法:
List<Student> selectByNameAndSex(String name, Character sex);
面对这种多参数的确情况,MyBatis 会自动创建一个 Map 集合,并且 Map 集合是以这样的方式来存储参数的:
map.put("arg0", name);
map.put("arg1", sex);
map.put("param1", name);
map.put("param2", sex);
2
3
4
所以 xml 文件可以这样写:
<select id="selectByNameAndSex" resultType="student">
select * from t_student where name = #{arg0} and sex = #{arg1}
</select>
2
3
# 1.5 @Param 注解 —— 命名注解
刚刚 MyBatis 自动创建的 map 的 key 是 arg0、arg1 这样的名字,可读性较差,那我们可以自定义 key 吗?
当然可以!使用 @Param
注解即可。@Param(...)
可以指定 map 集合的 key。
Mapper 接口方法:
List<Student> selectByNameAndAge(@Param("name") String name, @Param("age") int age);
xml 文件:
<select id="selectByNameAndAge" resultType="student">
select * from t_student where name = #{name} and age = #{age}
</select>
2
3
# 2. MyBatis 查询语句专题
# 2.1 返回一个实体类
当查询的结果有对应的实体类,并且查询结果只有一条时。
Mapper 方法如下:
Car selectById(Long id);
xml 文件:
<select id="selectById" resultType="Car">
select id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType from t_car where id = #{id}
</select>
2
3
# 2.2 返回实体类列表
Mapper 方法:
List<Car> selectAll();
xml 文件:
<select id="selectAll" resultType="Car">
select id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType from t_car
</select>
2
3
# 2.3 返回 Map
当返回的数据,没有合适的实体类对应的话,可以采用 Map 集合接收。字段名做 key,字段值做 value。
查询如果可以保证只有一条数据,则返回一个 Map 集合即可。
Map<String, Object> selectById(Long id);
<select id="selectById" resultType="map">
select id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType from t_car where id = #{id}
</select>
2
3
写 resultMap="map"
,这是因为 MyBatis 内置了很多别名。【参见mybatis开发手册】
当然,如果返回多个记录,可以使用 List<Map>
来接收。
# 2.4 返回 Map<String, Map>
比如我们想 selectAll()
的返回结果是一个 map,其中 key 为 car id,value 是 car 对象信息,那么我们可以用 Map<String, Map>
来接收,内层的 map 代表一个 car 对象的信息。
@MapKey("id")
Map<Long,Map<String,Object>> selectAll();
2
<select id="selectAllRetMap" resultType="map">
select id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType from t_car
</select>
2
3
# 2.5 resultMap 结果映射
查询结果的列名和 Java 对象的属性名对应不上怎么办(比如 car_type 与 carType)?解决方法有三种:
- 方法 1:使用 AS 关键字给 column 起别名
- 方法 2:使用 resultMap 进行结果映射
- 方法 3:开启驼峰命名自动映射(配置 settings)
# 2.5.1 使用 resultMap 进行结果映射
List<Car> selectAll();
<!--
resultMap:
id:这个结果映射的标识,作为select标签的resultMap属性的值。
type:结果集要映射的类。可以使用别名。
-->
<resultMap id="carResultMap" type="Car">
<!--对象的唯一标识,官方解释是:为了提高mybatis的性能。建议写上。-->
<id property="id" column="id"/>
<result property="carNum" column="car_num"/>
<!--当属性名和数据库列名一致时,可以省略。但建议都写上。-->
<!--javaType用来指定属性类型。jdbcType用来指定列类型。一般可以省略。-->
<result property="brand" column="brand" javaType="string" jdbcType="VARCHAR"/>
<result property="guidePrice" column="guide_price"/>
<result property="produceTime" column="produce_time"/>
<result property="carType" column="car_type"/>
</resultMap>
<!--resultMap属性的值必须和resultMap标签中id属性值一致。-->
<select id="selectAll" resultMap="carResultMap">
select * from t_car
</select>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2.5.2 开启驼峰命名自动映射
使用这种方式的前提是:属性名遵循 Java 的命名规范,数据库表的列名遵循 SQL 的命名规范。
- Java 命名规范:首字母小写,后面每个单词首字母大写,遵循驼峰命名方式。
- SQL 命名规范:全部小写,单词之间采用下划线分割。
启用该配置的方式是在 mybatis-config.xml 文件中:
<!--放在properties标签后面-->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
2
3
4
# 2.5.3 返回总记录条数
Mapper 接口:
Long selectTotal();
xml 文件:
<!--long是别名,可参考mybatis开发手册。-->
<select id="selectTotal" resultType="long">
select count(*) from t_car
</select>
2
3
4
- 这里 resultType 的 long 也是别名
# 3. 动态 SQL
动态 SQL 的场景:多条件查询等。
# 3.1 if 标签
需求:多条件查询
Mapper 接口:
List<Car> selectByMultiCondition(@Param("brand") String brand, @Param("guidePrice") Double guidePrice, @Param("carType") String carType);
xml 文件:
<select id="selectByMultiCondition" resultType="car">
select * from t_car where
<if test="brand != null and brand != ''">
brand like #{brand}"%"
</if>
<if test="guidePrice != null and guidePrice != ''">
and guide_price >= #{guidePrice}
</if>
<if test="carType != null and carType != ''">
and car_type = #{carType}
</if>
</select>
2
3
4
5
6
7
8
9
10
11
12
但如果第一个条件为空,其余两个不为空,那么拼接生成的 SQL 多出一个 and,解决办法就是下面要说的 where 标签。
# 3.2 where 标签
where 标签的作用:让 WHERE 子句更加动态智能。
- 当所有条件为空时,where 标签保证不会生成 WHERE 子句。
- 自动去除某些条件前面多余的 AND 或者 OR。
使用 where 标签后,上面的 xml 示例可以改成:
<select id="selectByMultiCondition" resultType="car">
select * from t_car
<where>
<if test="brand != null and brand != ''">
brand like #{brand}"%"
</if>
<if test="guidePrice != null and guidePrice != ''">
and guide_price >= #{guidePrice}
</if>
<if test="carType != null and carType != ''">
and car_type = #{carType}
</if>
</select>
2
3
4
5
6
7
8
9
10
11
12
13
如果你的写法是每个 if 标签里把 and 或 or 写在后面,那 where 标签无法自动去掉最后多余的 and/or
# 3.3 trim 标签
trim 标签的属性:
- prefix:在 trim 标签中的语句前添加内容
- suffix:在 trim 标签中的语句后添加内容
- prefixOverrides:前缀覆盖掉(去掉)
- suffixOverrides:后缀覆盖掉(去掉)
Mapper 接口:
List<Car> selectByMultiConditionWithTrim(@Param("brand") String brand, @Param("guidePrice") Double guidePrice, @Param("carType");
xml 文件:
<select id="selectByMultiConditionWithTrim" resultType="car">
select * from t_car
<trim prefix="where" suffixOverrides="and|or">
<if test="brand != null and brand != ''">
brand like #{brand}"%" and
</if>
<if test="guidePrice != null and guidePrice != ''">
guide_price >= #{guidePrice} and
</if>
<if test="carType != null and carType != ''">
car_type = #{carType}
</if>
</trim>
</select>
2
3
4
5
6
7
8
9
10
11
12
13
14
# 3.4 set 标签
主要用在 UPDATE 语句中,用来生成 set 关键字,同时去掉最后多余的逗号。
比如我们只更新提交的不为空的字段,如果提交的数据是空或者"",那么这个字段我们将不更新。
Mapper 接口:
int updateWithSet(Car car);
xml 文件:
<update id="updateWithSet">
update t_car
<set>
<if test="carNum != null and carNum != ''">car_num = #{carNum},</if>
<if test="brand != null and brand != ''">brand = #{brand},</if>
<if test="guidePrice != null and guidePrice != ''">guide_price = #{guidePrice},</if>
<if test="produceTime != null and produceTime != ''">produce_time = #{produceTime},</if>
<if test="carType != null and carType != ''">car_type = #{carType},</if>
</set>
where id = #{id}
</update>
2
3
4
5
6
7
8
9
10
11
# 3.5 choose、when、otherwise
这三个标签是一起使用的,格式为:
<choose>
<when></when>
<when></when>
<when></when>
<otherwise></otherwise>
</choose>
2
3
4
5
6
这等同于:
if () {
...
} else if () {
...
} else if () {
...
} else if () {
...
} else {
...
}
2
3
4
5
6
7
8
9
10
11
只有一个分支会被选择。
需求:先根据品牌查询,如果没有提供品牌,再根据指导价格查询,如果没有提供指导价格,就根据生产日期查询。
List<Car> selectWithChoose(@Param("brand") String brand, @Param("guidePrice") Double guidePrice, @Param("produceTime") String produceTime);
xml 文件:
<select id="selectWithChoose" resultType="car">
select * from t_car
<where>
<choose>
<when test="brand != null and brand != ''">
brand like #{brand}"%"
</when>
<when test="guidePrice != null and guidePrice != ''">
guide_price >= #{guidePrice}
</when>
<otherwise>
produce_time >= #{produceTime}
</otherwise>
</choose>
</where>
</select>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 3.6 foreach
循环数组或集合,动态生成 SQL,比如这样的 SQL:
delete from t_car where id in(1,2,3);
delete from t_car where id = 1 or id = 2 or id = 3;
2
下面以批量删除为例来展示用来,当然批量插入也可以用这个标签。
int deleteBatchByForeach(@Param("ids") Long[] ids);
<delete id="deleteBatchByForeach">
delete from t_car where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
2
3
4
5
6
foreach 的属性:
- collection:集合或数组
- item:集合或数组中的元素
- separator:分隔符
- open:foreach 标签中所有内容的开始
- close:foreach 标签中所有内容的结束
# 3.7 sql 标签和 include 标签
- sql 标签用来声明 SQL 片段
- include 标签用来将声明的 SQL 片段包含到某个 SQL 语句当中
作用:代码复用
<sql id="carCols">id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType</sql>
<select id="selectAllRetMap" resultType="map">
select <include refid="carCols"/> from t_car
</select>
<select id="selectAllRetListMap" resultType="map">
select <include refid="carCols"/> carType from t_car
</select>
<select id="selectByIdRetMap" resultType="map">
select <include refid="carCols"/> from t_car where id = #{id}
</select>
2
3
4
5
6
7
8
9
10
11
12
13