mybatis学习:三、 SQL映射文件、动态SQL

5. SQL映射文件

​ Mapper.xml映射文件中定义了操作数据库的sql,每个sql是一个statement,映射文件是mybatis的核心。

5.1 parameterType(输入类型)

5.1.1 #{}与${}

#{}实现的是向prepareStatement中的预处理语句中设置参数值,sql语句中#{}表示一个占位符即?。

<!-- 根据id查询用户信息 -->
<select id="findUserById" parameterType="int" resultType="user">
   select * from user where id = #{id}
</select>

​ 使用占位符#{}可以有效防止sql注入,在使用时不需要关心参数值的类型,mybatis会自动进行java类型和jdbc类型的转换。#{}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。

${}#{}不同,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。使用${}不能防止sql注入,但是有时用${}会非常方便,如下的例子:

<!-- 根据名称模糊查询用户信息 -->
<select id="selectUserByName" parameterType="string" resultType="user">
    select * from user where username like '%${value}%'
</select>

​ 如果本例子使用#{}则传入的字符串中必须有%号,而%是人为拼接在参数中,显然有点麻烦,如果采用${}在sql中拼接为%的方式则在调用mapper接口传递参数就方便很多。

//如果使用#{}占位符号则必须人为在传参数中加%
List<User> list = userMapper.selectUserByName("%张%");
//如果使用${}原始符号则不用人为在参数中加%
List<User>list = userMapper.selectUserByName("张");

再比如order by排序,如果将列名通过参数传入sql,根据传的列名进行排序,应该写为:

ORDER BY ${columnName}

如果使用#{}将无法实现此功能。

5.1.2 java的对象类型

略,参考前面对user的操作

5.1.3 Java的包装对象类型(一个类包含另外一个类的属性)

​ 开发中通过传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。

​ 解决方式: 建议使用自定义的包装类型。在包装类型中将复杂的查询条件包装进去。

  • 创建一个类,用来封装查询User的条件:
/**
 * 用户条件类
 * @author pactera
 *
 */
public class UserCondition {
	//为了程序的可扩展性,建议重新创建一个类来作为User的查询条件类
	private User user;
	//...还可以加入其它的条件

	public User getUser() {
		return user;
	}

	public void setUser(User user) {
		this.user = user;
	}
}

  • UserMapper接口
//根据用户条件查询用户
public List<User> queryByCondition(UserCondition userCondtion) throws Exception
  • UserMapper.xml
<!-- 根据查询条件查询用户 -->
	<select id="findUserByCondition"  resultType="User" parameterType="UserCondition">
		select * from t_user where id > #{user.id} 
			and username like '%${user.username}%'
	</select>

5.2 输出映射

5.2.1 resultType
5.2.1.1 输出简单类型

Mapper.xml文件

<!-- 获取用户列表总数 -->
<select id="findUserCount" resultType="int">
    select count(1) from user
</select>

Mapper接口:

public int findUserCount() throws Exception;

总结:

查询出来的结果集只有一行且一列,可以使用简单类型进行输出映射

5.2.1.2 输出Java对象类型

不管是输出的单个对象还是一个列表(list中包括对象),在mapper.xml中resultType指定的类型是一样的。都是对象类型

注意:

使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。

  • 如果查询出来的列名和对象中的属性名全部不一致,没有创建对象。

  • 只要查询出来的列名和对象中的属性有一个一致,就会创建对象。

5.2.2 resultMap

在使用resultType作为输出参数,会有以下问题:

  1. 如果我们的表的列名与对象的属性名不一致,使用resultType时,进行属性映射.

  2. 如果我们的对象中包含了另外一个对象(一对一,一对多,多对多关联关系),使用resultType进行映射 .

解决上面问题,就需要使用resultMap来作为输出参数.

1. 定义resultMap

用户表:

在这里插入图片描述

User类:
在这里插入图片描述

在Sql映射文件中,先要手动定义一个resultMap,把对象的属性与表的字段进行映射.

在这里插入图片描述

