文章目录
1 if标签
1.1 引入
比如下面的接口,我们期望根据查询条件动态查询用户信息
/****
* 根据条件查询用户
* @param tbUser
* @return
*/
List<TbUser> selectUser(TbUser tbUser);
<select id="selectUser" resultType="study.wyy.mybatis.dynamisc.model.TbUser">
select
*
from
tb_user
where
`id` = #{id}
and `username` = #{username}
and `phone` = #{phone}
and `password` = #{password}
</select>
测试:
TbUserMapper tbUserMapper;
@Before
public void getMapper() throws IOException {
// 加载全局配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
// 构建sqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
// 获取sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 生成Mapper接口的代理对象
tbUserMapper = sqlSession.getMapper(TbUserMapper.class);
}
@Test
public void test01() {
TbUser user = new TbUser();
user.setId(1L);
user.setUsername("kobe");
tbUserMapper.selectUser(user);
}
查询结果是空,但是数据库查询在id为1且username是kobe的数据,为何呢,查看日志输出的sql
select * from tb_user where `id` = 1 and `username` = "kobe" and `phone` = null and `password` = null
这条sql其实不是我们期望的sql,我们期望的sql,应该是
select * from tb_user where `id` = 1 and `username` = "kobe"
由于没有传phone和password,就不要给我们赋值为null,这样就导致数据没有查出来
更进一步来说,就是说希望sql能够根据我们的赋值动态的拼接查询条件
1.2 if标签改造sql映射文件
- 使用if标签判断是否该字段赋值
<select id="selectUser" resultType="study.wyy.mybatis.dynamisc.model.TbUser">
select
*
from
tb_user
where
<!-- test:判断表达式(OGNL)
从参数中取值进行判断
遇见特殊符号应该去写转义字符:
&&:
-->
<if test="id != null">
`id` = #{id}
</if>
<if test="username != null">
and `username` = #{username}
</if>
<!--
还可以执行函数,还可以使用逻辑运算
and:
or
-->
<if test="phone != null and phone.trim() != null">
and `phone` = #{phone}
</if>
<if test="password != null">
and `password` = #{password}
</if>
</select>
- 再次测试发现可以查询处结果,此时sql,没有在拼接phone和password
select * from tb_user where `id` = ? and `username` = ?
1.3 OGNL
OGNL( Object Graph Navigation Language )对象图导航语言, 这是一种强大的表达式语言,通过它可以非常方便的来操作对象属性。 类似于我们的EL, SpEL等。
- 访问对象属性: person.name
- 调用方法: person.getName()
- 调用静态属性/方法: @java.lang.Math@PI、@java.util.UUID@randomUUID()
- 调用构造方法: new com.lun.Person(‘admin’).name
- 运算符: +, -*, /, %
- 逻辑运算符: in, not in, >, >=, <, <=, ==, !=
注意: xml中特殊符号如”,>,<等这些都需要使用转义字符
访问集合伪属性:
类型 | 伪属性 | 伪属性对应的 Java 方法 |
---|---|---|
List、 Set、 Map | size、 isEmpty | List/Set/Map.size(),List/Set/Map.isEmpty() |
List、 Set | iterator | List.iterator()、 Set.iterator() |
Map | keys、 values | Map.keySet()、 Map.values() |
Iterator | next、 hasNext | Iterator.next()、 Iterator.hasNext() |
2 where标签
2.1 问题引入
刚刚的查询,如果是这样的:
@Test
public void test02() {
TbUser user = new TbUser();
// id不赋值
//user.setId(1L);
user.setUsername("kobe");
tbUserMapper.selectUser(user);
}
发现报错,查看日志的sql
select * from tb_user where and `username` = ?
显然是sql语法不对,因为id为null,跳过了,导致拼接username的时候,多拼接了一个and
所以解决方式,就是想办法去掉这个and,如果我们在where 条件后面永远跟一个 1=1呢:
给where后面加上1=1,以后的条件都and xxx。
select * from tb_user where 1=1 and `username` = ?
<select id="selectUser" resultType="study.wyy.mybatis.dynamisc.model.TbUser">
select
*
from
tb_user
where
<!--这样即使没有id条件,多出的and就和 1=1这个条件 进行拼了-->
1=1
<if test="id != null">
and `id` = #{id}
</if>
<if test="username != null">
and `username` = #{username}
</if>
<if test="phone != null and phone.trim() != null">
and `phone` = #{phone}
</if>
<if test="password != null">
and `password` = #{password}
</if>
</select>
2.2 where标签
mybatis推荐使用where标签解决,mybatis使用where标签来将所有的查询条件包括在内。mybatis就会将where标签中拼装的sql,多出来的and或者or去掉
<select id="selectUser" resultType="study.wyy.mybatis.dynamisc.model.TbUser">
select
*
from
tb_user
<where>
<if test="id != null">
`id` = #{id}
</if>
<if test="username != null">
and `username` = #{username}
</if>
<if test="phone != null and phone.trim() != null">
and `phone` = #{phone}
</if>
<if test="password != null">
and `password` = #{password}
</if>
</where>
</select>
这样也可以解决问题,但是where只解决前and(or)问题
比如:我们的and可以放到后面写:
<select id="selectUser2" resultType="study.wyy.mybatis.dynamisc.model.TbUser">
select
*
from
tb_user
<where>
<if test="id != null">
`id` = #{id} and
</if>
<if test="username != null">
`username` = #{username} and
</if>
<if test="phone != null and phone.trim() != null">
`phone` = #{phone} and
</if>
<if test="password != null">
`password` = #{password}
</if>
</where>
</select>
运行发现,又出现sql语法错误:
// 后面这个and没有去掉
select * from tb_user WHERE `username` = ? and
所以where只会去掉前面多出来的and或者or,但后面多出来的and或者or则不会去掉
3 trim标签-自定义字符串截取
trim标签体中是整个字符串拼串后的结果。
- prefix:
- prefix给拼串后的整个字符串加一个前缀
- prefixOverrides:
- 前缀覆盖: 去掉整个字符串前面多余的字符
- suffix:
- suffix给拼串后的整个字符串加一个后缀
- suffixOverrides:
- 后缀覆盖:去掉整个字符串后面多余的字符
比如使用trim标签后面多出的and或者or where标签不能解决,但是这个trim标签用的很少,做个了解就行
<select id="selectUser2" resultType="study.wyy.mybatis.dynamisc.model.TbUser">
select
*
from
tb_user
<!--前面 整个添加一个前缀 where
去掉整个字符串后面多余的and
-->
<trim prefix="where" suffixOverrides="and">
<if test="id != null">
`id` = #{id} and
</if>
<if test="username != null">
`username` = #{username} and
</if>
<if test="phone != null and phone.trim() != null">
`phone` = #{phone} and
</if>
<if test="password != null">
`password` = #{password}
</if>
</trim>
</select>
4 choose标签–分支选择
类似于switch-case
<select id="selectUser3" resultType="study.wyy.mybatis.dynamisc.model.TbUser">
select
*
from
tb_user
<where>
<choose>
<!-- 如果用户ID不为空,就是根据用户id查询-->
<when test="id != null">
id=#{id}
</when>
<!-- 如果用户ID为空,但是用户名不为空,就是根据用户名模糊查询-->
<when test="username!=null">
username like '$'#{username}'$'
</when>
<!-- 如果用户ID和用户名都为空,就是查询id=1 也就是otherwise相当于 switch case 的default分支-->
<otherwise>
id = 1
</otherwise>
</choose>
</where>
</select>
@Test
public void test04() {
TbUser user = new TbUser();
// 如果用户ID和用户名都为空,就是查询id=1 也就是otherwise相当于 switch case 的default分支
// select * from tb_user WHERE id = 1
tbUserMapper.selectUser3(user);
// 如果用户ID为空,但是用户名不为空,就是根据用户名模糊查询
// select * from tb_user WHERE username like '$'?'$'
user.setUsername("t-mac");
tbUserMapper.selectUser3(user);
// 如果用户ID不为空,就是根据用户id查询
// select * from tb_user WHERE id=?
user.setId(2L);
tbUserMapper.selectUser3(user);
}
5 set和if实现动态更新
<update id="update">
update
tb_user
set
<if test="username != null">
username = #{username},
</if>
<if test="password != null">
password = #{password},
</if>
<if test="phone != null">
phone = #{phone}
</if>
where id=#{id}
</update>
@Test
public void test05() {
TbUser user = new TbUser();
user.setId(1L);
user.setUsername("kobe");
tbUserMapper.update(user);
}
测试发现存在和之前查询时候 and一样的问题, username = ?,后面多了一个逗号
update tb_user username = ?, where id=?
如何修改呢?mybatis同样也提供了一个标签, 用于消除这个逗号
<update id="update">
update
tb_user
<set>
<if test="username != null">
username = #{username},
</if>
<if test="password != null">
password = #{password},
</if>
<if test="phone != null">
phone = #{phone}
</if>
</set>
where id=#{id}
</update>
6 foreach-遍历集合
- collection:指定要遍历的集合:
- list类型的参数会特殊处理封装在map中,map的key就叫list
- item:将当前遍历出的元素赋值给指定的变量
- separator:每个元素之间的分隔符
- open:遍历出所有结果拼接一个开始的字符
- close:遍历出所有结果拼接一个结束的字符
- index:索引。遍历list的时候是index就是索引,item就是当前值
- 遍历map的时候index表示的就是map的key,item就是map的值
- #{变量名}就能取出变量的值也就是当前遍历出的元素
6.1 批量查询
/****
* 批量根据id查询
* @param ids
* @return
*/
List selectByIds(List<Long> ids);
<select id="selectByIds" resultType="study.wyy.mybatis.dynamisc.model.TbUser">
select
*
from
tb_user
where id in
<!--
collection:指定要遍历的集合:
item:将当前遍历出的元素赋值给指定的变量
separator:每个元素之间的分隔符
index:索引。遍历list的时候是index就是索引,item就是当前值
遍历map的时候index表示的就是map的key,item就是map的值
-->
<foreach collection="ids" item="item_id" open="(" close=")" separator=",">
#{item_id}
</foreach>
</select>
测试
@Test
public void test06() {
tbUserMapper.selectByIds(Arrays.asList(1L, 2L, 3L));
}
日志输出sql:
select * from tb_user where id in ( ? , ? , ? )
6.2 批量插入
/****
* 批量插入
* @param tbUsers
* @return
*/
Boolean creates(@Param("tbUsers") List<TbUser> tbUsers);
<!-- 批量保存
Boolean creates(@Param("tbUsers") List<TbUser> tbUsers);
-->
<!--MySQL下批量保存:可以foreach遍历 mysql支持values(),(),()语法-->
<insert id="creates">
insert into tb_user(username,password,phone,create_time,update_time)
values
<foreach collection="tbUsers" item="user" separator=",">
(#{user.username},#{user.password},#{user.phone},now(),now())
</foreach>
</insert>
测试
@Test
public void test07() {
TbUser tbUser = new TbUser();
tbUser.setUsername("james");
tbUser.setPassword("123213");
tbUser.setPhone("13100001001");
TbUser tbUser1 = new TbUser();
tbUser1.setUsername("wade");
tbUser1.setPassword("123213");
tbUser1.setPhone("13100001001");
tbUserMapper.creates(Arrays.asList(tbUser, tbUser1));
sqlSession.commit();
}
7 动态sql-内置参数 _parameter & _databaseId
- 不只是方法传递过来的参数可以被用来判断,mybatis默认还有两个内置参数:
- 单个参数:_parameter就是这个参数
- 多个参数:参数会被封装为一个map;_parameter就是代表这个map
- _databaseId:如果配置了databaseIdProvider标签。
- _databaseId就是代表当前数据库的别名
<select id="selectUser" resultType="study.wyy.mybatis.dynamisc.model.TbUser">
<if test="_databaseId=='mysql'">
select * from tb_user
<if test="_parameter!=null">
where username like #{_parameter.username}
</if>
</if>
<if test="_databaseId=='oracle'">
select * from tb_user
<if test="_parameter!=null">
where username like #{_parameter.username}
</if>
</if>
</select>
7 动态sql-sql-抽取可重用的sql片段
抽取可重用的sql片段。方便后面引用:
- sql抽取:经常将要查询的列名,或者插入用的列名抽取出来方便引用
- include来引用已经抽取的sql:
- include还可以自定义一些property,sql标签内部就能使用自定义的属性
- include-property:取值的正确方式${prop},
- 不能使用#{},而使用${}