国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Java EE 突擊 13 - MyBatis 查詢數(shù)據(jù)庫(kù)(2)

這篇具有很好參考價(jià)值的文章主要介紹了Java EE 突擊 13 - MyBatis 查詢數(shù)據(jù)庫(kù)(2)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

這個(gè)專欄給大家介紹一下 Java 家族的核心產(chǎn)品 - SSM 框架
JavaEE 進(jìn)階專欄

Java 語(yǔ)言能走到現(xiàn)在 , 仍然屹立不衰的原因 , 有一部分就是因?yàn)?SSM 框架的存在

接下來(lái) , 博主會(huì)帶大家了解一下 Spring、Spring Boot、Spring MVC、MyBatis 相關(guān)知識(shí)點(diǎn)

并且?guī)ьI(lǐng)大家進(jìn)行環(huán)境的配置 , 讓大家真正用好框架、學(xué)懂框架

來(lái)上一篇文章復(fù)習(xí)一下吧
點(diǎn)擊即可跳轉(zhuǎn)到前置文章
CSDN 平臺(tái)觀感有限 , 可以私聊作者獲取源筆記鏈接
Java EE 突擊 13 - MyBatis 查詢數(shù)據(jù)庫(kù)(2),JavaEE 進(jìn)階,java-ee,mybatis,java

七 . 查詢操作

7.1 單表查詢

7.1.1 參數(shù)占位符 : #{} 和 ${}

我們之前介紹過(guò) : 傳參的時(shí)候使用 #{}

這種情況適用于 99.99% 的情況 , 但是還有 0.01% 的情況是使用不了 #{} 的
這也是一道非常經(jīng)典的面試題 !!!
我們通過(guò) getUserById 來(lái)舉例 :
[外鏈圖片轉(zhuǎn)存中…(img-lZFq1WJB-1692756514196)]
我們通過(guò)單元測(cè)試來(lái)看一下 , 目前這個(gè)查詢有無(wú)問(wèn)題
image.png
那我們接下來(lái) , 把 #{id} 替換成 ${id}
[外鏈圖片轉(zhuǎn)存中…(img-WpAtZwlE-1692756514197)]
這不都運(yùn)行成功了嗎 ? 那他們倆能有什么區(qū)別 ?
在 int 類型的傳參中 , #{} 和 ${} 是一樣的 , 但是二者在字符串類型的時(shí)候就不同了 .
接下來(lái) , 給大家實(shí)驗(yàn)一下 , 我們?cè)?UserMapper 里面添加一個(gè)方法 : 根據(jù)用戶名查詢用戶

package com.example.demo.mapper;

import com.example.demo.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

// MyBatis 接口,此注解一定不能省略
@Mapper
public interface UserMapper {
    // 根據(jù)用戶姓名查詢用戶
    public UserInfo getUserByName(@Param("username") String username);
}

[外鏈圖片轉(zhuǎn)存中…(img-8tt4Xp9Y-1692756514197)]
接下來(lái) , 我們?nèi)?UserMapper.xml 里面編寫 SQL 語(yǔ)句

<?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.UserMapper">
  <select id="getUserByName" resultType="com.example.demo.model.UserInfo">
    select * from userinfo where username = #{username}
  </select>
</mapper>

接下來(lái) , 我們?nèi)?UserMapper 里面去生成對(duì)應(yīng)的單元測(cè)試
[外鏈圖片轉(zhuǎn)存中…(img-2clTLWJL-1692756514197)]
[外鏈圖片轉(zhuǎn)存中…(img-8aSTt11x-1692756514198)]
[外鏈圖片轉(zhuǎn)存中…(img-RA34kBzR-1692756514199)]

package com.example.demo.mapper;

import com.example.demo.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest // 當(dāng)前測(cè)試的上下文環(huán)境為 Spring Boot
class UserMapperTest {

    // 要測(cè)試誰(shuí) , 就注入誰(shuí)
    @Autowired
    private UserMapper userMapper;

    @Test
    void getUserByName() {
        UserInfo userInfo = userMapper.getUserByName("admin");
        System.out.println(userInfo);
    }
}

[外鏈圖片轉(zhuǎn)存中…(img-NCfrBRLt-1692756514199)]
那我們把 #{} 改成 ${} 試試看
就報(bào)錯(cuò)了
[外鏈圖片轉(zhuǎn)存中…(img-plzsJeYu-1692756514200)]
那我們回到 MySQL 里面 , 嘗試去搜索 admin 這個(gè)用戶 , 能夠正常搜索到 .

select * from userinfo where name = 'admin';

[外鏈圖片轉(zhuǎn)存中…(img-ludyzF1G-1692756514201)]
但是我們把 admin 外面的單引號(hào)去掉之后就會(huì)報(bào)錯(cuò)
[外鏈圖片轉(zhuǎn)存中…(img-ngbM0Sde-1692756514201)]
而且這個(gè)報(bào)錯(cuò)信息跟我們程序中的報(bào)錯(cuò)信息一致
[外鏈圖片轉(zhuǎn)存中…(img-ZGEh2hF7-1692756514201)]
我們就可以把 ${} 當(dāng)成這樣的 SQL 語(yǔ)句

select * from userinfo where username = admin; -- 注意:這個(gè) admin 沒(méi)加單引號(hào)

這樣的話 , MySQL 就會(huì)誤以為是 username 字段與 admin 字段進(jìn)行比較 , 但是并未找到 admin 字段 , 所以就報(bào)錯(cuò)了 .
我們之前實(shí)驗(yàn) int 類型的數(shù)據(jù)之所以沒(méi)錯(cuò) , 是因?yàn)槲覀兊?SQL 語(yǔ)句被替換成了這樣 :

select * from userinfo where username = 1; -- 這樣寫, MySQL 就會(huì)以為是判斷 username 是否等于1 , 就不會(huì)報(bào)錯(cuò)了

所以這個(gè)就是 #{} 和 ${} 之間的區(qū)別
#{} : 預(yù)編譯進(jìn)行處理

與之前講的 JDBC 里面的 ? 類似 , #{} 就是事先占一個(gè)位置的 , 這個(gè)位置有可能是 int 類型的 , 也有可能是 String 類型的 , 占了這個(gè)位置 , 這一列是什么 , 預(yù)編譯的這個(gè)位置類型就已經(jīng)確定 , 在執(zhí)行的時(shí)候就不會(huì)發(fā)生報(bào)錯(cuò)了 .
e.g. 假如說(shuō)我們現(xiàn)在的 SQL 語(yǔ)句長(zhǎng)這樣

select * from user where username = ?;

我們要往 ? 里面填充數(shù)據(jù) , 但是我們提前知道 ? 這個(gè)位置是 String 類型 , 所以在對(duì)比的時(shí)候不會(huì)發(fā)生問(wèn)題的 , 就相當(dāng)于公司聚會(huì) , 馬云爸爸的位置還有馬哥的位置為了避免尷尬 , 提前就規(guī)定好了座位 .
[外鏈圖片轉(zhuǎn)存中…(img-k2Xfav5E-1692756514202)]

${} : 字符直接替換

屬于那種小公司 , 誰(shuí)先來(lái)誰(shuí)先找座 , 不講究那些亂碼七遭的說(shuō)頭

小結(jié)一下 :
#{} 就相當(dāng)于自己能分辨數(shù)據(jù)類型 , 比如 String 類型的數(shù)據(jù) , #{} 自己就知道加單引號(hào)
而 ${} 不是 , ${} 就相當(dāng)于一個(gè)空位置 , 誰(shuí)來(lái)誰(shuí)上不添加任何修飾
所以我們傳過(guò)去 String 類型的數(shù)據(jù)后
#{} 就知道把數(shù)據(jù)用單引號(hào)括起來(lái)表示這是字符串

