目录
- 一.多表查询
- [二.MyBatis参数赋值(#{ }和{ })](#{ }和{ }))
-
- [2.1 #{ }和{ }的使用](#{ }和{ }的使用)
- [2.2 #{ }和{ }的区别](#{ }和{ }的区别)
- [2.3 SQL注入](#2.3 SQL注入)
- [2.3 { }的应用场景](#2.3 { }的应用场景)
-
- [2.3.1 排序功能](#2.3.1 排序功能)
- [2.3.2 like查询](#2.3.2 like查询)
一.多表查询
多表查询的操作和单表查询基本相同,只需改变一下SQL语句,同时也要在实体类中创建出关联表
的相应字段
,让Mybatis将查询的结果进行映射,以下是一个多表查询的示例
- 实体类(ArticleInfo)
java
import lombok.Data;
import java.util.Date;
@Data
public class ArticleInfo {
// 文章相关信息
private Integer id;
private String title;
private String content;
private Integer uid;
private Integer deleteFlag;
private Date createTime;
private Date updateTime;
// 用户相关信息
private String userName;
private Integer age;
private Integer gender;
}
- Mapper接口(ArticleInfoXMLMapper)与测试方法
java
// Mapper接口
import org.apache.ibatis.annotations.Mapper;
import org.example.mybatisdemo.model.ArticleInfo;
@Mapper
public interface ArticleInfoXMLMapper {
ArticleInfo queryArticleInfo(Integer id);
}
// 测试方法
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class ArticleInfoXMLMapperTest {
@Autowired
private ArticleInfoXMLMapper articleInfoXMLMapper;
@Test
void queryArticleInfo() {
System.out.println(articleInfoXMLMapper.queryArticleInfo(1));
}
}
- XML文件(ArticleInfoMapper.xml)
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="org.example.mybatisdemo.mapper.ArticleInfoXMLMapper">
<select id="queryArticleInfo" resultType="org.example.mybatisdemo.model.ArticleInfo">
select * from articleinfo ta left join userinfo tb on ta.uid= tb.id where tb.id=#{id}
</select>
</mapper>

二.MyBatis参数赋值(#{ }和${ })
在之前的操作中,我们一直都是使用#{ }来在将参数赋值到SQL语句中,其实在MyBatis中,参数赋值的方式有两种,一种就是我们使用的#{ }
,而另一种是使用${ }
2.1 #{ }和${ }的使用
我们分别使用#{ }和${ }来赋值不同类型的参数(Integer和String),观察相应的MyBatis日志
- Integer类型的参数(上图为#{ },下图为${ })
- String类型的参数(上图为#{ },下图为{ })


通过观察MyBatis日志,可以发现#{ }使用的是预编译SQL,通过 `? 站位`的方式提前对SQL进行编译,然后把参数填充到SQL语句中,并且#{ }会根据参数类型,`自动`给参数`添加引号`,而使用{ }进行参数赋值时会直接进行
字符替换
,如果参数是字符串类型的,需要加上手动添加引号
,否则会报错(SQL语句语法错误)
2.2 #{ }和${ }的区别
- #{ }使用的是
预编译SQL
,而${ }使用的是即时SQL
- #{ }性能更高,在大部分情况下,某一条SQL语可能会被反复调用执行,或者每次执行时只有个别的值是不同的(比如insert语句的values值不同,update语句的set子句值不同),如果每次都需要经过语法分析,SQL优化,编译等,效率就会大幅降低,预编译SQL很大程度上解决了这个问题,在编译之后会将
SQL语句缓存起来
,后续在执行这条语句时,不会再次编译,省去了解析优化等过程,提高了效率 - #{ }更安全,可以防止SQL注入(下面会介绍)
2.3 SQL注入
在使用${ }时,可能会出现SQL注入问题,SQL注入就是通过输入的数据来修改
事先定义好的SQL语句,以达到执行代码对服务器进行攻击
的方法
java
// 测试方法
import org.example.mybatisdemo.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class UserInfoXMLMapperTest {
@Autowired
private UserInfoXMLMapper userInfoXMLMapper;
@Test
void queryUserInfos() {
userInfoXMLMapper.queryUserInfos("'' or 1='1'").forEach(System.out::println);
}
}

当我们给参数后添加一个or 1='1'
时,此时替换到SQL语句中,因为1='1'语句为true,即永真
,导致整个
用户表的内容都被返回,如果这是在实际的登录场景中且后端代码中使用了${ },在登录时密码输入or 1='1'就有可能完成登录,试想一下,不用密码就可以登录,这是何等大的一个漏洞
2.3 ${ }的应用场景
虽然${ }存在着SQL注入的风险,但它其实也有自己的应用场景,以下是对其场景的一个简单介绍
2.3.1 排序功能
- Mapper接口和测试方法
java
// Mapper接口
import org.apache.ibatis.annotations.Mapper;
import org.example.mybatisdemo.model.UserInfo;
import java.util.List;
@Mapper
public interface UserInfoXMLMapper {
List<UserInfo> queryUserInfoBySort(String sort);
}
//测试方法
import org.example.mybatisdemo.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class UserInfoXMLMapperTest {
@Autowired
private UserInfoXMLMapper userInfoXMLMapper;
@Test
void queryUserInfoBySort() {
userInfoXMLMapper.queryUserInfoBySort("DESC").forEach(System.out::println);
}
}
- XML文件
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="org.example.mybatisdemo.mapper.UserInfoXMLMapper">
<select id="queryUserInfoBySort" resultType="org.example.mybatisdemo.model.UserInfo">
select * from userinfo order by id ${sort}
</select>
</mapper>

当我们要赋值到SQL语句中的参数为排序的顺序时,使用${ }进行赋值可以正常进行,而#{ }就会出现错误,因为在SQL语句中,排序规则(DESC,ASC)不需要加引号,而因为参数是String类型,使用#{ }赋值时自动添加了引号,从而导致SQL语句出现语法错误
2.3.2 like查询
- Mapper接口和测试方法
java
// Mapper接口
import org.apache.ibatis.annotations.Mapper;
import org.example.mybatisdemo.model.UserInfo;
import java.util.List;
@Mapper
public interface UserInfoXMLMapper {
List<UserInfo> queryUserInfoByKey(String key);
}
// 测试方法
import org.example.mybatisdemo.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class UserInfoXMLMapperTest {
@Autowired
private UserInfoXMLMapper userInfoXMLMapper;
@Test
void queryUserInfoByKey() {
userInfoXMLMapper.queryUserInfoByKey("zhang").forEach(System.out::println);
}
}
- XML文件
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="org.example.mybatisdemo.mapper.UserInfoXMLMapper">
<select id="queryUserInfoByKey" resultType="org.example.mybatisdemo.model.UserInfo">
select * from userinfo where username like '%${key}%'
</select>
</mapper>

同样对于like语句,我们使用{ }进行赋值可以正常执行,而如果使用#{ }就会出现错误,因为这里也不需要自动添加引号,添加引号就会导致SQL语句出现语法错误,但是这种SQL语句的写法同样存在一定问题,因为使用了{ },所以可能会有SQL注入
问题,更好的写法是使用Mysql内置的concat()函数
来进行处理
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="org.example.mybatisdemo.mapper.UserInfoXMLMapper">
<select id="queryUserInfoByKey" resultType="org.example.mybatisdemo.model.UserInfo">
select * from userinfo where username like concat('%',#{key},'%')
</select>
</mapper>
