动态SQL
什么是动态SQL: 就是指根据不同的条件生成不同的SQL语句
所谓的动态SQL本质还是SQL语句,只是我们可以在SQL层面执行一些逻辑代码
1. 环境搭建
创建一个基础工程mybatis08
导包
编写配置文件
编写实体类
@Datapublic class Blog {private String id;private String titile;private String author;private Date createTime;private int views;}编写实体类对应的Mapper接口和mapper.xml文件
//插入数据int addBlog(Blog blog);<mapper namespace="com.bsx.dao.BlogMapper"><insert id="addBlog" parameterType="com.bsx.pojo.Blog">insert into blog (id, title, author, create_time, views)values (#{id}, #{title} , #{author}, #{createTime}, #{views});</insert></mapper>编写IDUtils工具类
public class IDUtils {public static String getUUID() {return UUID.randomUUID().toString().replace("-", "");}}- 开启驼峰命名映射
在核心配置文件中配置
settings
开启mapUnderscoreToCamelCase
<settings><setting name="logImpl" value="LOG4J"/><setting name="mapUnderscoreToCamelCase" value="true"/></settings>- 测试
@Testpublic void testInsert() throws IOException {InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);SqlSession sqlSession = sqlSessionFactory.openSession(true);try {BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);Blog blog = new Blog();blog.setId(IDUtils.getUUID());blog.setAuthor("bsx");blog.setTitle("Title 1");blog.setCreateTime(new Date());blog.setViews(9999);mapper.addBlog(blog);blog.setId(IDUtils.getUUID());blog.setTitle("Title 2");blog.setCreateTime(new Date());mapper.addBlog(blog);blog.setId(IDUtils.getUUID());blog.setTitle("Title 3");blog.setCreateTime(new Date());mapper.addBlog(blog);} catch (Exception e) {e.printStackTrace();} finally {sqlSession.close();}}- 开启驼峰命名映射
在核心配置文件中配置
2. 动态SQL之IF语句
如果传了作者就按作者查,如果传了标题就按标题查,如果啥也没传就查所有
接口
//查询博客List<Blog> queryBlogIF(Map map);mapper.xml
<select id="queryBlogIF" resultType="com.bsx.pojo.Blog" parameterType="map">select * from blog where 1=1<if test="title != null">and title = #{title}</if><if test="author != null">and author = #{author}</if></select>
测试
@Testpublic void testQueryBlogIF() throws IOException {InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);SqlSession sqlSession = sqlSessionFactory.openSession(true);try {BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);//1. 啥也不传Map map = new HashMap();//查出所有blogList<Blog> blogs = mapper.queryBlogIF(map);for (Blog blog : blogs) {System.out.println(blog);}//2. 传titlemap.put("title", "Title 1");//Blog(id=ac6d574b9f0a4dbe9ecb8a9ce433a461, title=Title 1, author=bsx, createTime=Thu Mar 19 20:38:00 CST 2020, views=9999)blogs = mapper.queryBlogIF(map);for (Blog blog : blogs) {System.out.println(blog);}map.put("author", "bsx");//Blog(id=ac6d574b9f0a4dbe9ecb8a9ce433a461, title=Title 1, author=bsx, createTime=Thu Mar 19 20:38:00 CST 2020, views=9999)blogs = mapper.queryBlogIF(map);for (Blog blog : blogs) {System.out.println(blog);}} catch (Exception e) {e.printStackTrace();} finally {sqlSession.close();}}
3. 动态SQL之常用标签
3.1 trim(where, set)
where元素只会在至少有一个子元素的条件返回sql子句的情况下才去插入"WHERE"子句。而且,若语句开头为"AND"或者"OR",where元素也会将它们去除
where标签
<select id="queryBlogIF" resultType="com.bsx.pojo.Blog" parameterType="map">select * from blog<where><if test="title != null">and title = #{title}</if><if test="author != null">and author = #{author}</if></where></select>set 用在Update语句中,set元素会动态前置SET关键字,同时也会删掉无关的逗号,因为用了条件语句之后很可能就会在生成的SQL语句的后面留下这些逗号
接口
//更新博客int updateBlog(Map map);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>测试
@Testpublic void testUpdateSet(){SqlSession sqlSession = MybatisUtils.getSqlSession();try {BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);Map map = new HashMap();//这里的id从数据库复制map.put("id","ac6d574b9f0a4dbe9ecb8a9ce433a461");map.put("title","UpdatedTitle");map.put("author","updateAuthor");mapper.updateBlog(map);} catch (Exception e) {e.printStackTrace();} finally {sqlSession.close();}}
trim 把
,
后缀替换为SET
<trim prefix="SET" suffixOverrides=",">...</trim>同理把
AND
或者OR
替换为WHERE
3.2 choose, when, otherwise
类似Java中的switch语句,用where
标签替换sql语句中的where
接口
//test Choose when otherwiseList<Blog> queryBlogChoose(Map map);mapper.xml
<select id="queryBlogChoose" resultType="com.bsx.pojo.Blog" parameterType="map">select * from blog<where><choose><when test="title != null">title = #{title}</when><when test="author != null">and author = #{author}</when><otherwise>and views = #{views}</otherwise></choose></where></select>测试
@Testpublic void testChoose() {SqlSession sqlSession = MybatisUtils.getSqlSession();try {BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);Map map = new HashMap();map.put("views", 9999);List<Blog> blogs = mapper.queryBlogChoose(map);for (Blog blog : blogs) {System.out.println(blog);}// map.put("title", "Title 1");// blogs = mapper.queryBlogChoose(map);// for (Blog blog : blogs) {// System.out.println(blog);// }map.put("author", "bsx");blogs = mapper.queryBlogChoose(map);for (Blog blog : blogs) {System.out.println(blog);}} catch (Exception e) {e.printStackTrace();} finally {sqlSession.close();}}
4. SQL片段
有的时候,我们可能会将一些公共的部分抽取出来,用sql标签
包起来,方便复用。
实用include标签
引用sql标签
的内容
注意事项:
- 最好基于单表定义SQL片段
- 不要存在
where标签
5. 动态SQL之Foreach
动态SQL的另一个常用的操作需求是对一个集合进行遍历,通常是在构造IN条件语句的时候
foreach标签
允许指定一个集合,声名可以在元素体内实用的集合项item
和索引index
变量。它也允许你指定开始和结尾的字符串以及迭代结果之间分隔符。
当使用List、Set或者数组时,index
是当前迭代的次数,item
是本次迭代获取的元素;当使用Map对象或者Map.Entry对象的集合时,index
是键,item
是值
为了测试方便,现将数据库中的id改为1234的形式
接口
//查询第1-2-3号记录的博客List<Blog> queryBlogForeach(Map map);mapper.xml 现在传递一个万能的
map
,这个map
中存在一个集合ids
对应foreach
中的collection
,其中的每一项为id
对应item
<select id="queryBlogForeach" resultType="com.bsx.pojo.Blog" parameterType="map">select * from blog<where><foreach collection="ids" item="id" open="(" separator="or" close=")">id = #{id}</foreach></where></select>
测试
@Testpublic void testForeach() {SqlSession sqlSession = MybatisUtils.getSqlSession();try {BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);Map map = new HashMap();List list = Arrays.asList(1, 2, 3);map.put("ids", list);List<Blog> blogs = mapper.queryBlogForeach(map);for (Blog blog : blogs) {System.out.println(blog);}} catch (Exception e) {e.printStackTrace();} finally {sqlSession.close();}}结果
Blog(id=1, title=UpdatedddddTitle, author=updateAuthor, createTime=Thu Mar 19 20:38:00 CST 2020, views=9999)Blog(id=2, title=Title 2, author=bsx, createTime=Thu Mar 19 20:38:01 CST 2020, views=9999)Blog(id=3, title=Title 3, author=bsx, createTime=Thu Mar 19 20:38:01 CST 2020, views=9999)动态情况
select * from blogselect * from blog where (id=1)select * from blog where (id=1 or id=2 or id=2)
动态SQL就是在拼接SQL语句,我们只要确保SQL的正确性,按照SQL的格式,进行排列组合
建议:
- 先在Mysql中写出完整的SQL,在对应写改成为动态SQL,实现通用即可