环境搭建
- 创建表并插入数据
CREATE TABLE `blog` (
`id` varchar(50) NOT NULL COMMENT '博客id',
`title` varchar(100) NOT NULL COMMENT '博客标题',
`author` varchar(30) NOT NULL COMMENT '博客作者',
`create_time` datetime NOT NULL COMMENT '创建时间',
`views` int(30) NOT NULL COMMENT '浏览量'
) ENGINE=InnoDB DEFAULT CHARSET=utf8
- 创建实体类
@Data
public class Blog {
private String id;
private String title;
private String author;
private Date createTime;
private int views;
}
- Mapper接口
public interface BlogMapper {
List<Blog> getAllBlogs();
}
- Mapper映射文件
<mapper namespace="com.wcy.dao.BlogMapper">
<select id="getAllBlogs" resultType="Blog">
select *
from blog;
</select>
</mapper>
- mybatis配置文件
<configuration>
<!-- 外部配置文件 -->
<properties resource="db.properties"/>
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
<!-- 别名 -->
<typeAliases>
<typeAlias type="com.wcy.pojo.Blog" alias="Blog"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!-- 自己编写的Mapper接口对应的mapper.xml -->
<mappers>
<mapper resource="com/wcy/dao/BlogMapper.xml"/>
</mappers>
</configuration>
- 测试
@Test
public void getAllBlogs(){
SqlSession session = MybatisUtil.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
List<Blog> allBlogs = mapper.getAllBlogs();
for (Blog blog : allBlogs) {
System.out.println(blog);
}
session.close();
}
这里create出现null是因为数据库中的字段和实体类中的属性不匹配导致的,这里由于他们的区别只是没有用驼峰命名,我们只需要添加一条设置即可
<setting name="mapUnderscoreToCamelCase" value="true"/>
if语句
使用if语句实现动态查询
List<Blog> getBlogsByIf(Map<String, Object> map);
<select id="getBlogsByIf" resultType="Blog" parameterType="map">
select * from blog where 1=1
<!--如果title条件存在 继续加上下面的条件-->
<if test="title != null">
and title=#{title}
</if>
<!--如果author条件存在 继续加上下面的条件-->
<if test="author != null">
and author=#{author}
</if>
</select>
@Test
public void getBlogsByIf(){
SqlSession session = MybatisUtil.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, Object> map = new HashMap<>();
List<Blog> blogs = mapper.getBlogsByIf(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
session.close();
}
此时如果不在map中传入任何的参数,能够查询到所有的信息
如果要查询符合条件的信息,只需要传入对应的kv键值对即可
@Test
public void getBlogsByIf(){
SqlSession session = MybatisUtil.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, Object> map = new HashMap<>();
map.put("title", "python");
map.put("author", "王二");
List<Blog> blogs = mapper.getBlogsByIf(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
session.close();
}
可以看到对应的sql加上了限制条件
where语句
在上面的例子中,我们在基础sql语句的最后添加了一个条件1=1,这是为了我们在使用if语句拼接的时候可以正确的拼接语句,因为如果不写1=1这个条件,当所有的if条件没有匹配上时,sql语句就会变成下面这个样子
select * from blog where
这样的话sql语句就会报错,所以添加1=1这个条件防止sql语句出错
但是在实际开发中我们不会加上中多余的条件,所以where元素就专门来解决这个问题的,来看看官方说明
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除
用个实例来说明一下,继续用上面的例子
List<Blog> getBlogsByIf(Map<String, Object> map);
将mapper更改一下
<select id="getBlogsByIf" resultType="Blog" parameterType="map">
select * from blog
<!--如果where标签中有成立的选项,才会拼接where条件-->
<where>
<!--如果title条件存在 继续加上下面的条件-->
<if test="title != null">
and title=#{title}
</if>
<!--如果author条件存在 继续加上下面的条件-->
<if test="author != null">
and author=#{author}
</if>
</where>
</select>
接下来测试
- 满足第一个条件时
@Test
public void getBlogsByIf(){
SqlSession session = MybatisUtil.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, Object> map = new HashMap<>();
// 传入第一个条件
map.put("title", "python");
List<Blog> blogs = mapper.getBlogsByIf(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
session.close();
}
可以看到sql语句拼接了where,并且我们在每一个条件的前面其实都加了and,但是实际的sql语句里面,and已经被去掉了,这就是where的好处,也印证了官方的话
- 满足两个条件
@Test
public void getBlogsByIf(){
SqlSession session = MybatisUtil.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, Object> map = new HashMap<>();
// 传入第一个条件和第二个条件
map.put("title", "python");
map.put("author", "王二");
List<Blog> blogs = mapper.getBlogsByIf(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
session.close();
}
结果和想象中的一样,sql语句被正确的拼接了
- 没有任何条件时
@Test
public void getBlogsByIf(){
SqlSession session = MybatisUtil.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, Object> map = new HashMap<>();
List<Blog> blogs = mapper.getBlogsByIf(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
session.close();
}
可以看到当没有任何条件时,并没有拼接where关键字,查询到了所有的信息
set语句
set和where的用法差不多
set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)
int updateBlog(Map<String, Object> map);
<update id="updateBlog" parameterType="map">
update blog
<!--动态拼接set字段-->
<set>
<if test="title != null">
title=#{title}
</if>
<if test="author != null">
author=#{author}
</if>
<if test="views != null">
views=#{views}
</if>
</set>
where id=#{id}
</update>
trim语句
可以自定义where和set语句
如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:
<!--and和or后面都有空格-->
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。
来看看与 set 元素等价的自定义 trim 元素吧:
<trim prefix="SET" suffixOverrides=",">
...
</trim>
注意,我们覆盖了后缀值设置为",",并且自定义了前缀值为set
choose语句
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
编写一个条件查询来试一下
ist<Blog> getBlogsByChoose(Map<String, Object> map);
<select id="getBlogsByChoose" parameterType="map" resultType="Blog">
select * from blog
<where>
<!--
choose中只有一个选项能执行
当when中的条件满足时就会拼接上
当when中的条件都不满足时会拼接otherwise中的语句
-->
<choose>
<when test="id != null">
id=#{id}
</when>
<when test="title != null">
title=#{title}
</when>
<when test="author != null">
author=#{author}
</when>
<otherwise>
<!--这里什么也不做 不存在条件就查询全部-->
</otherwise>
</choose>
</where>
</select>
SqlSession session = MybatisUtil.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, Object> map = new HashMap<>();
map.put("views", 6666);
map.put("id", 1);
int i = mapper.updateBlog(map);
System.out.println(i);
session.close();
可以看到 传入id后,满足了第一个条件,并没有加上views条件
来看一下什么都不传的情况
@Test
public void getBlogsByChoose(){
SqlSession session = MybatisUtil.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Map<String, Object> map = new HashMap<>();
List<Blog> blogs = mapper.getBlogsByChoose(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
session.close();
}
确实没有添加条件,查询到了全部的信息
sql片段
有时候可能某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们需要将这些代码抽取出来,然后使用时直接调用。使用sql标签即可完成
<select id="getBlogsByIf" resultType="Blog" parameterType="map">
select * from blog
<!--如果where标签中有成立的选项,才会拼接where条件-->
<where>
<!--使用include来引入sql片段-->
<include refid="condition"/>
</where>
</select>
<!-- 使用sql标签提取出sql片段 -->
<sql id="condition">
<!--如果title条件存在 继续加上下面的条件-->
<if test="title != null">
and title=#{title}
</if>
<!--如果author条件存在 继续加上下面的条件-->
<if test="author != null">
and author=#{author}
</if>
</sql>
foreach语句
foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符,看它多智能!
提示 你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。
例如用一个多条件查询来实现这个例子
select * from blog where (id=1 or id=2 or id=3)
在这个sql语句中,我们用foreach来动态添加括号内的条件,只需要传入一个id数组即可
List<Blog> getBlogsByForeach(Map<String, Object> map);
<select id="getBlogsByForeach" parameterType="map" resultType="Blog">
select * from blog
<where>
<!--
collection->被遍历的集合 意味着我们需要在map中put一个名为ids的集合
item->每一个被遍历项目的名字
index->被遍历的索引名
open->开始符号
separator->分隔符号
close->结尾符号
-->
<foreach collection="ids" item="id" index="index" open="(" separator="or" close=")">
id=#{id}
</foreach>
</where>
</select>
当传入参数时,拼接条件
@Test
public void getBlogsByForeach(){
SqlSession session = MybatisUtil.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
HashMap<String, Object> map = new HashMap<>();
ArrayList<Integer> ids = new ArrayList<>();
ids.add(1);
ids.add(2);
map.put("ids", ids);
List<Blog> blogs = mapper.getBlogsByForeach(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
session.close();
}
传入空列表时,默认查询全部
@Test
public void getBlogsByForeach(){
SqlSession session = MybatisUtil.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
HashMap<String, Object> map = new HashMap<>();
ArrayList<Integer> ids = new ArrayList<>();
map.put("ids", ids);
List<Blog> blogs = mapper.getBlogsByForeach(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
session.close();
}