注意: resultType与resultMap不能共存.

6. 动态SQL

​ mybatis核心 对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接、组装。

6.1 if

<!-- 传递pojo综合查询用户信息 -->
<select id="findUserList" parameterType="user" resultType="user">
    select * from user 
    where 1=1 
    <if test="id!=null and id!=''">
        and id=#{id}
    </if>
    <if test="username!=null and username!=''">
        and username like '%${username}%'
    </if>
</select>

6.2 where

上边的sql也可以改为:

<select id="findUserList" parameterType="user" resultType="user">
		select * from user 
		<where>
		<if test="id!=null and id!=''">
		and id=#{id}
		</if>
		<if test="username!=null and username!=''">
		and username like '%${username}%'
		</if>
		</where>
	</select>

注意: <where />可以自动处理第一个and。or

6.3 set

	<!-- 修改用户 -->
	<update id="updateUser" parameterType="org.csmf.mybatis.entity.User">
		update t_user 
		<set>
			<if test="name!=null and name !='' ">
				username =#{name},
			</if>
			<if test="password !=null and password !='' ">
				password =#{password},
			</if>
			<if test="sex!=null and sex !='' ">
				sex =#{sex},
			</if>
			<if test="brithday!=null and brithday !='' ">
				brithday =#{brithday},
			</if>
			<if test="address!=null and address !='' ">
				address =#{address},
			</if>
		</set>
		<where>
			<if test="id!=null and id!=''">
				id = #{id}
			</if>
		</where>
	</update>

<set>可以处理最后一个逗号

6.4 foreach

向sql传递List,mybatis使用foreach解析.

现在需要通过一组ID查询用户,该sql语句有两种

 select * from t_user where id =1 or id=2 or id=3 or id=4;

select * from t_user where id in (1,2,3,4);

那么对应的Sql映射文件中的sql语句也有两种写法:

第一种:

UserMapper接口:
在这里插入图片描述

Sql映射文件:

	<!-- 根据一组Id查询用户 -->
	<select id="findUserByIds"  resultType="User" parameterType="QueryVo">
		select * from t_user 
		<where>
			<!--select * from t_user where id=? or id=? or =? ...  -->
			<foreach collection="list" item="id" open="and ( " close=")" separator="or">
				id = #{id}
			</foreach> 
		</where>
	</select>

第二种sql的写法:

	<!-- 根据一组Id查询用户 -->
	<select id="findUserByIds"  resultType="User" parameterType="QueryVo">
		select * from t_user 
		<where>
			<!--select * from t_user where id  in (? ,?, ?...) -->
			<foreach collection="list" item="id" open="and id in ( " close=")" separator=" , ">
				#{id}
			</foreach> 
		</where>
	</select>

注意:

<foreach>标签中collection属性不是写参数名,而是写list/array: List集合的参数写: list, 数组类型的参数写: array

6.5 sql片段

Sql中可将重复的sql提取出来,使用时用include引用即可,最终达到sql重用的目的,如下:

<!--综合查询用户信息 -->
	<select id="findUserList" parameterType="user" resultType="user">
		select * from user 
		<where>
		<if test="id!=null and id!=''">
		and id=#{id}
		</if>
		<if test="username!=null and username!=''">
		and username like '%${username}%'
		</if>
		</where>
	</select>

我们可以把上面的sql的条件单独抽取出来,方便其他的sql复用:

<!--将where条件抽取出来:-->
<sql id="query_user_where">
	<if test="id!=null and id!=''">
		and id=#{id}
	</if>
	<if test="username!=null and username!=''">
		and username like '%${username}%'
	</if>
</sql>

然后在其他需要使用到该sql片段的sql中使用<include>标签引入

<select id="findUserList" parameterType="user" resultType="user">
    select * from user 
    <where>
        <include refid="query_user_where"/>
    </where>
</select>

注意:如果引用其它mapper.xml的sql片段,则在引用时需要加上namespace,如下:

<include refid="namespace.sql片段”/>

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值