select * from userinfo where username = 'admin'; -- 單引號(hào)是 #{} 主動(dòng)去添加的

${} 就是什么也不做

select * from userinfo where username = admin; -- ${} 不會(huì)進(jìn)行任何修飾

我們要是想讓 ${} 的方式成功 , 我們需要自己去添加單引號(hào)
[外鏈圖片轉(zhuǎn)存中…(img-B35wR1Ks-1692756514202)]

? 那我們以后所有的查詢都用單引號(hào)包裹起來(lái)不就得了 ?
? 是不可以的 . 雖然通過(guò)這種方式也能夠查詢到數(shù)據(jù)
[外鏈圖片轉(zhuǎn)存中…(img-u8YX41bO-1692756514202)]
但是這種查詢是發(fā)生了隱式類型轉(zhuǎn)換的 , 這種方式就不能去走索引了 , 性能就會(huì)大大降低 .
目前是數(shù)據(jù)量少 , 如果我們?cè)诰€上環(huán)境 , 執(zhí)行速度慢的就會(huì)非常明顯了 .

但是剛才我們說(shuō) 還有 0.01 {} 還有 0.01% 的情況 , 肯定還是有它自己存在的價(jià)值的 , 它的價(jià)值就在于使用直接替換 ( 還有0.01{}) 的這種形式可以 傳遞/執(zhí)行 MySQL 的關(guān)鍵字
舉個(gè)栗子 :
image.png
排序的時(shí)候 , 有兩種情況 , 價(jià)格從低到高 / 價(jià)格從高到低 , 這是一種規(guī)則 .
? 那我們點(diǎn)這里的時(shí)候 , 傳過(guò)去的數(shù)據(jù)是什么 ?
? 傳過(guò)去的就是排序的規(guī)則 , 排序的規(guī)則屬于 MySQL 的關(guān)鍵字 , 在 MySQL 中 , 排序的語(yǔ)句如下圖
[外鏈圖片轉(zhuǎn)存中…(img-6MH6dt2I-1692756514203)]
那我們點(diǎn)擊價(jià)格從高到底 , 傳過(guò)去的就是 desc 關(guān)鍵字 .
點(diǎn)擊價(jià)格從低到高 , 傳過(guò)去的就是 asc 關(guān)鍵字 .
我們自己來(lái)設(shè)計(jì)一個(gè)例子 :
在 UserMapper 里面寫一個(gè)方法聲明 : 查詢所有的信息(按價(jià)格排序)

package com.example.demo.mapper;

import com.example.demo.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

// MyBatis 接口,此注解一定不能省略
@Mapper
public interface UserMapper {
    // 按排序條件查詢所有的信息
    public List<UserInfo> getAllByOrder(@Param("order") String order);
}

[外鏈圖片轉(zhuǎn)存中…(img-zJRkuXTI-1692756514203)]
接下來(lái) , 我們?nèi)?UserMapper.xml 中編寫 SQL 語(yǔ)句

<?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.UserMapper">
    <select id="getAllByOrder" resultType="com.example.demo.model.UserInfo">
        select * from userinfo order by id ${}
    </select>
</mapper>

我們?nèi)ゾ帉憜卧獪y(cè)試
[外鏈圖片轉(zhuǎn)存中…(img-nV5s7fx3-1692756514203)]
[外鏈圖片轉(zhuǎn)存中…(img-9TdQgnl8-1692756514203)]
[外鏈圖片轉(zhuǎn)存中…(img-z92ZTKgI-1692756514204)]
為了更方便查看效果 , 我們?cè)?MySQL 中新添加一條數(shù)據(jù)

insert into userinfo (username,password) values ('zhangsan','zhangsan');

[外鏈圖片轉(zhuǎn)存中…(img-SgzoBkdm-1692756514204)]
如果我們使用的是 asc , 或者是 desc , 我們現(xiàn)在數(shù)據(jù)庫(kù)里面查看一下效果
image.png
接下來(lái)我們編寫單元測(cè)試的代碼

package com.example.demo.mapper;

import com.example.demo.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest // 當(dāng)前測(cè)試的上下文環(huán)境為 Spring Boot
class UserMapperTest {

    // 要測(cè)試誰(shuí) , 就注入誰(shuí)
    @Autowired
    private UserMapper userMapper;

    @Test
    void getAllByOrder() {
        List<UserInfo> list = userMapper.getAllByOrder("asc");
        for (UserInfo userInfo : list) {
            System.out.println(userInfo.toString());
        }
    }
}

運(yùn)行一下 :
image.png
這是因?yàn)槲覀兊?#{} 把 SQL 語(yǔ)句優(yōu)化成了這樣

select * from userinfo order by id 'asc';

[外鏈圖片轉(zhuǎn)存中…(img-OltZ6jCM-1692756514205)]
這條 SQL 語(yǔ)句是存在語(yǔ)法問(wèn)題的 , 所以會(huì)報(bào)錯(cuò) .
那我們把 #{} 改成 ${} 試試看 , 就可以了
[外鏈圖片轉(zhuǎn)存中…(img-hdUkl4uC-1692756514205)]
[外鏈圖片轉(zhuǎn)存中…(img-wvWLxNaC-1692756514205)]

7.1.2 SQL 注入問(wèn)題

假如我們有一個(gè)這樣的例子 :
正常的查詢應(yīng)該是這樣 :
image.png
那么什么叫 SQL 注入呢 ?
SQL 注入就是在不知道賬號(hào)密碼的情況下 , 就訪問(wèn)到了你的信息
SQL 注入就是這樣的一個(gè)簡(jiǎn)單字符串 : ' or 1='1'
他利用的就是 SQL 執(zhí)行漏洞
直接來(lái)看運(yùn)行結(jié)果
[外鏈圖片轉(zhuǎn)存中…(img-9RPF7has-1692756514206)]
’ or 1=‘1’ 并不是你真正的密碼啊 , 怎么就獲取到你的信息了呢 ?
[外鏈圖片轉(zhuǎn)存中…(img-fnKbtTKf-1692756514206)]
如果使用了 ${} , 那么程序就會(huì)存在 SQL 注入的問(wèn)題 , 因?yàn)樗麜?huì)把 ’ or 1=‘1’ 當(dāng)成關(guān)鍵字來(lái)去執(zhí)行代碼
而 #{} 不會(huì)存在這種問(wèn)題 , #{} 是預(yù)處理的 , 他會(huì)把 ’ or 1=‘1’ 當(dāng)成密碼來(lái)看 , 不認(rèn)為這一串是 SQL 語(yǔ)句
那我們寫個(gè)代碼來(lái)實(shí)驗(yàn)一下
我們?cè)?UserMapper 里面寫一個(gè)登錄方法

package com.example.demo.mapper;

import com.example.demo.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

// MyBatis 接口,此注解一定不能省略
@Mapper
public interface UserMapper {
    public UserInfo login(@Param("username") String username,
                          @Param("password") String password);
}

接下來(lái) , 我們?cè)?UserMapper.xml 里面編寫 SQL 語(yǔ)句

注意 : 這時(shí)候要保證我們數(shù)據(jù)表里面僅有一條數(shù)據(jù) , 不然會(huì)報(bào)錯(cuò)
因?yàn)槲覀兎祷刂凳欠祷氐膶?duì)象 , 而不是 List
[外鏈圖片轉(zhuǎn)存中…(img-gs7buBy2-1692756514206)]

