MyBatis06:动态SQL
动态SQL指的是根据不同的查询条件 , 生成不同的Sql语句
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
搭建环境
数据库文件
CREATE TABLE `blog`(
`id` VARCHAR(50) NOT NULL,
`title` VARCHAR(100) NOT NULL,
`author` VARCHAR(30) NOT NULL,
`create_time` DATETIME NOT NULL,
`views` INT(30) NOT NULL
)ENGINE=INNODB DEFAULT CHARSET=utf8;
新建普通maven项目
依赖和资源过滤pom.xml
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.4.2</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
</plugins>
</build>
连接数据库
db.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8
username=root
password=123456
mybatis-config.xml
<?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="mapUnderscoreToCamelCase" value="true"/>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<typeAliases>
<package name="com.wgg.pojo"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<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.xml-->
<mappers>
<mapper resource="mapper/BlogMapper.xml"/>
</mappers>
</configuration>
工具类
IDUtils
//返回随机id的字符串
public class IDUtil {
public static String genId() {
return UUID.randomUUID().toString().replaceAll("-", "");
}
}
MybatisUtils获取连接
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
String resource="mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory= new SqlSessionFactoryBuilder().build(inputStream);
}catch (IOException e){
e.printStackTrace();
}
}
//获取sqlSession连接
public static SqlSession getSession(){
return sqlSessionFactory.openSession();
}
}
实体类
@Data
public class Blog {
private String id;
private String title;
private String author;
private Date createTime;
private int views;
}
BlogMapper接口
public interface BlogMapper {
int addBlog(Blog blog);
}
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.wgg.mapper.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 addInitBlog(){
SqlSession session = MybatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = new Blog();
blog.setId(IDUtil.genId());
blog.setTitle("mybatis如此简单");
blog.setAuthor("大神");
blog.setCreateTime(new Date());
blog.setViews(9999);
mapper.addBlog(blog);
blog.setId(IDUtil.genId());
blog.setTitle("Java如此简单");
mapper.addBlog(blog);
blog.setId(IDUtil.genId());
blog.setTitle("Spring如此简单");
mapper.addBlog(blog);
blog.setId(IDUtil.genId());
blog.setTitle("微服务如此简单");
mapper.addBlog(blog);
session.close();
}
}
if语句
根据title和author来查询博客,某一项可为空
select * from blog where title = #{title} and author = #{author}
接口
List<Blog> queryBlogIf(Map map);
sql语句
<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>
</select>
测试
@Test
public void testQueryBlogIf(){
SqlSession session = MybatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
HashMap<String, String> map = new HashMap<String, String>();
map.put("title","Mybatis如此简单");
map.put("author","大神");
List<Blog> blogs = mapper.queryBlogIf(map);
System.out.println(blogs);
session.close();
}
问题:
当title为空时sql语句为
select * from blog where and author = #{author}
发生错误
使用where解决
<select id="queryBlogIf" parameterType="map" resultType="blog">
select * from blog where
<where>
<if test="title!=null">
title=#{title}
</if>
<if test="author!=null">
and author =#{author}
</if>
</where>
</select>
这个“where”标签会知道如果它包含的标签中有返回值的话,它就插入一个‘where’。此外,如果标签返回的内容是以AND 或OR 开头的,则它会剔除掉。
set
接口
int updateBlog(Map map);
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>
测试
@Test
public void testUpdateBlog(){
SqlSession session = MybatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
HashMap<String, String> map = new HashMap<String, String>();
map.put("title","动态SQL");
map.put("author","学霸");
map.put("id","75650df9fcd447f591f6a17a34b41f41");
mapper.updateBlog(map);
session.close();
}
choose
不想用到所有的查询条件,只想选择其中的一个,查询条件有一个满足即可
类似:switch
接口
List<Blog> queryBlogChoose(Map map);
sql
<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>
测试
@Test
public void testQuryBlogChoose(){
SqlSession session = MybatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("title","Java如此简单");
map.put("author","大神");
map.put("views",999);
List<Blog> blogs = mapper.queryBlogChoose(map);
System.out.println(blogs);
session.close();
}
SQL片段
抽取sql语句实现重用
- 引用的sql不在同一文件时需要使用namespace
- 建议单表中使用
- sql片段中不包含
<where>
<sql id="if-title-author">
<if test="title!=nul">
title=#{title}
</if>
<if test="author!=null">
and author=#{author}
</if>
</sql>
<select id="queryBlogIf" parameterType="map" resultType="blog">
select * from blog where
<where>
/*引用*/
<include refid="if-title-author"></include>
</where>
</select>
ForEeach
接口
List<Blog> queryBlogForeach(Map map);
初始的sql语句
select * from blog where 1=1 and (id=1 or id=2 or id=3)
sql语句
<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>
测试
@Test
public void testQueryBlogForeach(){
SqlSession session = MybatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
HashMap map = new HashMap();
List<Integer> ids = new ArrayList<Integer>();
ids.add(1);
ids.add(2);
ids.add(3);
map.put("ids",ids);
List<Blog> blogs = mapper.queryBlogForeach(map);
System.out.println(blogs);
session.close();
}