在实际场景中,我们需要根据业务使用sql语句,这时动态sql语句就能很大程度上提高代码重用性,使编程更加灵活
我们先来看看示例
// mapper接口
public interface UserMapper {
public List findUserListByUserInfo(User user);
}
//mapper映射文件
<select id="findUserListByUserInfo" parameterType="com.zyj.mybatis.po.User" resultType="com.zyj.mybatis.po.User">
select * from user where username like '%${username}%' and sex = #{sex}
select>
//测试代码
@Test
public void testFindUserListByUserInfo() throws IOException {
//......
// 调用mapper方法
User userCondition = new User();
userCondition.setUsername("小明");
userCondition.setSex("1");
List list = userMapper.findUserListByUserInfo(userCondition);
//......
}
问题:以上代码可以正常运行,但是存在硬编码问题,灵活性差
比如只能固定使用username和sex两个字段作为条件来查询,如果增加或缺少字段,就会导致程序运行结果与预期不符
解决方法:使用Mybatis提供的标签,实现动态SQL语句
我们可以修改下mapper映射文件
<select id="findUserListByUserInfo" parameterType="com.zyj.mybatis.po.User" resultType="com.zyj.mybatis.po.User">
select * from user
<where>
<if test="username != null and username != ''">
and username like '%${username}%'
if>
<if test="sex != null and sex != ''">
and sex = #{sex}
if>
where>
select>
修改后,Mybatis可以自行根据条件创建sql语句
另外还支持将通用SQL抽取出来,提高代码重用性
<sql id="whereClause">
<if test="user != null">
<if test="username != null and username != ''">
AND username LIKE '%${username}%'
if>
<if test="sex != null and sex != ''">
AND sex = #{sex}
if>
if>
sql>
<select id="findUserListByUserInfo" parameterType="com.zyj.mybatis.po.User" resultType="com.zyj.mybatis.po.User">
select * from user
<where>
<include refid="whereClause" />
where>
select>
上面的where标签,其实用trim可以表示如下:
"WHERE" prefixOverrides="AND | OR ">
...
它的意思就是: 当WHERE后紧随AND或则OR的时候,就去除AND或者OR。 除了WHERE以外, 其实还有一个比较经典的实现,那就是SET。
id="updateUser" parameterType="com.dy.entity.User">
update user set
<if test="name != null">
name = #{name},
if>
<if test="password != null">
password = #{password},
if>
<if test="age != null">
age = #{age}
if>
<where>
<if test="id != null">
id = #{id}
if>
and deleteFlag = 0;
where>
问题来了: “如果只有name不为null时, 那么这SQL不就成了 update set name = #{name}, where ........
? 那name后面那逗号会导致出错啊!”
是的,这时候,就可以用mybatis为我们提供的set标签了。下面是通过set标签改造后:
"updateUser" parameterType="com.dy.entity.User">
update user
<set>
<if test="name != null">name = #{name},if>
<if test="password != null">password = #{password},if>
<if test="age != null">age = #{age},if>
set>
<where>
<if test="id != null">
id = #{id}
if>
and deleteFlag = 0;
where>
这个用trim可表示为:
"SET" suffixOverrides=",">
...
WHERE是使用的 prefixOverrides(前缀), SET是使用的 suffixOverrides (后缀), 看明白了吧!
需求:SELECT * FROM user WHERE id IN (1,10,16)
// mapper接口
public interface UserMapper {
public List<User> findUserListByIdList(List<Integer> ids);
}
// mapper映射文件
<select id="findUserListByIdList" parameterType="list" resultType="com.zyj.mybatis.po.User">
select * from user
<where>
<if test="list != null">
and id in
<foreach collection="list" index="index" item="id" open="(" separator="," close=")">
#{id}
foreach>
if>
where>
// 拼出来的字符串:where id in (1, 10, 16)
select>
// 测试代码
@Test
public void findUserListByIdList() throws IOException {
//......
// 调用mapper方法
List<Integer> ids = new ArrayList<Integer>();
ids.add(1);
ids.add(10);
ids.add(16);
List<User> list = mapper.findUserListByIdList(ids);
//......
}
bind 元素可以从 OGNL 表达式中创建一个变量并将其绑定到上下文。比如:
<select id="selectBlogsLike" resultType="Blog">
"pattern" value="'%' + _parameter.getTitle() + '%'" />
SELECT * FROM BLOG
WHERE title LIKE #{pattern}
select>