<?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.UserMapper">
    <select id="login" resultType="com.example.demo.model.UserInfo">
        select * from userinfo where username = ${username} and password = ${password}
    </select>
</mapper>

接下來(lái) , 我們編寫單元測(cè)試
[外鏈圖片轉(zhuǎn)存中…(img-QZ7RbhER-1692756514206)]
image.png
image.png

package com.example.demo.mapper;

import com.example.demo.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest // 當(dāng)前測(cè)試的上下文環(huán)境為 Spring Boot
class UserMapperTest {

    // 要測(cè)試誰(shuí) , 就注入誰(shuí)
    @Autowired
    private UserMapper userMapper;

    @Test
    void login() {
        // 測(cè)試 ${} 的時(shí)候 , 要把賬號(hào)用單引號(hào)括起來(lái)
        // 因?yàn)?${} 識(shí)別字符串的時(shí)候會(huì)把他當(dāng)成 SQL 語(yǔ)句,然后報(bào)錯(cuò)
        String username = "'admin'";
        String password = "'' or 1='1'";//SQL 注入
        UserInfo userInfo = userMapper.login(username, password);
        System.out.println("userinfo ->" + userInfo);
    }
}

[外鏈圖片轉(zhuǎn)存中…(img-sOyG1T5v-1692756514207)]

還可以這樣寫image.png

再測(cè)試 #{}

package com.example.demo.mapper;

import com.example.demo.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest // 當(dāng)前測(cè)試的上下文環(huán)境為 Spring Boot
class UserMapperTest {

    // 要測(cè)試誰(shuí) , 就注入誰(shuí)
    @Autowired
    private UserMapper userMapper;

    @Test
    void login() {
        // 測(cè)試 #{} 的時(shí)候,就不用再加單引號(hào)了
        // 因?yàn)?#{} 會(huì)自動(dòng)幫我們加
        String username = "admin";
        String password = "' or 1='1'";//SQL 注入
        UserInfo userInfo = userMapper.login(username, password);
        System.out.println("userinfo ->" + userInfo);
    }
}

image.png

7.1.3 模糊查詢 : like 查詢

對(duì)于普通的查詢 , 我們使用 #{} 都能搞得定 , 但是模糊查詢比較特殊 , 模糊查詢使用 % 或者 _ 來(lái)指代 0-n 個(gè)字符
本來(lái)我們的 SQL 實(shí)現(xiàn)是這個(gè)樣子

<select id="findUserByName2" resultType="com.example.demo.model.UserInfo">
    select * from userinfo where username like '%#{username}%';
</select>

我們上面使用的是 #{} 的形式 , 他會(huì)自己判斷類型 . 我們這里傳輸過(guò)去的是 String 類型 , 所以實(shí)際的 SQL 就變?yōu)榱?/p>

select * from userinfo where username like '%'username'%'; 
-- username 是字符串類型 , 就自動(dòng)在 username 兩邊加了單引號(hào)

這樣肯定是不可以的
[外鏈圖片轉(zhuǎn)存中…(img-AyM3fFuh-1692756514208)]
但是我們想要實(shí)現(xiàn)的 SQL 是 :

select * from userinfo where username like '%m%';

image.png
那咱們就改成使用 ${} 不就可以了嗎 ? 答案真的有這樣簡(jiǎn)單嗎 ?
其實(shí)是不行的 . 想想之前咱們的淘寶案例 , 傳過(guò)去的是 asc desc 這兩個(gè)關(guān)鍵字 , 這兩個(gè)關(guān)鍵字是可以進(jìn)行窮舉的 , 意思就是我們可以寫兩條 SQL 語(yǔ)句塊來(lái)實(shí)現(xiàn)升序排列以及降序排列 , 然后這兩個(gè)關(guān)鍵字我們是在 Controller 層里面去進(jìn)行參數(shù)校驗(yàn)的 , 參數(shù)校驗(yàn)成功才可以去實(shí)現(xiàn)相對(duì)應(yīng)的功能 .但是用戶名能窮舉嗎 , 他的可能性無(wú)窮無(wú)盡 , 那咱們還能寫無(wú)數(shù)個(gè) SQL 語(yǔ)句塊 ?
這肯定是不行的 , 不過(guò)我們可以通過(guò) SQL 里面的一個(gè)內(nèi)置函數(shù) concat() 來(lái)進(jìn)行處理 ,他可以實(shí)現(xiàn)將多個(gè)字符拼接在一起 ,那我們就把 %#{username}#分成了三個(gè)部分 : % 、#{username} 、# ,這樣的話把他們?nèi)齻€(gè)拼接到一起就可以了

<select id="findUserByName3" resultType="com.example.demo.model.UserInfo">
    select * from userinfo where username like concat('%',#{username},'%')
</select>

那我們來(lái)試驗(yàn)一下 , 先在 UserMapper 里面寫方法聲明

package com.example.demo.mapper;

import com.example.demo.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

// MyBatis 接口,此注解一定不能省略
@Mapper
public interface UserMapper {
    // 模糊查詢
    public UserInfo findUserByName3(@Param("username") String username);
}

然后 UserMapper.xml 我們剛才已經(jīng)寫完了
接下來(lái)完成單元測(cè)試即可
[外鏈圖片轉(zhuǎn)存中…(img-2514weQ0-1692756514208)]
[外鏈圖片轉(zhuǎn)存中…(img-juKFtIJ1-1692756514208)]
[外鏈圖片轉(zhuǎn)存中…(img-kvWM2XxK-1692756514209)]

package com.example.demo.mapper;

import com.example.demo.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest // 當(dāng)前測(cè)試的上下文環(huán)境為 Spring Boot
class UserMapperTest {

    // 要測(cè)試誰(shuí) , 就注入誰(shuí)
    @Autowired
    private UserMapper userMapper;

    @Test
    void findUserByName3() {
        UserInfo userInfo = userMapper.findUserByName3("m");//傳過(guò)去要按哪個(gè)字符/字符串去查找
        System.out.println(userInfo.toString());
    }
}

[外鏈圖片轉(zhuǎn)存中…(img-wSRirPM6-1692756514209)]
用 MySQL 命令行也查到了相關(guān)信息
[外鏈圖片轉(zhuǎn)存中…(img-ymdkh1Li-1692756514209)]

7.2 多表查詢

7.2.1 返回類型 : resultType VS resultMap

我們?cè)谶M(jìn)入公司上班的過(guò)程中 , 肯定會(huì)遇見(jiàn)這樣的問(wèn)題 :
之前我們學(xué)過(guò) , 數(shù)據(jù)庫(kù)的字段名一般通過(guò)下劃線來(lái)分隔 , 比如 user_name
而 Java 語(yǔ)言的規(guī)范是變量的命名使用小駝峰命名法 , 比如 userName
那在公司之后 , 操作數(shù)據(jù)庫(kù)的是一波人 , 他們習(xí)慣變量使用下劃線分隔
那為了與數(shù)據(jù)庫(kù)中的字段名保持一致 , 我們 Java 程序員就不得不低頭 , 也采用下劃線分割的方式 ?
那肯定不行 , 但是不保持一致還查詢不到
[外鏈圖片轉(zhuǎn)存中…(img-dGLjjAiN-1692756514209)]那我們 MyBatis 也考慮到了這個(gè)問(wèn)題 , 就推出了 resultMap , 他的功能與 resultType 一致
resultMap 可以解決程序中實(shí)體類的名稱和數(shù)據(jù)庫(kù)當(dāng)中字段名不一樣的問(wèn)題
那 resultMap 怎樣去使用呢 ?
resultMap 使用起來(lái)相對(duì)麻煩一下 , 他需要在 xml 文件中進(jìn)行配置
我們就可以使用一個(gè) 標(biāo)簽在 xxxMapper.xml 里面進(jìn)行聲明

