目錄
- 一.多表查詢
- 二.MyBatis參數賦值(#{ }和${ })
- 2.1 #{ }和${ }的使用
- 2.2 #{ }和${ }的區別
- 2.3 SQL注入
- 2.3 ${ }的應用場景
- 2.3.1 排序功能
- 2.3.2 like查詢
一.多表查詢
多表查詢的操作和單表查詢基本相同,只需改變一下SQL語句,同時也要在實體類中創建出關聯表
的相應字段
,讓Mybatis將查詢的結果進行映射,以下是一個多表查詢的示例
- 實體類(ArticleInfo)
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)與測試方法
// 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 {@Autowiredprivate ArticleInfoXMLMapper articleInfoXMLMapper;@Testvoid queryArticleInfo() {System.out.println(articleInfoXMLMapper.queryArticleInfo(1));}
}
- XML文件(ArticleInfoMapper.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語句,以達到執行代碼對服務器進行攻擊
的方法
// 測試方法
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 {@Autowiredprivate UserInfoXMLMapper userInfoXMLMapper;@Testvoid 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接口和測試方法
// 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 {@Autowiredprivate UserInfoXMLMapper userInfoXMLMapper;@Testvoid queryUserInfoBySort() {userInfoXMLMapper.queryUserInfoBySort("DESC").forEach(System.out::println);}
}
- 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接口和測試方法
// 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 {@Autowiredprivate UserInfoXMLMapper userInfoXMLMapper;@Testvoid queryUserInfoByKey() {userInfoXMLMapper.queryUserInfoByKey("zhang").forEach(System.out::println);}
}
- 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 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>