目录
多表查询
查询文章详情
查询一个用户底下的所有文章
动态SQL的使用
if 标签
trim 标签
where 标签
set 标签
foreach 标签
多表查询
现在有俩张表,一张是文章表,一张是用户表.如下:
查询文章详情
我们现在想查询得到一张表,表里面的内容和文章表大多一致,只是要在文章表的基础上添加用户表中的username字段,这就需要多表联查来实现
用户类(用户表的映射)
@Data
public class UserEntity {
private int id;
private String username;
private String password;
private String photo;
private LocalDateTime createtime;
private LocalDateTime updatetime;
private int state;
}
文章类(文章表的映射)
@Data
public class ArticleInfo {
private Integer id;
private String title;
private String content;
private LocalDateTime createtime;
private LocalDateTime updatetime;
private Integer uid;
private Integer rcount;
private int state;
}
文章表拓展(文章表加上用户表中的username字段的表)
public class ArticleInfoVO extends ArticleInfo {
private String username;
//Lombok的toString方法默认是不打印父类的属性的,所以这里我们要重写toString方法
@Override
public String toString() {
return "ArticleInfoVO{" +
"username='" + username + '\'' +
"} " + super.toString();
}
}
这里因为Lombok的toString方法默认是不打印父类属性的,所以我们进行了重写(方便后续打印观察结果)
实现mapper接口
@Mapper
public interface ArticleMapper {
//查询文章详情
ArticleInfoVO getDetail(@Param("id") Integer id);
}
实现对应的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.example.demo.mapper.ArticleMapper">
<select id="getDetail" resultType="com.example.demo.entity.vo.ArticleInfoVO">
select a.*,u.username from articleinfo a
left join userinfo u on u.id = a.uid
where a.id=#{id}
</select>
</mapper>
单元测试
@SpringBootTest
class ArticleMapperTest {
@Autowired
private ArticleMapper articleMapper;
@Test
void getDetail() {
ArticleInfoVO articleInfoVO = articleMapper.getDetail(1);
System.out.println(articleInfoVO);
}
}
结果
查询一个用户底下的所有文章
主表依然是文章表,对文章表先插入几条数据
mapper接口
@Mapper
public interface ArticleMapper {
List<ArticleInfoVO> getArticleByUid(@Param("uid")Integer uid);
}
xml
<select id="getArticleByUid" resultType="com.example.demo.entity.vo.ArticleInfoVO">
select a.*,u.username from articleinfo a
left join userinfo u on u.id = a.uid
where a.uid = #{uid}
</select>
单元测试
@Test
void getArticleByUid() {
Integer uid = 1;
List<ArticleInfoVO> list = articleMapper.getArticleByUid(uid);
list.stream().forEach(System.out::println);
}
结果
动态SQL的使用
动态SQL:允许我们在xml中写一些逻辑判断,来实现sql语句的拼接
例如,在我们填写表单的时候,一些字段是必须要填的,一些字段是非必须填的,我们要如何实现呢?
难点在于对于一些非必填的字段,我们如何写插入的sql语句,这些字段是写在sql语句中怎么实现,用户填写这个字段的时候要写,不填写这个字段的时候又不需要写.
if 标签
现在要上传用户信息,我们需要传递username,password,photo这个三个字段,这其中username和password是必填的,photo是可填可不填的,我应该如何实现呢?
mapper
int addUser2(UserEntity user);
xml
<insert id="addUser2">
insert into userinfo(username,password
<if test="photo != null">
,photo
</if>
)values(#{username},#{password}
<if test="photo != null">
,#{photo}
</if>
)
</insert>
if标签必须要有test(判断条件),这里面除了要写到sql语句中的属性,我们可以直接拿到程序中的参数,而写入到sql语句中就需要使用#{},${}等方式获取参数.
单元测试
@Transactional
@Test
void addUser2() {
String username = "宝宝";
String password = "123456";
UserEntity user = new UserEntity();
user.setUsername(username);
user.setPassword(password);
int result = userMapper.addUser2(user);
System.out.println(result);
}
结果
可以看到我们传入username和password生成的sql语句就只有这俩个字段
@Transactional
@Test
void addUser2() {
String username = "宝宝";
String password = "123456";
UserEntity user = new UserEntity();
user.setUsername(username);
user.setPassword(password);
user.setPhoto("cat.png");
int result = userMapper.addUser2(user);
System.out.println(result);
}
可以看到同样的代码,我们这次多传入了photo属性,此时生成的sql语句就有username,password,photo字段了
trim 标签
上面这个例子,如果username,password,photo都是非必填的(sql语句中的逗号不好处理),此时就需要<trim>标签了
<trim>标签的属性
prefix: 表示整个语句块,以prefix的值为前缀
suffix: 表示整个语句块,以suffix的值为后缀
prefixOverrides: 表示整个语句块要去除掉的前缀
suffixOverrides: 表示整个语句块要去除掉的后缀
现在username,password,photo字段都为非必填,我们要如何实现?
mapper
int addUser3(UserEntity user);
xml
<insert id="addUser3">
insert into userinfo
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="username != null">
username,
</if>
<if test="password != null">
password,
</if>
<if test="photo != null">
photo
</if>
</trim>
values
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="username != null">
#{username},
</if>
<if test="password != null">
#{password},
</if>
<if test="photo != null">
#{photo}
</if>
</trim>
</insert>
单元测试
@Transactional
@Test
void addUser3() {
String username = "白杨";
String password = "123456";
UserEntity user = new UserEntity();
user.setUsername(username);
user.setPassword(password);
int result = userMapper.addUser3(user);
System.out.println(result);
}
结果
where 标签
想象一下这种场景:当我们在搜索框输入文章标题的时候,搜索引擎会根据这个标题查询,但是这个标题不是必须填的,我们也可以不输入文章标题只是输入了文章标题,搜索引擎会根据标题查询,我们要如何实现这个功能呢?
例如现在在搜索框可以输入标题或者id,或者什么都不输入
mapper
List<ArticleInfoVO> getListByIdOrTitle(@Param("id")Integer id,@Param("title")String title);
xml
<select id="getListByIdOrTitle" resultType="com.example.demo.entity.vo.ArticleInfoVO">
select * from articleinfo
<where>
<if test="id!=null and id>0">
id = #{id}
</if>
<if test="title!=null">
and title like concat('%',#{title},'%')
</if>
</where>
</select>
使用了where标签的好处:1.如果我们什么都没传,where后面的判断语句都为Null,此时where标签会自动帮我们去掉where.2.当我们只传了一部分,where标签会自动帮我们去掉前缀and
单元测试
@Test
void getListByIdOrTitle() {
List<ArticleInfoVO> list = articleMapper.getListByIdOrTitle(null,null);
System.out.println(list.size());
}
此时我们什么都没传,生成的sql语句没有where
@Test
void getListByIdOrTitle() {
List<ArticleInfoVO> list = articleMapper.getListByIdOrTitle(null,"C语言");
System.out.println(list.size());
}
此时我们传入了标题"C语言",这时生成的sql就有了where判断语句, 且自动帮我们去掉了and
set 标签
和where标签很像,当我set标签里面有信息,生成的sql语句就会生成set去修改内容(set会自动帮我们去掉最后一个","),如果set标签里面没有信息,生成的sql语句就没有set
foreach 标签
<foreach>标签允许我们传入一个集合
<foreach>标签属性
collection: 绑定方法参数中的集合,如List,Set,Map或数组对象
item:遍历时的每一个对象
open:语句块开头的字符串
close:语句块结束的字符串
separator:每次遍历之间间隔的字符串
利用foreach标签来进行批量删除
mapper
// 根据文章id集合批量删除文章
int deleteByIdList(@Param("idList")List<Integer> idList);
xml
<delete id="deleteByIdList">
delete from articleinfo
where id in
<foreach collection="idList" item="id" open="(" close=")" separator="," >
#{id}
</foreach>
</delete>
单元测试
@Transactional
@Test
void deleteByIdList() {
List<Integer> idList = new ArrayList<>();
idList.add(1);
idList.add(2);
idList.add(3);
int result = articleMapper.deleteByIdList(idList);
System.out.println(result);
}
结果