<resultMap id="BaseMap" type="com.example.demo.model.User">
  <id column="id" property="id"></id>
  <result column="username" property="username"></result>
  <result column="password" property="pwd"></result>
</resultMap>

這段代碼就相當(dāng)于我們定義了一個(gè)返回結(jié)果的字典來(lái)映射數(shù)據(jù)庫(kù)當(dāng)中的字段和實(shí)體類當(dāng)中的屬性
<id column="id" property="id"></id>意思就是把程序中的 id 和數(shù)據(jù)庫(kù)中的 id 匹配上 , 其中 : property 代表的是程序里面的屬性名 , column 代表數(shù)據(jù)庫(kù)里面的字段
<result column="username" property="username"></result>、<result column="password" property="pwd"></result>就是把 username 和 password 匹配上
那我們就可以在 UserMapper.xml 里面去聲明 resultMap 了

<?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.UserMapper">
    <!--  id 的名字無(wú)所謂,甚至可以重復(fù)  -->
    <!--  
        type 代表要映射的哪個(gè)類
        參數(shù)仍然是包名+類名  
    -->
    <resultMap id="BaseMap" type="com.example.demo.model.UserInfo">
        <!-- 
            里面要寫需要映射的字段 
            column 代表數(shù)據(jù)庫(kù)中的字段
            property 代表實(shí)體類當(dāng)中的屬性
        -->
        <!-- 推薦把所有情況都寫上,即使字段名與屬性名是一致的 -->
        <id column="id" property="id"></id> <!-- 這種情況是設(shè)置主鍵 -->
        <!-- 接下來(lái)其他的設(shè)置成普通類型的即可 -->
        <result column="username" property="name"></result>
        <result column="password" property="password"></result>
        <result column="photo" property="photo"></result>
        <result column="createtime" property="createtime"></result>
        <result column="updatetime" property="updatetime"></result>
        <result column="state" property="state"></result>
    </resultMap>

    <select id="getAll" resultType="com.example.demo.model.UserInfo">
        select * from userInfo
    </select>
</mapper>

[外鏈圖片轉(zhuǎn)存中…(img-q2nbdvBl-1692756514210)]
然后我們測(cè)試的是 getAll 方法 ,就需要把 getAll 的方法對(duì)應(yīng)的 xml 實(shí)現(xiàn)里面的 ResultType 刪除掉 ,改成 ResultMap 即可 , 參數(shù)填寫上面的 id
[外鏈圖片轉(zhuǎn)存中…(img-Oj8RyQxC-1692756514210)]
接下來(lái) , 我們就可以去執(zhí)行單元測(cè)試了
[外鏈圖片轉(zhuǎn)存中…(img-S95mEhYZ-1692756514210)]
雖然這樣寫麻煩一些 , 但是他可以解決數(shù)據(jù)庫(kù)字段名與實(shí)體類屬性名不一致的問(wèn)題
[外鏈圖片轉(zhuǎn)存中…(img-msA7kh6F-1692756514210)]

7.2.2 多表查詢

我們的數(shù)據(jù)庫(kù)目前有兩張表 : articleinfo 以及 userinfo
其實(shí)這兩張表是有關(guān)聯(lián)關(guān)系的
[外鏈圖片轉(zhuǎn)存中…(img-nDlRdeb4-1692756514211)]
articleInfo 里面的 uid 對(duì)應(yīng)的就是 userinfo 里面的 id , 這其實(shí)就是一個(gè)外鍵 .
那如果我們想得到所有文章的信息 ,并且得到每篇文章對(duì)應(yīng)的作者的時(shí)候 , 我們就需要采用多表查詢的方式了
在 MyBatis 里面 , 多表查詢?cè)鯓訉?shí)現(xiàn)呢 ?
目前我們的需求就是打印文章表的時(shí)候 , 順便打印作者姓名
所以我們就可以先在文章表對(duì)應(yīng)的實(shí)體類上 , 先添加作者姓名屬性
[外鏈圖片轉(zhuǎn)存中…(img-4eCkQ1Lj-1692756514211)]

package com.example.demo.model;

import lombok.Data;

import java.util.Date;

/**
 * 文章的實(shí)體類
 */
@Data
public class ArticleInfo {
    private int id;
    private String title;
    private String content;
    private Date createtime;
    private Date updatetime;
    private int uid;
    private int rcount;//訪問(wèn)量
    private int state;//狀態(tài)
    
    // 多表查詢
    private String username;//文章作者名 - 來(lái)源于別的表
}

接下來(lái)在 ArticleMapper 里面寫多表聯(lián)合查詢的方法聲明

package com.example.demo.mapper;

import com.example.demo.model.ArticleInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

// 記得添加 @Mapper 注解
@Mapper
public interface ArticleInfoMapper {
    // 查詢文章及其作者信息
    public List<ArticleInfo> getAll();
}

[外鏈圖片轉(zhuǎn)存中…(img-mPfL4vvi-1692756514211)]
接下來(lái)去 ArticleMapper.xml 里面編寫多表聯(lián)合查詢的 SQL 語(yǔ)句

<?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.ArticleInfoMapper">

    <select id="getAll" resultType="com.example.demo.model.ArticleInfo">
        select a.*,u.username from articleinfo as a
        left join userinfo as u
        on a.uid = u.id;
    </select>
</mapper>

[外鏈圖片轉(zhuǎn)存中…(img-L3I5fYB7-1692756514211)]
先去數(shù)據(jù)庫(kù)中看一下我們的 SQL 語(yǔ)句有沒(méi)有問(wèn)題
image.png
沒(méi)有問(wèn)題我們就可以跑單元測(cè)試了
[外鏈圖片轉(zhuǎn)存中…(img-pPmbenXq-1692756514212)]
[外鏈圖片轉(zhuǎn)存中…(img-MYhMRECU-1692756514212)]
[外鏈圖片轉(zhuǎn)存中…(img-D9tMXYsy-1692756514212)]

package com.example.demo.mapper;

import com.example.demo.model.ArticleInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

// 要記得加這個(gè)注解,代表 Spring Boot 的單元測(cè)試
@SpringBootTest
class ArticleInfoMapperTest {

    // 屬性注入
    @Autowired
    private ArticleInfoMapper articleInfoMapper;

    @Test
    void getAll() {
        List<ArticleInfo> list = articleInfoMapper.getAll();
        for (ArticleInfo info : list) {
            System.out.println(info);
        }
    }
}

也成功打印了
image.png
要注意 :
image.png
那我們這兩個(gè)字段的名稱就是對(duì)不上呢 ?
我們有兩種方案 :

  1. 使用 resultMap

我們把 AticleInfo 實(shí)體類里面的 username 屬性改成了 name
image.png
在 ArticleMapper.xml 里面寫 resultMap 標(biāo)簽

