- 动态SQL是指根据不同的条件生成不同的SQL语句
- 所谓的动态SQL,本质还是SQL语句,只是可以在SQL层面去执行一个逻辑代码
- 动态SQL就是在拼接SQL语句,只要保证SQL的正确性,按照SQL的格式,去排列组合就可以了
1、搭建环境
-
搭建数据库
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
-
创建一个基础工程
-
导包
-
编写配置文件
<?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核心配置文件--> <configuration> <!--引入外部配置文件--> <properties resource="db.properties" /> <settings> <!--标准日志工厂实现--> <setting name="logImpl" value="STDOUT_LOGGING"/> <!--是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。--> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings> <!--可以给实体类起别名--> <typeAliases> <package name="com.ping.pojo"/> </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> <mappers> <mapper class="com.ping.dao.BlogMapper"/> </mappers> </configuration
-
编写工具类
public class MybatisUtils { private static SqlSessionFactory sqlSessionFactory; static{ try { //使用Mybatis的第一步:获取sqlSessionFactory对象 String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } //既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。 //SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。 public static SqlSession getSqlSession() { return sqlSessionFactory.openSession(true); } }
//获取随机ID public class IDUtils { public static String getId(){ return UUID.randomUUID().toString().replaceAll("-",""); } @Test public void test(){ System.out.println(IDUtils.getId()); System.out.println(IDUtils.getId()); } }
-
编写实体类
@Data public class Blog { private String id; private String title; private String author; private Date createTime; //属性名和字段名不一致 private int views; }
-
编写实体类对应Mapper接口
public interface BlogMapper { //插入数据 int addBlog(Blog blog); }
-
Mapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.ping.dao.BlogMapper"> <insert id="addBlog" parameterType="Blog"> insert into blog (id, title, author, create_time, views) values(#{id}, #{title}, #{author},#{createTime}, #{views}); </insert> </mapper>
-
测试类插入数据
public class MyTest { @Test public void testaddBlog(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); Blog blog = new Blog(); blog.setId(IDUtils.getId()); blog.setTitle("学习JavaEE"); blog.setAuthor("张三"); blog.setCreateTime(new Date()); blog.setViews(9999); mapper.addBlog(blog); blog.setId(IDUtils.getId()); blog.setTitle("学习Mybatis"); blog.setViews(1111); mapper.addBlog(blog); blog.setId(IDUtils.getId()); blog.setTitle("学习Spring"); blog.setViews(5555); mapper.addBlog(blog); blog.setId(IDUtils.getId()); blog.setTitle("学习Springboot"); blog.setViews(7777); mapper.addBlog(blog); sqlSession.close(); } }
-
2、IF的使用
-
BlogMapper接口
public interface BlogMapper { //查询Blog List<Blog> queryBlogIF(Map map); }
-
BlogMapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.ping.dao.BlogMapper"> <select id="queryBlogIF" parameterType="map" resultType="blog"> select * from blog where 1=1 <if test="title != null"> and title = #{title} </if> <if test="author != null"> and author = #{author} </if> </select> </mapper>
-
测试类
public class MyTest { @Test public void testqueryBlogIF(){ 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(); } }
3、choose(when,otherwise)的使用
- 不使用所有的条件,而只是从多个条件中选择一个使用
<select id="queryBlogChoose" parameterType="map" resultType="Blog">
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>
4、trim、where、set的使用
-
where标签
- where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
- 使用where标签修改12.2中BlogMapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.ping.dao.BlogMapper"> <select id="queryBlogIF" parameterType="map" resultType="blog"> select * from blog <where> <if test="title != null"> title = #{title} </if> <if test="author != null"> and author = #{author} </if> </where> </select> </mapper>
-
set标签
- set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)
<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标签
-
自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:
<trim prefix="WHERE" prefixOverrides="AND |OR "> ... </trim> <!--prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。-->
-
与 set 元素等价的自定义 trim 元素
<trim prefix="SET" suffixOverrides=","> ... </trim> <!--覆盖了后缀值设置,并且自定义了前缀值。 -->
-
5、SQL片段
-
有的时候,可能会将一些功能的SQL语句抽取出来,方便复用
- 使用SQL标签抽取公共的部分
- 在需要使用的地方使用include标签引用即可
-
使用SOL片段修改12.2中BlogMapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.ping.dao.BlogMapper"> <!--使用SQL标签抽取公共的部分--> <sql id="if-title-author"> <if test="title != null"> and title = #{title} </if> <if test="author != null"> and author = #{author} </if> </sql> <!--在需要使用的地方使用**include**标签引用即可--> <select id="queryBlogIF" parameterType="map" resultType="blog"> select * from blog <where> <include refid="if-title-author" /> </where> </select> </mapper>
-
注意事项
- 最好基于单表来定义SQL片段
- 不要存在where标签
6、foreach
-
数据
-
Mapper接口
public interface BlogMapper { //查询1,2,3号记录的Blog List<Blog> queryBlogForeach(Map map); }
-
Mapper.xml文件
<!--实现sql语句:select * from blog where 1=1 and (id=1 or id = 2 or id=3)--> <select id="queryBlogForeach" parameterType="map" resultType="blog"> select * from blog <where> <foreach collection="ids" item="id" open="and (" close=")" separator="or"> id = #{id} </foreach> </where> </select> <!--foreach 指定一个集合【collection="ids"】,声明可以在元素体内使用的集合项【item="id"】和索引(index)变量。也允许指定开头 【open="and ("】 与结尾 【close=")"】 的字符串以及集合项迭代之间的分隔符 【separator="or"】。 -->
-
测试类
@Test public void testqueryBlogForeach(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); ArrayList<Integer> ids = new ArrayList<>(); ids.add(1); ids.add(2); ids.add(3); map.put("ids",ids); List<Blog> blogs = mapper.queryBlogForeach(map); for (Blog blog : blogs) { System.out.println(blog); } sqlSession.close(); }
-
测试查询结果