动态SQL指的是根据不同的查询条件 , 生成不同的Sql语句.
1. 数据准备
- 数据库表:blog
字段:id,title,author,create_time,views
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
实体类:Blog
@Data public class blog { private String id; private String title; private String author; // 数据库中是create_time, 字段名不一致 private Date createTime; private int views; }
BlogMapper:
public interface BlogMapper {
}
- 配置 db.properties:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8
user=root
pwd=1234
配置 mybatis-config.xml :
在Blog有字段 createTime, 在数据库中的存储为 create_time。其字段不一致。因此,在settings里面添加:<setting name="mapUnderscoreToCamelCase" value="true"/>
就允许驼峰命名。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="db.properties"/>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<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="${user}"/>
<property name="password" value="${pwd}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/dao/BlogMapper.xml" />
</mappers>
</configuration>
- 配置BlogMapper.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.pojo.Blog">
</mapper>
在 com.utils包下创建工具类
public class IDutils { public static String getId(){ return UUID.randomUUID().toString().replace("-","") ; } }
- 插入初始数据
编写接口:int addBlog(Blog blog);
sql配置文件:
<mapper namespace="com.dao.BlogMapper">
<insert id="addBlog" parameterType="com.pojo.Blog" >
insert into blog(id , title, author, create_time, views)
values (#{id} , #{title}, #{author}, #{createTime}, #{views})
</insert>
</mapper>
Test:
@Test
public void testAddBlog(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
Blog blog = new Blog();
blog.setId(IDutils.getId());
blog.setCreateTime(new Date());
blog.setAuthor("张三");
blog.setTitle("气态之说");
blog.setViews(455);
blogMapper.addBlog(blog);
sqlSession.close();
}
2. 语句
if
条件判断
根据作者名字和博客名字来查询博客!如果作者名字为空,那么只根据博客名字查询,反之,则根据作者名来查询
- 在 BlogMapper中编写接口
//需求1 : 查询博客
List<Blog> queryBlogIf(Map map);
- 在BlogMapper.xml 编写SQL语句:
<!--需求1:
根据作者名字和博客名字来查询博客!
如果作者名字为空,那么只根据博客名字查询,反之,则根据作者名来查询
select * from blog where title = #{title} and author = #{author}
-->
<select id="queryBlogIf" parameterType="map" resultType="com.pojo.Blog">
select * from blog
where 1 = 1
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</select>
<if test=""> </if> 判断添加是否满足,满足的话,就自动拼接SQL语句。
Test:
@Test
public void testQueryBlogIf(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
Map<String,String> map = new HashMap<String,String>();
map.put("author","侯杰");
map.put("title","软件设计模式");
List<Blog> blogList = blogMapper.queryBlogIf(map);
for (Blog blog : blogList) {
System.out.println(blog);
}
}
注意:
- 在上述where语句后面添加了 “1 = 1”, 如果在<if>不满足的时候,“1 = 1” 能保证 SQL语句的正确性。
- 如果去掉“1 = 1” 之后,怎么解决上述问题?,我们接下来可以使用 where 语句。
where
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
- 在 BlogMapper中编写接口
//需求1 : 查询博客
List<Blog> queryBlogWhere(Map map);
- 在BlogMapper.xml 编写SQL语句:
<!--需求1:
根据作者名字和博客名字来查询博客!
如果作者名字为空,那么只根据博客名字查询,反之,则根据作者名来查询
select * from blog where title = #{title} and author = #{author}
-->
<select id="queryWhere" parameterType="map" resultType="com.pojo.Blog">
select * from blog
<where>
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
author = #{author}
</if>
</where>
</select>
- 原来的 SQL语句的where 不写
Test:
@Test
public void testqueryWhere(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
Map<String,String> map = new HashMap<String,String>();
map.put("author","侯杰");
List<Blog> blogList = blogMapper.queryBlogWhere(map);
for (Blog blog : blogList) {
System.out.println(blog);
}
}
choose、when、otherwise
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
- 在 BlogMapper中编写接口
//需求1 : 查询博客
List<Blog> queryBlogChoose(Map map);
- 在BlogMapper.xml 编写SQL语句:
<select id="queryBlogChoose" parameterType="map" resultType="com.pojo.Blog">
select * from blog
<where>
<choose>
<when test="title != null">
title = #{title}
</when>
<when test="author !=null">
and author = #{author}
</when>
<otherwise>
and views > #{view}
</otherwise>
</choose>
</where>
</select>
Test:
@Test
public void testqueryBlogChoose(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
Map<String,String> map = new HashMap<String, String>();
// map.put("title","软件设计模式");
// map.put("author","侯杰");
map.put("view","500");
List<Blog> blogList = blogMapper.queryBlogChoose(map);
for (Blog blog : blogList) {
System.out.println(blog);
}
}
- choose、when、otherwise的搭配等价于java中的switch、case;
- choose下面的when只会有一个被选择出来(相当于每一个 when后面由一个break)
set
- set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。(和where中的带有同意的道理)。
- 原生的SQL语句中的set 用 <set> 标签替代。
- 在 BlogMapper中编写接口
//更新博客
int updateBlog(Map map);
- 在BlogMapper.xml 编写SQL语句:
<!-- 当 if 中的语句和 前面的sql拼接的时候,<set>标签会
自动的将“,”去除,从而保证正确的sql语法
-->
<update id="updateBlog" parameterType="map" >
update blog
<set>
<if test="title != null">
, title = #{title}
</if>
<if test="author != null">
,author = #{author}
</if>
</set>
where id = #{id}
</update>
trim
foreach
有时候可能某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们需要将这些代码抽取出来,然后使用时直接调用。
把前面中案例中的片段提取出来(用 标签 <sql>来表示):
<sql id="ifVer">
<if test="title != null">
, title = #{title}
</if>
<if test="author != null">
,author = #{author}
</if>
</sql>
引用该片段用标签:<include refid="">
例如:
<update id="updateBlog" parameterType="map" >
update blog
<set>
<include refid="ifVer" />
</set>
where id = #{id}
</update>
注意事项:
- 最好基于单表sql片段,多表的复杂性较高
- 不要把 where等标签放到片段中去
foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符.
1、编写接口
//查询,根据 Foreach
List<Blog> queryBlogForeach(Map map);
- 在BlogMapper中编写SQL语句:
<!--
collection:指定输入对象中的集合属性
item:每次遍历生成的对象
open:开始遍历时的拼接字符串
close:结束时拼接的字符串
separator:遍历对象之间需要拼接的字符串
-->
<!--
map里传递了一个集合:nameList
-->
<!-- select * from blog where ( name = "x1" or name = "x2" or name = "x3")-->
<select id="queryBlogForeach" parameterType="map" resultType="com.pojo.Blog">
select * from blog
<where>
<foreach collection="nameList" item="name_item" open="(" separator="or" close=")">
author = #{name_item}
</foreach>
</where>
</select>
Test:
@Test
public void testqueryBlogForeach(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
HashMap<String,List<String>> hashMap = new HashMap<String,List<String>>();
List<String> nameList = new ArrayList<String>();
nameList.add("侯杰");
nameList.add("李二");
hashMap.put("nameList", nameList);
List<Blog> listBlog = blogMapper.queryBlogForeach(hashMap);
for (Blog blog : listBlog) {
System.out.println(blog);
}
sqlSession.close();
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。