<?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.ArticleInfoMapper">
    <!--  
        id 隨便起,可以重復(fù)  
        type 代表要映射的哪個(gè)類
        參數(shù)仍然是包名+類名
    -->
    <resultMap id="BaseMap" type="com.example.demo.model.ArticleInfo">
        <!--   id 代表主鍵     -->
        <id column="id" property="id"></id> <!-- column 代表數(shù)據(jù)庫(kù)字段名,property 代表實(shí)體類屬性名 -->
        <!--   result 代表普通屬性     -->
        <result column="username" property="name"></result>
        <!--   ...     -->
        <!--   其他的省略了     -->
    </resultMap>

    <!--  使用resultMap 解決名字不一樣問(wèn)題  -->
    <!--  要記得將這里面的 resultType 改成 resultMap  -->
    <!--  參數(shù)就是上面寫的 id,也就是 BaseMap  -->
    <select id="getAll" resultMap="BaseMap">
        select a.*,u.username from articleinfo as a
        left join userinfo as u
        on a.uid = u.id;
    </select>
</mapper>

單元測(cè)試運(yùn)行一下
[外鏈圖片轉(zhuǎn)存中…(img-BYVWPDbK-1692756514213)]

  1. 給要查詢的這一列進(jìn)行重命名 , 重命名成你的屬性名

所以我們只需要在 SQL 語(yǔ)句上進(jìn)行重命名操作 (as 關(guān)鍵字)

<?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.ArticleInfoMapper">

    <select id="getAll" resultType="com.example.demo.model.ArticleInfo">
        select a.*,u.username as name from articleinfo as a
        left join userinfo as u
        on a.uid = u.id;
    </select>

</mapper>

[外鏈圖片轉(zhuǎn)存中…(img-t6x03m4p-1692756514214)]

八 . 動(dòng)態(tài) SQL 使用

這里是官方的 動(dòng)態(tài) SQL 文檔 : https://mybatis.org/mybatis-3/zh/dynamic-sql.html
官方 : 動(dòng)態(tài) SQL 是 MyBatis 的強(qiáng)大特性之一。如果你使用過(guò) JDBC 或其它類似的框架,你應(yīng)該能理解根據(jù)不同條件拼接 SQL 語(yǔ)句有多痛苦,例如拼接時(shí)要確保不能忘記添加必要的空格,還要注意去掉列表最后一個(gè)列名的逗號(hào)。利用動(dòng)態(tài) SQL , 可以徹底擺脫這種痛苦。

8.1 標(biāo)簽

MyBatis 主要就是解決必傳參數(shù)以及非必傳參數(shù)的 , 也就是我們常見(jiàn)的必填項(xiàng)與非必填項(xiàng)
[外鏈圖片轉(zhuǎn)存中…(img-66QuD24A-1692756514214)]
標(biāo)簽 這種情況就適用于 : 傳遞的參數(shù)我現(xiàn)在是不確定的 , 有可能有用 , 有可能沒(méi)用 .
我們就可以使用 標(biāo)簽來(lái)進(jìn)行判斷 , 他就會(huì)根據(jù)傳遞的參數(shù)進(jìn)行 SQL 語(yǔ)句拼接
我們用 photo 字段舉例
photo 用戶有可能傳 ,有可能不傳 .
我們先來(lái)模擬一下不使用動(dòng)態(tài)標(biāo)簽的時(shí)候 , SQL 語(yǔ)句的編寫

insert into userinfo (username,password,photo) values ('張三','zhangsan',null);
-- 在沒(méi)有學(xué)習(xí)動(dòng)態(tài)標(biāo)簽的時(shí)候,我們是把可選參數(shù)和必選參數(shù)一起去添加的
-- 前端沒(méi)給我們傳過(guò)來(lái)頭像數(shù)據(jù),那我們就先插入一個(gè) null

如果我們有動(dòng)態(tài)標(biāo)簽了 , 用戶沒(méi)傳頭像 , 那我們插入數(shù)據(jù)就可以不管頭像字段了

insert into userinfo (username,password) values ('李四','lisi');

[外鏈圖片轉(zhuǎn)存中…(img-1Japvhsq-1692756514216)]
NULL 和 空不是一樣的東西 ,所以事情就變得很難搞了
[外鏈圖片轉(zhuǎn)存中…(img-RbrvXyvn-1692756514217)]
想要實(shí)現(xiàn)必選項(xiàng)的問(wèn)題 , 我們就可以使用 標(biāo)簽
語(yǔ)法 :

<if test="photo!=null">
  ...
</if>

如果有多個(gè)位置需要?jiǎng)討B(tài)輸入 , 我們就可以寫多個(gè) 標(biāo)簽
我們來(lái)試驗(yàn)一下 , 以 User的添加舉例

在這里再給大家推薦一個(gè)十分好用的插件 : MyBatisX
[外鏈圖片轉(zhuǎn)存中…(img-2WILAZKT-1692756514217)]
[外鏈圖片轉(zhuǎn)存中…(img-VdmfO0Yn-1692756514217)]
這個(gè)插件的作用就是 :
點(diǎn)擊前面的小鳥 , 就可以跳轉(zhuǎn)到接口聲明或者 xxx.xml 實(shí)現(xiàn)
[外鏈圖片轉(zhuǎn)存中…(img-F9riPc0O-1692756514217)]
[外鏈圖片轉(zhuǎn)存中…(img-f4O85Km6-1692756514218)]

我們?cè)?UserMapper 接口里面去聲明方法

package com.example.demo.mapper;

import com.example.demo.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

// MyBatis 接口,此注解一定不能省略
@Mapper
public interface UserMapper {
    // 添加用戶
    public int add(@Param("username") String username,
                   @Param("password") String password,
                   @Param("photo") String photo);
}

[外鏈圖片轉(zhuǎn)存中…(img-HvhdNRiB-1692756514218)]
接下來(lái)我們?nèi)?UserMapper.xml 里面去實(shí)現(xiàn)具體 SQL 實(shí)現(xiàn)

<!-- insert 只有一個(gè)參數(shù):函數(shù)名 -->
<insert id="add">
  insert into userinfo(username,password,photo)
  values(#{username},#{password},#{photo})
</insert>

但是我們的 photo 字段不是必傳項(xiàng) , 所以需要程序員去設(shè)置一下

<?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.UserMapper">

    <!-- insert 只有一個(gè)參數(shù):函數(shù)名 -->
    <insert id="add">
        insert into userinfo (username,
            <if test="photo!=null">
                photo,
            </if>
        password)
        values (#{username}
            <if test="photo!=null">
                ,#{photo}
            </if>
        ,#{password})
    </insert>
</mapper>

添加完之后 , 我們就可以通過(guò)單元測(cè)試驗(yàn)證一下了

如果數(shù)據(jù)庫(kù)中的自增主鍵 ID 已經(jīng)混亂了 , 我們就可以通過(guò)這條 SQL 去修改自增主鍵的 ID

alter table ‘your_table_name’ auto_increment = '期望的id值'

[外鏈圖片轉(zhuǎn)存中…(img-Mf3MK18l-1692756514218)]
[外鏈圖片轉(zhuǎn)存中…(img-03k2Dyjw-1692756514218)]
我們先實(shí)驗(yàn) : 可選參數(shù)傳值的情況

package com.example.demo.mapper;

import com.example.demo.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest // 當(dāng)前測(cè)試的上下文環(huán)境為 Spring Boot
class UserMapperTest {

    // 要測(cè)試誰(shuí) , 就注入誰(shuí)
    @Autowired
    private UserMapper userMapper;

    @Test
    void add() {
        int result = userMapper.add("王五","wangwu","default.png");
        System.out.println("添加用戶結(jié)果:" + result);
    }
}

[外鏈圖片轉(zhuǎn)存中…(img-s0470fUN-1692756514219)]
[外鏈圖片轉(zhuǎn)存中…(img-X5u7eIOF-1692756514219)]
我們?cè)賮?lái)試驗(yàn)一下可選參數(shù)不傳值的情況 :

