MyBatis(九):动态SQL
动态SQL(Dynamic SQL)
-
动态 SQL 是 MyBatis 的强大特性之一。
-
其实就是简化了拼接SQL的方式。比如实际业务中,输入了用户名时,要按用户名查询是非常常见的,动态SQL其实就是Mybatis里的方式。
if(username!=null&&!"".equals(username)){ sb.append("and username = '"+username+"' " ); }
-
在Mapper.xml文件中使用以下四种符号实现(和JSTL很像)。
-
if
-
choose (when, otherwise)
-
trim (where, set)
-
foreach
-
环境准备
拓展
-
实体类
public class Blog { private int id; private String title; private String author; private Date createTime; private int views; }
注意:实体类的Date是createTime,而数据库中的是create_time,字段不一样,但是可以通过主配置文件的setting,自动把驼峰规则修改为下划线---->createTime的T自动变为_t。
<settings> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings>
-
UUID--雪花算法自动生成pk
public class IDutils { public static String getId(){ return UUID.randomUUID().toString().replaceAll("-",""); } }
-
Mapper.xml
<insert id="addBlog" parameterType="blog">
<!--注意value中传入的时间是实体类的名称,insert进数据库写的是字段名-->
insert into mybatis.blog (id,title,author,create_time,views)
values (#{id},#{title},#{author},#{createTime},#{views})
</insert>
-
测试类
-
日期的new Date()虽然在控制台输出是,但是只要实体类和数据库的格式都是date,那么就会自动转换成数据库的格式而不需要手动转换。
-
@Test public void addInitBlog(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); Blog blog = new Blog(); blog.setId(IDutils.getId()); blog.setTitle("Mybatis学习"); blog.setAuthor("张三"); blog.setCreateTime(new Date()); blog.setViews(222); System.out.println(blog.toString()); mapper.addBlog(blog); blog.setId(IDutils.getId()); blog.setTitle("Java学习"); mapper.addBlog(blog); blog.setId(IDutils.getId()); blog.setTitle("Spring学习"); mapper.addBlog(blog); blog.setId(IDutils.getId()); blog.setTitle("SpringMVC学习"); mapper.addBlog(blog); sqlSession.commit(); sqlSession.close(); }
if
-
Mapper接口
//查询博客 List<Blog> queryBlogIF(Map map);
-
Mapper.xml
-
增加if条件即可
-
<select id="queryBlogIF" parameterType="map" resultType="blog"> select * from blog t where 1=1 <if test="title!=null"> and title = #{title} </if> <if test="author!=null"> and author = #{author} </if> </select>
-
测试类,通过map传参
@Test public void queryBlogIf(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); // map.put("title","Mybatis学习"); map.put("author","李四"); List<Blog> blogs = mapper.queryBlogIF(map); for (Blog blog : blogs) { System.out.println(blog); } sqlSession.close(); }
choose和where
-
和if的区别是,choose中只会选择一个执行,就和switch一样
-
Mapper.xml
<select id="queryBlogChoose" parameterType="map" resultType="blog"> select * from blog t <where> <choose> <when test="title!=null"> title = #{title} </when> <when test="author!=null"> and author = #{author} </when> <otherwise> and views >10 </otherwise> </choose> </where> </select>
where:
-
上面的例子中增加了where标签
-
如果不使用where 1=1,可以使用官方给的标签<where>,然后第一个语句不写连接符就可以了
-
(其实第一句也加and测试下来也没问题,而且官方描述是子句开头是and或者or的,作为第一句语句时会自动去除and和or,写了更整齐,以后用多了再看吧)。
-
测试类
@Test public void queryBlogIf(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); // map.put("title","Mybatis学习"); map.put("author","李四"); List<Blog> blogs = mapper.queryBlogChoose(map); for (Blog blog : blogs) { System.out.println(blog); } sqlSession.close(); }
set
-
set只限于update中,和where的用法类似
-
Mapper.xml
<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>
-
测试类
@Test public void updateblog(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); map.put("title","Mybatis学习1212"); map.put("id","1"); mapper.updateBlog(map); sqlSession.commit(); sqlSession.close(); }
foreach
-
对于in语句,可以使用foreach对集合进行遍历
-
比如对于以下语句,如果2、4、6用map来传,xml文件里就要定义3个变量了,这时候可以用foreach
select * from blog where id in ('2','4','6')
-
foreach
<!--collection--传入集合的名称 item--从集合遍历时每个元素的引用名称 open--循环前拼接的内容 separator--每个元素之间间隔的内容 close--循环后拼接的内容 index--循环时下标的序号名称,很少会使用到 --> <select id="queryBlogForeach" parameterType="map" resultType="blog"> select * from blog <where> id in <foreach collection="ids" item="idv" open="(" separator="," close=")"> #{idv} </foreach> </where> </select>
-
测试类
@Test public void queryBlogForeach(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); ArrayList<Integer> ids = new ArrayList<>(); ids.add(2); ids.add(4); ids.add(6); HashMap map = new HashMap(); map.put("ids",ids); List<Blog> blogs = mapper.queryBlogForeach(map); for (Blog blog : blogs) { System.out.println(blog); } sqlSession.close(); }
trim
-
这个标签其实一般不会用到,因为where、set标签一般就够用了。
-
假如没有where 标签,使用trim也可以达到相同的效果:
-
trim有3个属性
-
prefix:标签内的语句会用这个属性开头
-
suffix:标签内的语句会用这个结尾
-
prefixOverrides:标签内的第一个语句是这个属性开头,会去掉
-
suffixOverrides:标签内最后一个语句是这个结尾,会去掉
-
<trim prefix="WHERE" prefixOverrides="AND |OR " suffixOverrides=","> ... </trim>
-
示例:其实就和where完全一样
<select id="queryBlogForeach" parameterType="map" resultType="blog"> select * from blog <trim prefix="where" prefixOverrides="and|or" > and id in <foreach collection="ids" item="idv" open="(" separator="," close=")"> #{idv} </foreach> </trim> </select>
SQL片段
-
把公共的SQL抽取出来,方便复用。
-
Mapper.xml
<!--把公共部分抽取出来--> <sql id="ifta"> <if test="title!=null"> and title = #{title} </if> <if test="author!=null"> and author = #{author} </if> </sql> <!--通过ID可以进行调用--> <select id="queryBlogIF" parameterType="map" resultType="blog"> select * from blog t <where> <include refid="ifta"/> </where> </select>
注意事项:
-
最好基于单表来定义SQL片段
-