package com.example.demo.mapper;

import com.example.demo.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest // 當(dāng)前測(cè)試的上下文環(huán)境為 Spring Boot
class UserMapperTest {

    // 要測(cè)試誰(shuí) , 就注入誰(shuí)
    @Autowired
    private UserMapper userMapper;

    @Test
    void add() {
        int result = userMapper.add("老六","laoliu",null);
        System.out.println("添加用戶結(jié)果:" + result);
    }
}

[外鏈圖片轉(zhuǎn)存中…(img-vIyYPcKo-1692756514219)]
[外鏈圖片轉(zhuǎn)存中…(img-Tpa2bHBh-1692756514220)]

8.2 標(biāo)簽

字面意思就是 : 去掉某些信息
我們就可以結(jié)合 標(biāo)簽完成一些事情
標(biāo)簽中有如下屬性 :

  • prefix : 表示整個(gè)語(yǔ)句塊 , 以 prefix 的值作為前綴
  • suffix : 表示整個(gè)語(yǔ)句塊 , 以 suffix 的值作為后綴
  • prefixOverrides : 表示整個(gè)語(yǔ)句塊要去除掉的前綴
  • suffixOverrides : 表示整個(gè)語(yǔ)句塊要去除掉的后綴

以 prefixOverrides、suffixOverrides 我們來(lái)舉個(gè)栗子 :
我們剛才在寫這里的時(shí)候 , 其實(shí)有點(diǎn)取巧了
[外鏈圖片轉(zhuǎn)存中…(img-WsjamgOd-1692756514220)]
如果我們這樣寫

<insert id="add">
  insert into userinfo (username,password,
  <if test="photo!=null">
    photo
  </if>)
  values (#{username},#{password},
  <if test="photo!=null">
    #{photo}
  </if>
  )
</insert>

如果我們傳入照片 , 無(wú)所謂了
但是如果我們沒(méi)傳進(jìn)去照片 , 那么 SQL 語(yǔ)句就變成了

insert into userinfo (username,password, ) values ("老六","laoliu", );

[外鏈圖片轉(zhuǎn)存中…(img-6MxS5rbI-1692756514220)]
就變成了病句 , 最后面的逗號(hào)就單蹦了 .
那使用我們的 就解決不了了 , 我們就可以搭配 使用
我們把場(chǎng)景設(shè)置的極端一些 : 所有字段都設(shè)置成可填字段

<?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.UserMapper">

    <!-- insert 只有一個(gè)參數(shù):函數(shù)名 -->
    <insert id="add">
        insert into userinfo
            <!--
                prefix 代表前綴,在這里加 prefix="(" , 就不用寫 SQL 里面前面的"("了
                suffix 代表后綴,在這里加 suffix=")" , 就不用寫 SQL 里面后面的")"了
                suffixOverrides 表示整個(gè)語(yǔ)句塊要去除掉的后綴,意思是我們會(huì)把SQL中最后面的逗號(hào)去除掉,這樣就不會(huì)有錯(cuò)了
             -->
            <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>

</mapper>

其中 , 我們最后一個(gè)字段 photo 加不加逗號(hào)無(wú)所謂了 , 因?yàn)槲覀円呀?jīng)有 標(biāo)簽里面的 suffixOverrides 屬性保駕護(hù)航了 , 不加也不會(huì)報(bào)錯(cuò) , 加了更不會(huì)報(bào)錯(cuò)
測(cè)試一下吧
先測(cè)試每個(gè)字段都插入的情況

package com.example.demo.mapper;

import com.example.demo.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest // 當(dāng)前測(cè)試的上下文環(huán)境為 Spring Boot
class UserMapperTest {

    // 要測(cè)試誰(shuí) , 就注入誰(shuí)
    @Autowired
    private UserMapper userMapper;

    @Test
    void add() {
        int result = userMapper.add("老七","laoqi","default.png");
        System.out.println("添加用戶結(jié)果:" + result);
    }
}

[外鏈圖片轉(zhuǎn)存中…(img-dSKxgy0Z-1692756514220)]
[外鏈圖片轉(zhuǎn)存中…(img-odbTSjoC-1692756514221)]
我們?cè)賮?lái)試一下不傳入 photo 字段的情況

package com.example.demo.mapper;

import com.example.demo.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest // 當(dāng)前測(cè)試的上下文環(huán)境為 Spring Boot
class UserMapperTest {

    // 要測(cè)試誰(shuí) , 就注入誰(shuí)
    @Autowired
    private UserMapper userMapper;

    @Test
    void add() {
        int result = userMapper.add("老八","laoba",null);
        System.out.println("添加用戶結(jié)果:" + result);
    }
}

[外鏈圖片轉(zhuǎn)存中…(img-PZMHuJDc-1692756514221)]
[外鏈圖片轉(zhuǎn)存中…(img-wvYvaqkW-1692756514221)]

8.3 標(biāo)簽

標(biāo)簽是針對(duì)于查詢的
比如一個(gè)頁(yè)面上 , 我們可以通過(guò)用戶名查詢 , 也可以通過(guò)用戶 ID 去查詢
我們選擇使用用戶名查詢 , 那么這個(gè)用戶名我們可以傳 , 也可以不傳 .
傳的話 , 就返回對(duì)應(yīng)用戶信息 . 不傳的話 , username 就是空 , 應(yīng)該返回所有用戶信息 , 但是事與愿違
[外鏈圖片轉(zhuǎn)存中…(img-942M8mAE-1692756514221)]
那我們能不能使用 標(biāo)簽?zāi)??
正常情況下 , 我們使用 標(biāo)簽 , 就可以把 SQL 看成這樣

select * from userinfo where username = '';

但是我們不傳參數(shù)的話 , SQL 就變成了這樣

select * from userinfo where;

這就有錯(cuò)誤了
image.png
再比如說(shuō) :

select * from userinfo where username = 'zhangsan' and photo = '';

假如我們使用 標(biāo)簽 , 把 where username = 'zhangsan'包裹起來(lái) , 再用另外一個(gè) 標(biāo)簽把 and photo = ''包裹起來(lái) , 那我們第一個(gè)參數(shù)不填 , SQL 就變成了這樣

select * from userinfo and photo = '';

這個(gè) SQL 也是有錯(cuò)誤的
所以 標(biāo)簽就不太好使了 , 我們需要使用 標(biāo)簽了 , 標(biāo)簽仍然是與 標(biāo)簽搭配使用
我們把之前的 getUserByName 改造一下
[外鏈圖片轉(zhuǎn)存中…(img-Sjcoz30u-1692756514222)]

提前把這里改回來(lái)
[外鏈圖片轉(zhuǎn)存中…(img-Am1mZEsv-1692756514222)]

<?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.UserMapper">

    <select id="getUserByName" resultType="com.example.demo.model.UserInfo">
        select * from userinfo
        <where>
            <!-- <where>標(biāo)簽可以天然去除第一個(gè)標(biāo)簽里面的 and -->
            <if test="username!=null">
                and username=#{username}
            </if>
        </where>
    </select>

</mapper>

進(jìn)行單元測(cè)試

package com.example.demo.mapper;

import com.example.demo.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest // 當(dāng)前測(cè)試的上下文環(huán)境為 Spring Boot
class UserMapperTest {

    // 要測(cè)試誰(shuí) , 就注入誰(shuí)
    @Autowired
    private UserMapper userMapper;

    @Test
    void getUserByName() {
        UserInfo userInfo = userMapper.getUserByName("admin");
        System.out.println(userInfo);
    }
}

[外鏈圖片轉(zhuǎn)存中…(img-h4aRIydG-1692756514222)]
我們?cè)囈幌虏粋髅?/p>

package com.example.demo.mapper;

import com.example.demo.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest // 當(dāng)前測(cè)試的上下文環(huán)境為 Spring Boot
class UserMapperTest {

    // 要測(cè)試誰(shuí) , 就注入誰(shuí)
    @Autowired
    private UserMapper userMapper;

    @Test
    void getUserByName() {
        UserInfo userInfo = userMapper.getUserByName(null);
        System.out.println(userInfo);
    }
}

清除一下無(wú)效數(shù)據(jù)
因?yàn)闇y(cè)試類返回的是 UserInfo , 而不是 UserInfo 數(shù)組 , 沒(méi)能力支持多條數(shù)據(jù) , 只能實(shí)驗(yàn)一組數(shù)據(jù)
[外鏈圖片轉(zhuǎn)存中…(img-8MLtpTWv-1692756514223)]

運(yùn)行一下
[外鏈圖片轉(zhuǎn)存中…(img-IIhH9qMk-1692756514223)]
我們就可以對(duì) 標(biāo)簽做一個(gè)總結(jié) :

  1. 根據(jù) 標(biāo)簽里面的內(nèi)容 , 決定要不要拼接 where 語(yǔ)句

image.png

  1. 標(biāo)簽會(huì)去除掉最前面的 and 關(guān)鍵字 , 讓 SQL 符合數(shù)據(jù)庫(kù)的執(zhí)行標(biāo)準(zhǔn)

[外鏈圖片轉(zhuǎn)存中…(img-xf9jzGfc-1692756514223)]

  1. 標(biāo)簽 等價(jià)于 <trim prefix="where" prefixOverrides="and">

8.4 標(biāo)簽

標(biāo)簽常常使用在 update 語(yǔ)句中

update userinfo set password = "123456" where id = 1;

image.png
標(biāo)簽是去除掉后面的 ,的 , 而 標(biāo)簽是去除掉前面的 and
我們可以來(lái)試一試
在 UserMapper 接口當(dāng)中聲明方法

package com.example.demo.mapper;

import com.example.demo.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

// MyBatis 接口,此注解一定不能省略
@Mapper
public interface UserMapper {

    // 修改用戶
    public int updateById(@Param("username") String username,
                          @Param("password") String password,
                          @Param("id") Integer id);
}

[外鏈圖片轉(zhuǎn)存中…(img-ycBNpq6A-1692756514224)]
然后去 UserMapper.xml 中實(shí)現(xiàn)具體的 SQL

<?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.UserMapper">

    <update id="updateById">
        update userinfo
            <set>
                <if test="username != null">
                    username = #{username},
                </if>
                <if test="password != null">
                    password = #{password},
                </if>
            </set>
        where id=#{id}
    </update>
</mapper>

[外鏈圖片轉(zhuǎn)存中…(img-czGu6trh-1692756514224)]
接下來(lái) , 編寫單元測(cè)試代碼

單元測(cè)試的代碼生成方法就不一一截圖了

package com.example.demo.mapper;

import com.example.demo.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest // 當(dāng)前測(cè)試的上下文環(huán)境為 Spring Boot
class UserMapperTest {

    // 要測(cè)試誰(shuí) , 就注入誰(shuí)
    @Autowired
    private UserMapper userMapper;

    @Test
    void updateById() {
        int result = userMapper.updateById(null,"666",1);
        System.out.println("添加用戶結(jié)果:" + result);
    }
}

[外鏈圖片轉(zhuǎn)存中…(img-ZlXCiNv3-1692756514224)]
image.png
標(biāo)簽的作用 :

  1. 生成 set 關(guān)鍵字
  2. 去除最后一個(gè) ,

8.5 標(biāo)簽

的用途 : 我想實(shí)現(xiàn)一個(gè)批量刪除的功能 , 傳遞的是一個(gè) id 集合

delete from userinfo where id in(3,4,5);

但是我們括號(hào)里面并不是幾個(gè)數(shù) , 而是一個(gè) list 集合 , 我們通過(guò) 標(biāo)簽循環(huán)集合當(dāng)中的每個(gè)元素
標(biāo)簽有幾個(gè)屬性

  • collection : 綁定方法參數(shù)中的集合(綁定的參數(shù)名 <- 接口方法中集合的名字) , 如 List,Set,Map 或數(shù)組對(duì)象
  • item : 遍歷時(shí)的每?個(gè)對(duì)象
  • open : 語(yǔ)句塊開頭的字符串 ( 類似 的 prefix )
  • close : 語(yǔ)句塊結(jié)束的字符串 ( 類似 的 suffix )
  • separator : 每次遍歷之間間隔的字符串

[外鏈圖片轉(zhuǎn)存中…(img-wlwAM7Q5-1692756514225)]
為了測(cè)試 標(biāo)簽 , 我們?cè)跀?shù)據(jù)庫(kù)中構(gòu)造幾條數(shù)據(jù)

insert into userinfo (username,password) values ('張三','123456');
insert into userinfo (username,password) values ('李四','123456');
insert into userinfo (username,password) values ('王五','123456');

[外鏈圖片轉(zhuǎn)存中…(img-7ntvwiGU-1692756514225)]
先在 UserMapper 接口中聲明方法

package com.example.demo.mapper;

import com.example.demo.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

// MyBatis 接口,此注解一定不能省略
@Mapper
public interface UserMapper {
    // 刪除多條數(shù)據(jù)
    public int delByIds(List<Integer> ids);
}



再去 UserMapper.xml 中實(shí)現(xiàn) 具體 SQL

<?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.UserMapper">

    <delete id="delByIds">
        delete from userinfo where id in
            <!--
                collection:UserMapper接口當(dāng)中集合類的名稱
                item:每個(gè)元素的屬性,名字無(wú)所謂,item="item"引號(hào)里的內(nèi)容要和#{item}中{}里面的內(nèi)容相匹配
                open:前置
                close:后置
                separator:分隔符
            -->
            <foreach collection="ids" item="item" open="(" close=")" separator=",">
                #{item}
            </foreach>
    </delete>
</mapper>

[外鏈圖片轉(zhuǎn)存中…(img-oXSszqX0-1692756514226)]
最后生成單元測(cè)試類檢驗(yàn)一下

package com.example.demo.mapper;

import com.example.demo.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.ArrayList;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest // 當(dāng)前測(cè)試的上下文環(huán)境為 Spring Boot
class UserMapperTest {

    // 要測(cè)試誰(shuí) , 就注入誰(shuí)
    @Autowired
    private UserMapper userMapper;

    @Test
    void delByIds() {
        List<Integer> list = new ArrayList<>();
        list.add(6);
        list.add(7);
        list.add(8);

        int result = userMapper.delByIds(list);
        System.out.println("刪除了:" + result);

    }
}

[外鏈圖片轉(zhuǎn)存中…(img-NhQTewAx-1692756514226)]文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-668806.html

到了這里,關(guān)于Java EE 突擊 13 - MyBatis 查詢數(shù)據(jù)庫(kù)(2)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • MyBatis查詢數(shù)據(jù)庫(kù)(1)

    MyBatis查詢數(shù)據(jù)庫(kù)(1)

    ??????SSM專欄更新中,各位大佬覺(jué)得寫得不錯(cuò),支持一下,感謝了!?????? Spring + Spring MVC + MyBatis_冷兮雪的博客-CSDN博客 經(jīng)過(guò)前?的學(xué)習(xí)咱們 Spring 系列的基本操作已經(jīng)實(shí)現(xiàn)的差不多了,接下來(lái),咱們來(lái)學(xué)習(xí)更重要的知識(shí),將前端傳遞的數(shù)據(jù)存儲(chǔ)起來(lái),或者查詢

    2024年02月15日
    瀏覽(23)
  • MyBatis查詢數(shù)據(jù)庫(kù)(4)

    MyBatis查詢數(shù)據(jù)庫(kù)(4)

    ??????SSM專欄更新中,各位大佬覺(jué)得寫得不錯(cuò),支持一下,感謝了!?????? Spring + Spring MVC + MyBatis_冷兮雪的博客-CSDN博客 終于到了MyBatis最后一篇,這篇講的是 動(dòng)態(tài)SQL的使用。 動(dòng)態(tài) SQL?是Mybatis的強(qiáng)大特性之?,能夠完成不同條件下不同的 SQL?拼接。 可以參考官

    2024年02月14日
    瀏覽(39)
  • MyBatis查詢數(shù)據(jù)庫(kù)(2)

    MyBatis查詢數(shù)據(jù)庫(kù)(2)

    目錄 前言?? 一、增刪查改操作?? 1、查?? Ⅰ、mapper接口:?? Ⅱ、UserMapper.xml 查詢所有用戶的具體實(shí)現(xiàn) SQL:?? Ⅲ、進(jìn)行單元測(cè)試?? 2、增、刪、改操作?? Ⅰ、增?? 添加用戶?? 添加用戶并且返回自增 id?? Ⅱ、改?? 根據(jù)id修改用戶名?? 開啟 MyBatis sql 日志打印?? Ⅲ、

    2024年02月16日
    瀏覽(19)
  • MyBatis 查詢數(shù)據(jù)庫(kù)、持久層框架簡(jiǎn)介

    MyBatis 查詢數(shù)據(jù)庫(kù)、持久層框架簡(jiǎn)介

    MyBatis是一款優(yōu)秀的持久層框架,支持自定義SQL、存儲(chǔ)過(guò)程以及高級(jí)映射。它通過(guò)簡(jiǎn)單的XML或注解來(lái)配置和映射原始類型、接口和Java POJO為數(shù)據(jù)庫(kù)中的記錄。

    2024年02月12日
    瀏覽(16)
  • MyBatis查詢數(shù)據(jù)庫(kù)之一(概念+創(chuàng)建項(xiàng)目+基礎(chǔ)交互)

    MyBatis查詢數(shù)據(jù)庫(kù)之一(概念+創(chuàng)建項(xiàng)目+基礎(chǔ)交互)

    目錄 1.MyBatis是什么? 2.為什么學(xué)習(xí)MyBatis? 3. 怎么學(xué) MyBatis 4.第?個(gè)MyBatis查詢 4.1 添加MyBatis框架支持 4.1.1老項(xiàng)目添加MyBatis 4.1.2 新項(xiàng)目添加MyBatis 4.2 配置連接字符串和MyBatis 4.2.1 配置連接字符串 4.2.2 配置 MyBatis 中的 XML 路徑 5. 使用 MyBatis 的操作模式操作數(shù)據(jù)庫(kù) 5.1 添加實(shí)體類

    2024年02月13日
    瀏覽(44)
  • MyBatis 查詢數(shù)據(jù)庫(kù)之二(增、刪、改、查操作)

    MyBatis 查詢數(shù)據(jù)庫(kù)之二(增、刪、改、查操作)

    目錄 1. 配置打印 MyBatis 執(zhí)行的SQL 2. 查詢操作 2.1 通過(guò)用戶 ID 查詢用戶信息、查詢所有用戶信息 (1) Mapper 接口 (2)UserMapper.xml 查詢所有用戶的具體實(shí)現(xiàn) SQL (3)進(jìn)行單元測(cè)試 3. 增加操作 3.1 在 mapper(interface)里面添加增加方法的聲明 3.2 在 XMl 中添加 標(biāo)簽和增加的 sql 代碼 3.3 生成

    2024年02月14日
    瀏覽(31)
  • mybatis plus 查詢數(shù)據(jù)庫(kù)字段名自動(dòng)添加下劃線問(wèn)題解決

    實(shí)體類和數(shù)據(jù)庫(kù)中的字段名是一致的,但報(bào)錯(cuò)Unknown column \\\'dept_id\\\' in \\\'field list\\\',這是因?yàn)閜lus中的駝峰命名法,會(huì)自動(dòng)添加下劃線。 關(guān)閉駝峰式命名轉(zhuǎn)換為下劃線 在配置文件中加一個(gè): 重新運(yùn)行,就可以了! 報(bào)錯(cuò)信息如下: java.sql.SQLSyntaxErrorException: Unknown column \\\'dept_id\\\' in \\\'fi

    2024年02月07日
    瀏覽(96)
  • 【數(shù)據(jù)庫(kù)原理】期末突擊(1)

    【數(shù)據(jù)庫(kù)原理】期末突擊(1)

    下列關(guān)系運(yùn)算中,(? C??? )運(yùn)算不屬于專門的關(guān)系運(yùn)算。 ??? ?A.選擇? ? ? ? ? ? ? ? ? ? ? ? ? ? B.連接 ? ? C .廣義笛卡爾積 ? ? ? ? ? ? ? ?D.投影 傳統(tǒng)的集合運(yùn)算有:并、差、交、笛卡爾積 專門的關(guān)系運(yùn)算有:選擇、投影、連接、除運(yùn)算等 SQL語(yǔ)言具有(?

    2024年01月25日
    瀏覽(25)
  • MyBatis-Plus 查詢PostgreSQL數(shù)據(jù)庫(kù)jsonb類型保持原格式

    MyBatis-Plus 查詢PostgreSQL數(shù)據(jù)庫(kù)jsonb類型保持原格式

    在這篇文章,我們保存了數(shù)據(jù)庫(kù)的jsonb類型:MyBatis-Plus 實(shí)現(xiàn)PostgreSQL數(shù)據(jù)庫(kù)jsonb類型的保存與查詢 這篇文章介紹了模糊查詢json/jsonb類型:PostgreSQL 查詢json/jsonb是否存在某個(gè)片段 在模糊查詢json/jsonb之前,我們得拿到正確的json/jsonb片段,比如我們模糊查詢好幾個(gè)連著的鍵值對(duì),

    2024年02月15日
    瀏覽(110)
  • 【MyBatis學(xué)習(xí)】MyBatis操縱數(shù)據(jù)庫(kù)進(jìn)行查詢操作 ?MyBatis與JDBC想比怎么樣,趕快與我一起探索吧 ! ! !

    【MyBatis學(xué)習(xí)】MyBatis操縱數(shù)據(jù)庫(kù)進(jìn)行查詢操作 ?MyBatis與JDBC想比怎么樣,趕快與我一起探索吧 ! ! !

    前言: 大家好,我是 良辰丫 ,從今天開始我們就要進(jìn)入MyBatis的學(xué)習(xí)了,請(qǐng)君與我一起操縱數(shù)據(jù)庫(kù),MyBatis到底是什么呢?我們慢慢往下瞧! ! !?????? ??個(gè)人主頁(yè):良辰針不戳 ??所屬專欄:javaEE進(jìn)階篇之框架學(xué)習(xí) ??勵(lì)志語(yǔ)句:生活也許會(huì)讓我們遍體鱗傷,但最終這些傷口會(huì)成為我

    2024年02月09日
    瀏覽(17)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包