亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

MyBatis查詢數(shù)據(jù)庫語句總結(jié)

 更新時間:2023年06月20日 09:20:58   作者:YoLo?  
MyBatis是一種持久化框架,可以與許多不同類型的關(guān)系型數(shù)據(jù)庫連接,下面這篇文章主要給大家介紹了關(guān)于MyBatis查詢數(shù)據(jù)庫語句的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下

1.MyBatis是什么?

MyBatis是一款開源的基于Java的持久層框架,它可以幫助Java開發(fā)人員簡化數(shù)據(jù)庫操作,通過XML配置文件或注解,把Java對象映射到對應(yīng)的數(shù)據(jù)庫表中,實現(xiàn)對象關(guān)系和數(shù)據(jù)關(guān)系的互相轉(zhuǎn)換,從而使得Java應(yīng)用程序能夠更簡單的操作和讀取數(shù)據(jù)庫。

MyBatis相對于其他ORM框架最大的特點就是它提供了優(yōu)秀的SQL編寫和調(diào)試機制。通過MyBatis,我們可以直接編寫出原生SQL語句,并通過MyBatis的一些工具,如參數(shù)映射、結(jié)果集映射等機制,把查詢結(jié)果自動映射成Java對象或者List/Map等數(shù)據(jù)格式。同時,MyBatis還提供了懶加載、緩存和事務(wù)等高級特性,可以支持各種復(fù)雜的業(yè)務(wù)場景。

核心思想

將JavaBean中的數(shù)據(jù)和SQL語句中的數(shù)據(jù)進行映射,因此,在使用MyBatis時,我們需要定義一個Mapper接口,然后在XML中描述這個接口中每個方法對應(yīng)的SQL語句,并指定參數(shù)和返回值類型,最后,讓MyBatis自動生成這個Mapper接口的實現(xiàn)類,這樣就可以方便地對數(shù)據(jù)庫進行操作。

持久層

在 Java 程序開發(fā)中,數(shù)據(jù)通常被存儲在關(guān)系型數(shù)據(jù)庫或者非關(guān)系型數(shù)據(jù)庫中,而持久層就是用來處理和管理這些數(shù)據(jù)存取操作的技術(shù)層次。持久層的作用是將應(yīng)用程序中的對象轉(zhuǎn)換成可存儲的形式,然后將其存儲到數(shù)據(jù)存儲介質(zhì)中,同時還要負(fù)責(zé)從數(shù)據(jù)存儲介質(zhì)中獲取數(shù)據(jù)并將其轉(zhuǎn)換成應(yīng)用程序所需要的對象形式,這樣就把數(shù)據(jù)存儲和數(shù)據(jù)訪問分開了,提高了程序的可維護性和擴展性。

持久層技術(shù)通常包括以下方面的內(nèi)容:

  • 對象-關(guān)系映射(ORM):ORM將Java對象與關(guān)系型數(shù)據(jù)庫之間進行了映射,使得Java對象可以像操作內(nèi)存一樣操作數(shù)據(jù)庫,簡化了開發(fā)。
  • 數(shù)據(jù)訪問層(DAO):定義了對數(shù)據(jù)訪問的接口,封裝了數(shù)據(jù)存取的細(xì)節(jié),使得上層業(yè)務(wù)邏輯不需要關(guān)注數(shù)據(jù)存取的具體實現(xiàn)方式。
  • 持久化框架:用于簡化數(shù)據(jù)庫訪問、提高性能、降低開發(fā)難度、提供高級功能,如緩存、批量處理、分布式共享等等。

JDBC編程的缺點

  1. 繁瑣的代碼編寫:JDBC需要開發(fā)人員自己手動編寫大量的結(jié)果集映射、異常處理等代碼,很容易出現(xiàn)重復(fù)代碼和錯誤。
  2. 容易造成資源泄漏:使用JDBC需要顯式地打開和關(guān)閉連接、Statement和ResultSet等對象,如果不仔細(xì)處理,可能會導(dǎo)致資源泄漏,從而影響應(yīng)用程序的性能和穩(wěn)定性。
  3. SQL語句的硬編碼:JDBC需要直接在Java代碼中編寫SQL語句,這樣就容易出現(xiàn)硬編碼,對于SQL語句的修改和維護也不太方便。
  4. 難以應(yīng)對復(fù)雜業(yè)務(wù)場景:如果某個應(yīng)用有比較復(fù)雜的業(yè)務(wù)邏輯需求,例如多表關(guān)聯(lián)查詢、分頁查詢、事務(wù)控制等,使用JDBC來實現(xiàn)可能比較困難,需要編寫大量的復(fù)雜代碼。

MyBatis可以解決這些問題.ORM框架可以將Java對象和數(shù)據(jù)庫表自動映射,并提供了更加優(yōu)雅和高效的API,讓開發(fā)人員專注于業(yè)務(wù)邏輯,而不是繁瑣的數(shù)據(jù)訪問代碼。同時,ORM框架還可以提供緩存、懶加載和批處理等高級特性,從而進一步提高程序的性能和可維護性。

MyBatis與JDBC

MyBatis是基于JDBC實現(xiàn)的。MyBatis雖然與JDBC有很大的相似之處,但是它封裝了JDBC的細(xì)節(jié),使得開發(fā)人員可以更加便捷和高效地進行數(shù)據(jù)庫操作。

在使用MyBatis進行數(shù)據(jù)訪問時,程序仍然需要使用JDBC的API來獲取連接對象、創(chuàng)建Statement對象、執(zhí)行SQL語句以及處理查詢結(jié)果等操作。不過,MyBatis對JDBC進行了簡化和封裝,提供了面向?qū)ο蟮姆绞皆L問數(shù)據(jù)庫,通過 XML 或注解方式配置 SQL 語句,并且提供了一些高級特性,如緩存、動態(tài) SQL 和對象關(guān)系映射(ORM)等。

MyBatis相對于JDBC的優(yōu)勢在于,MyBatis更加簡單易用,提升了開發(fā)效率;同時,MyBatis還提供了更多的功能,如自動映射、動態(tài) SQL 和二級緩存等,可以提升應(yīng)用程序的性能和可維護性。

因此,MyBatis是一種基于JDBC實現(xiàn)的高級數(shù)據(jù)訪問框架,它封裝了JDBC的底層細(xì)節(jié),提供了一種高級的、面向?qū)ο蟮姆绞絹碓L問數(shù)據(jù)庫,并且提供了多種高級特性,以方便開發(fā)人員進行數(shù)據(jù)訪問和業(yè)務(wù)邏輯的實現(xiàn)。

ORM框架

ORM是對象關(guān)系映射(Object-Relational Mapping)的縮寫,是一種將對象模型和關(guān)系數(shù)據(jù)庫模型進行轉(zhuǎn)換、映射的技術(shù)。通過ORM框架,可以將Java對象映射到關(guān)系數(shù)據(jù)庫表中的行,從而通過面向?qū)ο蟮姆绞絹聿僮鲾?shù)據(jù)庫,而無需編寫大量的SQL語句。

Java的類,對象,對象屬性映射到ORM框架中是什么

類映射:在MyBatis中,Java的類映射到數(shù)據(jù)庫中的某個表

對象映射:在MyBatis中,Java的對象映射到數(shù)據(jù)庫中的數(shù)據(jù)行

屬性映射:Java對象的屬性和數(shù)據(jù)庫表的列是一一對應(yīng)的

2.配置MyBatis環(huán)境

1.添加MyBatis框架支持

運行后會報錯

2.設(shè)置MyBatis配置信息

1.設(shè)置數(shù)據(jù)庫連接相關(guān)信息

2.配置xml保存路徑,xml命名規(guī)則 

classpath

        表示類路徑,即應(yīng)用程序的CLASSPATH環(huán)境變量所指的路徑,用于指示 MyBatis 框架在類路徑下查找配置文件。

/mybatis/

        是一個目錄路徑,表示 MyBatis 框架將在類路徑下的 mybatis 目錄中查找 *Mapper.xml 配置文件。

*Mapper.xml

        *是通配符,表示所有以 Mapper.xml 結(jié)尾的文件都應(yīng)該被 MyBatis 框架解析和加載。

綜合起來,classpath:/mybatis/*Mapper.xml 用于指示 MyBatis 框架在類路徑下的 mybatis 目錄中查找所有以 Mapper.xml 結(jié)尾的配置文件,并將其解析為 MyBatis 的 Mapper 映射文件。

舉個例子,假設(shè)我們的應(yīng)用程序類路徑中有一個名為 mybatis 的目錄,該目錄下包含了兩個 MyBatis 的映射文件:UserMapper.xmlOrderMapper.xml。那么,使用 classpath:/mybatis/*Mapper.xml 這個路徑表達(dá)式,MyBatis 框架將會自動解析這兩個映射文件,并將其配置信息綁定到對應(yīng)的 Java 接口或類上,從而實現(xiàn)與數(shù)據(jù)庫的數(shù)據(jù)訪問操作。

至此,配置環(huán)境就完成了

3. MyBatis模式開發(fā)

先向數(shù)據(jù)庫中插入一些數(shù)據(jù)

首先,創(chuàng)建一個實體類UserEntity,包含上述幾個屬性,必須對應(yīng)。

接著,在Mapper接口中聲明對UserEntity表進行操作的方法:

Mapper是MyBatis框架中的一個概念,用于描述一組將Java對象映射到SQL語句的規(guī)則。通常情況下,Mapper會包含一組接口和配置文件,用于定義Java對象和數(shù)據(jù)庫表之間的映射關(guān)系。

然后,在Mapper.xml文件中,實現(xià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.UserMapper">
    <select id="getAll" resultType="com.example.demo.entity.UserEntity">
        select * from userinfo
    </select>
</mapper>

id對應(yīng)接口中的方法名

namesapce:實現(xiàn)接口(包名加類名)

按照標(biāo)準(zhǔn)分層,然后,創(chuàng)建Service層訪問Mapper 

Service層處理業(yè)務(wù)邏輯,并對外提供服務(wù)接口

創(chuàng)建Controller層

Controller層:負(fù)責(zé)接收用戶請求,調(diào)用 Service 層處理請求,并通過視圖呈現(xiàn)處理結(jié)果

啟動項目,成功訪問 

向表中插入一條數(shù)據(jù)

刷新后,更新數(shù)據(jù)庫中插入的新數(shù)據(jù)

上述是最簡單的查詢操作

4.單元測試

 此處介紹一下單元測試的概念

SpringBoot已經(jīng)內(nèi)置了單元測試的依賴,不用添加支持

spring-boot-starter-test 是 Spring Boot 提供的一種測試 Starter,旨在提供各種常見的測試工具和框架,使開發(fā)人員能夠更加輕松地編寫、運行、管理 Spring Boot 應(yīng)用程序的單元測試和集成測試

包含了以下幾個主要組件:

  1. JUnit:一個廣泛使用的 Java 單元測試框架,能夠幫助開發(fā)人員快速構(gòu)建單元測試用例,并自動執(zhí)行這些測試用例;()我們此處使用的JUit5)
  2. Spring Test:一個專門為 Spring 應(yīng)用程序設(shè)計的測試框架,能夠幫助開發(fā)人員快速搭建 Spring 容器環(huán)境,在容器環(huán)境中執(zhí)行測試用例,并驗證應(yīng)用程序的正確性;
  3. AssertJ:一個優(yōu)秀的斷言庫,能夠幫助開發(fā)人員編寫簡潔、易于理解、易于擴展的斷言語句;
  4. Hamcrest:另一個流行的斷言庫,也提供了類似于 AssertJ 的各種斷言方法;
  5. Mockito:一個強大的 Java 模擬框架,能夠幫助開發(fā)人員快速創(chuàng)建模擬對象,并進行各種測試;
  6. JsonPath:一個用于處理 JSON 路徑的庫,能夠幫助開發(fā)人員快速過濾、提取 JSON 數(shù)據(jù)。

優(yōu)點主要有以下幾個:

  1. 提升測試效率:借助 spring-boot-starter-test Starter 提供的各種測試工具和框架,開發(fā)人員能夠更加輕松地編寫、運行、管理單元測試和集成測試,從而大大提升測試效率;
  2. 方便集成 Spring Boot:spring-boot-starter-test Starter 與 Spring Boot 完美集成,可直接使用 Spring Boot 的自動配置機制和依賴注入機制,使得單元測試與實際應(yīng)用程序開發(fā)更加無縫銜接;
  3. 簡化代碼編寫:借助 spring-boot-starter-test Starter 提供的各種測試工具和框架,開發(fā)人員不需要編寫大量的測試框架代碼,只需要關(guān)注業(yè)務(wù)邏輯和測試用例的編寫即可;
  4. 多樣化的測試支持:spring-boot-starter-test Starter 支持多種類型的測試:單元測試、集成測試、端到端測試等等;
  5. 良好的社區(qū)支持與更新:spring-boot-starter-test Starter 是 Spring Boot 社區(qū)的核心組件之一,擁有龐大的用戶群和活躍的維護者團隊,能夠及時更新和修復(fù)各種測試工具和框架的問題。

單元測試實現(xiàn)步驟

1.在要測試的類上右鍵Generate

會生成測試類

寫測試信息.不要忘記添加注解!!

啟動測試類

這是測試類的創(chuàng)建,向測試類中添加測試時,會報一個錯誤

意思是已經(jīng)存在了這個測試類,是否向其中追加測試,直接點擊Ok

單元測試就簡單了解到這里

5.增刪查改

下來看傳參問題

當(dāng)這兩處,參數(shù)名稱不一致,xml中應(yīng)該寫成什么

啟動測試類會報錯,參數(shù)id沒找到

 修改xml文件

此時單元測試運行成功了 .

 所以xml文件的參數(shù)命名要和@Param("uid")一致..如果沒有加這個注解,就要和原參數(shù)名相同

 加了注解,生效的就是注解中的參數(shù)命名

Mybatis獲取動態(tài)參數(shù)的方式有兩種:

1.${key}

${key} 是一種占位符語法,被稱為字符串替換,用于將 SQL 語句中的參數(shù)占位符替換為實際的值。使用 ${} 語法會直接將參數(shù)替換為 SQL 字符串,而不是通過預(yù)編譯語句來傳遞參數(shù)。在使用 ${key} 時,如果不正確地處理輸入的參數(shù),可能會導(dǎo)致 SQL 注入攻擊。

可以打印出執(zhí)行的生成的sql語句,就能看到效果了

需要先配置一下

spring.datasource.url=jdbc:mysql://127.0.0.1:3306/mycnblog?characterEncoding=utf8&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#配置mybatis xml 的文件路徑,在resources/mapper 創(chuàng)建的所有表的 xml 文件
mybatis.mapper-locations=classpath:/mybatis/*Mapper.xml
#日志打印sql
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
#日志打印級別(默認(rèn)是info,需要設(shè)置位debug,才能顯示)
logging.level.com.example.demo=debug

然后執(zhí)行測試

可以看到這是直接將參數(shù)替換為 SQL 字符串 

2.#{key}

在 MyBatis 中,#{key} 是一種占位符語法,被稱為參數(shù)占位符,用于將 SQL 語句中的參數(shù)占位符替換為實際的值。它可以幫助我們在 SQL 語句中使用參數(shù),使得 SQL 語句更加靈活和通用

具體來說,當(dāng)應(yīng)用程序調(diào)用 DAO 層的方法時,會傳遞一些參數(shù)給對應(yīng)的 SQL 語句,這些參數(shù)可以通過 #{} 占位符來引用。MyBatis 會自動將 #{} 中的參數(shù)值進行預(yù)編譯處理,保證輸入數(shù)據(jù)的安全性,并將它們以安全的方式插入到 SQL 語句中,然后發(fā)送給數(shù)據(jù)庫執(zhí)行,從而防止了 SQL 注入攻擊等安全問題

啟動單元測試

這里的 #{uid} 是一個占位符,代表該位置需要動態(tài)替換為具體的參數(shù)值。在執(zhí)行 SQL 時,MyBatis 會自動將 #{uid} 替換為實際傳入的 uid 參數(shù)的值,并將其進行預(yù)編譯處理,從而確保 SQL 查詢語句的安全性。

日志打印看到的也不是sql語句,而是通過占位符模式進行內(nèi)容的填充

這里數(shù)據(jù)是int類型的,我們換用String類型數(shù)據(jù)嘗試

結(jié)果:

當(dāng)將#{}替換為${} 再次進行執(zhí)行.報錯了 

原因:${}是直接替換字符串的,你輸入的是什么就完全替換

'${username}',才不會報錯,不加單引號sql語句就會出現(xiàn)問題

這樣只能保障不報錯,但是會存在安全性問題

例如登陸場景下:sql注入問題

 為了只返回一條數(shù)據(jù),先將表中數(shù)據(jù)刪除

mysql> select*from userinfo;
+----+----------+----------+-------+---------------------+---------------------+-------+
| id | username | password | photo | createtime          | updatetime          | state |
+----+----------+----------+-------+---------------------+---------------------+-------+
|  2 | lisi     | lisi     |       | 2022-12-06 17:10:48 | 2022-12-06 18:10:48 |     1 |
+----+----------+----------+-------+---------------------+---------------------+-------+
1 row in set (0.00 sec)

正常行為: 

攻擊者發(fā)送如下輸入:

mysql> select 1 = '1';
+---------+
| 1 = '1' |
+---------+
|       1 |
+---------+
1 row in set (0.00 sec)

那么該 SQL 查詢語句將會被替換為:

SELECT * FROM users WHERE username = '' or '1'='1' AND password = '' or '1'='1'

使用不存在的username,不存在的password也能查到用戶信息

這就是使用${key}時的sql注入攻擊.

將${key}替換為#{key}

占位符的方式,不會出現(xiàn)安全性問題 

${}在特定場景下,也有優(yōu)點

此時使用#{key}會被錯誤地解析為字符串: 

SELECT * FROM userinfo ORDER BY id "desc"

即使設(shè)置了 ord 參數(shù)的值為 ASC 或 DESC,也無法正確地替換該字符串

需要將該 SQL 語句更改為以下形式進行直接替換:

SELECT * FROM userinfo ORDER BY id ${ord}

總結(jié):

1.${key}   主要用于字符串替換,可以方便地將參數(shù)替換為 SQL 語句

        使用 ${key} 時需要注意安全性問題,應(yīng)該避免潛在的 SQL 注入攻擊

2.#{key}   主要用于預(yù)處理 SQL 語句,可以有效地防止 SQL 注入攻擊

#{key}   底層原理:

在 MyBatis 中,#{} 在底層的實現(xiàn)中使用了 PreparedStatement 進行參數(shù)的預(yù)處理和類型轉(zhuǎn)換。

當(dāng) MyBatis 執(zhí)行 SQL 語句時,它會將 SQL 語句中的 #{} 占位符替換為 JDBC 的 Placeholder(如 ?),然后生成一個預(yù)編譯的 SQL 語句。這個預(yù)編譯的 SQL 語句會被傳遞給 DriverManager,并由 DriverManager 創(chuàng)建一個 PreparedStatement 對象。

然后,MyBatis 會將查詢參數(shù)的值按照 JDBC 規(guī)范設(shè)置到 PreparedStatement 的參數(shù)位置上,然后執(zhí)行 PreparedStatement 對象的查詢操作,最后將查詢結(jié)果映射成 Java 對象并返回給調(diào)用方。

使用預(yù)處理語句可以提高 SQL 的執(zhí)行效率,避免 SQL 注入等安全問題,并且可以自動進行類型轉(zhuǎn)換,讓開發(fā)人員更加專注于業(yè)務(wù)邏輯的實現(xiàn)。

需要注意的是,由于預(yù)處理語句必須在編譯和執(zhí)行之間進行變量綁定,因此不能在運行時動態(tài)地構(gòu)建 SQL 語句。如果需要在運行時動態(tài)地構(gòu)建 SQL 語句,需要使用 ${} 實現(xiàn)字符串替換,并且需要注意防止 SQL 注入攻擊的問題。

PreparedStatement 是 JDBC 提供的一種接口,用于提高執(zhí)行 SQL 的性能和安全性 PreparedStatement 的特點:

  1. 預(yù)編譯:PreparedStatement 對象在創(chuàng)建時會將 SQL 語句編譯成一個可執(zhí)行的語句,這樣可以提高 SQL 的執(zhí)行效率。
  2. 參數(shù)綁定:PreparedStatement 可以在執(zhí)行前設(shè)置參數(shù),可以使用占位符 (?) 或命名參數(shù)(:param)來代替實際的參數(shù)值,從而避免了 SQL 注入攻擊。
  3. 批處理:PreparedStatement 支持批量處理,可以將多個 SQL 語句一次性提交到數(shù)據(jù)庫執(zhí)行,從而提高數(shù)據(jù)庫處理的效率。
  4. 預(yù)處理語句緩存:預(yù)編譯語句可以緩存,再次執(zhí)行同樣的 SQL 語句時,可以直接從緩存中獲取已編譯的語句,避免了每次都重新編譯 SQL,從而提高 SQL 的執(zhí)行效率。

修改密碼 

運行單元測試

成功修改 

mysql> select*from userinfo ;
+----+----------+----------+-------+---------------------+---------------------+-------+
| id | username | password | photo | createtime          | updatetime          | state |
+----+----------+----------+-------+---------------------+---------------------+-------+
|  2 | lisi     | 123456   |       | 2022-12-06 17:10:48 | 2022-12-06 18:10:48 |     1 |
+----+----------+----------+-------+---------------------+---------------------+-------+
1 row in set (0.00 sec)

 在單元測試情況下,我們是不愿意改動數(shù)據(jù)庫的,也就是不污染數(shù)據(jù)庫

默認(rèn)情況下,是會持久化改動數(shù)據(jù)庫的

這里就用到@Transactional注解了

正常執(zhí)行,但不污染數(shù)據(jù)庫,執(zhí)行時開啟事務(wù),執(zhí)行結(jié)束后進行回滾操作,就不會污染數(shù)據(jù)庫

看看數(shù)據(jù)庫中,沒有改變,說明進行了回滾...并且成功驗證了程序,返回修改:1

mysql> select*from userinfo ;
+----+----------+----------+-------+---------------------+---------------------+-------+
| id | username | password | photo | createtime          | updatetime          | state |
+----+----------+----------+-------+---------------------+---------------------+-------+
|  2 | lisi     | 123456   |       | 2022-12-06 17:10:48 | 2022-12-06 18:10:48 |     1 |
+----+----------+----------+-------+---------------------+---------------------+-------+
1 row in set (0.00 sec)

 下來學(xué)習(xí)刪除操作

//刪除用戶,返回受影響行數(shù)
    int deleteById(@Param("id")Integer id);
 
<delete id="deleteById">
<!--        默認(rèn)返回受影響的行數(shù)-->
        delete from userinfo where id = #{id}
    </delete>
 
@Transactional
    @Test
    void deleteById() {
        int result = userMapper.deleteById(2);
        System.out.println("刪除: "+result);
    }

執(zhí)行結(jié)果

因為設(shè)置事務(wù)了,所以測試完成后進行了回滾,不會污染數(shù)據(jù)庫

普通得增加模塊,這里我們不進行回滾了,讓數(shù)據(jù)插入到數(shù)據(jù)庫中

//添加用戶
    int addUser(UserEntity user);
 
<insert id="addUser">
        <!--        默認(rèn)返回受影響的行數(shù)-->
        insert into userinfo(username,password) values(#{username},#{password})
    </insert>
 
@Test
    void addUser() {
        UserEntity user = new UserEntity();
        user.setUsername("zhangsan");
        user.setPassword("123456");
        int result = userMapper.addUser(user);
        System.out.println(result);
    }

執(zhí)行結(jié)果,返回影響行數(shù):1.數(shù)據(jù)庫中新增了一條數(shù)據(jù)

==>  Preparing: insert into userinfo(username,password) values(?,?)
==> Parameters: zhangsan(String), 123456(String)
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3e4e4c1]
1

mysql> select*from userinfo ;
+----+----------+----------+-------+---------------------+---------------------+-------+
| id | username | password | photo | createtime          | updatetime          | state |
+----+----------+----------+-------+---------------------+---------------------+-------+
|  2 | lisi     | 123456   |       | 2022-12-06 17:10:48 | 2022-12-06 18:10:48 |     1 |
|  3 | zhangsan | 123456   |       | 2023-05-18 17:21:49 | 2023-05-18 17:21:49 |     1 |
+----+----------+----------+-------+---------------------+---------------------+-------+
2 rows in set (0.00 sec)

添加用戶得到id

//添加用戶得到ID
    int addUserGetId(UserEntity user);
 
<insert id="addUserGetId" useGeneratedKeys="true" keyProperty="id">
        <!--返回受影響的行數(shù)  和  id-->
        <!--useGeneratedKeys="true"keyProperty="id"是否自動生成id,拿到id放到id字段中-->
 
        insert into userinfo(username,password) values(#{username},#{password})
    </insert>
 
@Test
    void addUserGetId() {
        UserEntity user = new UserEntity();
        user.setUsername("wangwu");
        user.setPassword("123456");
        int result = userMapper.addUserGetId(user);
        System.out.println("ID: "+user.getId());
    }

執(zhí)行結(jié)果

JDBC Connection [HikariProxyConnection@1775046789 wrapping com.mysql.cj.jdbc.ConnectionImpl@60bb7995] will not be managed by Spring
==>  Preparing: insert into userinfo(username,password) values(?,?)
==> Parameters: wangwu(String), 123456(String)
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@ef60710]
ID: 4

mysql> select*from userinfo ;
+----+----------+----------+-------+---------------------+---------------------+-------+
| id | username | password | photo | createtime          | updatetime          | state |
+----+----------+----------+-------+---------------------+---------------------+-------+
|  2 | lisi     | 123456   |       | 2022-12-06 17:10:48 | 2022-12-06 18:10:48 |     1 |
|  3 | zhangsan | 123456   |       | 2023-05-18 17:21:49 | 2023-05-18 17:21:49 |     1 |
|  4 | wangwu   | 123456   |       | 2023-05-18 17:36:28 | 2023-05-18 17:36:28 |     1 |
+----+----------+----------+-------+---------------------+---------------------+-------+
3 rows in set (0.00 sec)

模糊查詢-concat

 使用#{key}方式的查詢結(jié)果會報錯

因為傳遞參數(shù)為string類型,會被#{}解析為字符串,因此會自動加上'',那么占位符替換后變成

'%'li'%'

mysql> select*from userinfo where username like '%'li'%';
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'li'%'' at line 1

需要借助concat來進行拼接

mysql>  select concat ('%','li','%');
+-----------------------+
| concat ('%','li','%') |
+-----------------------+
| %li%                  |
+-----------------------+
1 row in set (0.00 sec)

執(zhí)行結(jié)果 

JDBC Connection [HikariProxyConnection@1622899093 wrapping com.mysql.cj.jdbc.ConnectionImpl@40fa8766] will not be managed by Spring
==>  Preparing: select * from userinfo where username like concat('%',?,'%')
==> Parameters: li(String)
<==    Columns: id, username, password, photo, createtime, updatetime, state
<==        Row: 2, lisi, 123456, , 2022-12-06 17:10:48, 2022-12-06 18:10:48, 1
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@56399b9e]
UserEntity(id=2, username=lisi, password=123456, photo=, createtime=2022-12-06T17:10:48, updatetime=2022-12-06T18:10:48, state=1)

 錯誤的模糊匹配查詢會導(dǎo)致索引失效

1.like 'zhang%'

2.like '%zhang'

3.like '%zhang%'

只有第一種查詢會走索引,后面兩個都不會走索引,索引失效了

由于DBA和后端開發(fā)人員代碼風(fēng)格不同,可能會出現(xiàn)不兼容的問題,比如

然后我們執(zhí)行該單元測試

我們發(fā)現(xiàn)JDBC成功執(zhí)行,但是由于password映射不上pwd,pwd的值為空

此時resultType="com.example.demo.entity.UserEntity"就失效了,因為表中字段和類的屬性不一樣了,無法一對一直接映射了

解決方法--<resultMap>

<resultMap> 是 MyBatis 中用于映射查詢結(jié)果集的標(biāo)簽。它能夠解決以下兩個問題:

  1. 解決列名與屬性名不一致的問題:在數(shù)據(jù)庫中,有些列名可能并不符合 Java 對象中屬性的命名規(guī)范,這時可以通過 <resultMap> 映射來將查詢結(jié)果集中的列名與 Java 對象中屬性名進行映射,使得結(jié)果集與對象之間能夠正確匹配。
  2. 解決多表關(guān)聯(lián)查詢的問題:在進行多表關(guān)聯(lián)查詢時,查詢結(jié)果集通常會包含多個表中的列,這時可以使用 <resultMap> 將不同表中的列映射到不同的 Java 對象屬性中,從而完成對結(jié)果集的映射轉(zhuǎn)換。

第一步,設(shè)置映射關(guān)系

    <resultMap id="BaseMap" type="com.example.demo.entity.UserEntity">
    <!--設(shè)置主鍵   property:屬性,類中的  column:字段,數(shù)據(jù)庫表中的     -->
        <id property="id" column="id"></id>
    <!--設(shè)置普通參數(shù)-->
        <result property="pwd" column="password"></result>
        <result property="username" column="username"></result>
        <result property="createtime" column="createtime"></result>
        <result property="photo" column="photo"></result>
        <result property="updatetime" column="updatetime"></result>
        <result property="state" column="state"></result>
    </resultMap>

第二步,修改返回類型

    <select id="getUserById" resultMap="BaseMap">
        select * from userinfo where id = #{uid}
    </select>

執(zhí)行結(jié)果

還有比較簡單的方式,在sql語句中設(shè)置重命名也能成功映射

<select id="getUserByName" resultType="com.example.demo.entity.UserEntity">
        select id,username,password as pwd from userinfo where username = '${username}'
    </select>

多表聯(lián)查

mysql> update userinfo set id = 1 where username = 'lisi';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
文章信息表
mysql> select*from articleinfo;
+----+-------+----------+---------------------+---------------------+-----+--------+-------+
| id | title | content  | createtime          | updatetime          | uid | rcount | state |
+----+-------+----------+---------------------+---------------------+-----+--------+-------+
|  1 | Java  | Java正文 | 2023-05-15 09:12:59 | 2023-05-15 09:12:59 |   1 |      1 |     1 |
+----+-------+----------+---------------------+---------------------+-----+--------+-------+
1 row in set (0.01 sec)

為了對應(yīng),將lisi 的id修改為1

mysql> update userinfo set id = 1 where username = 'lisi';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
mysql> select*from userinfo;
+----+----------+----------+-------+---------------------+---------------------+-------+
| id | username | password | photo | createtime          | updatetime          | state |
+----+----------+----------+-------+---------------------+---------------------+-------+
|  1 | lisi     | 123456   |       | 2022-12-06 17:10:48 | 2022-12-06 18:10:48 |     1 |
|  3 | zhangsan | 123456   |       | 2023-05-18 17:21:49 | 2023-05-18 17:21:49 |     1 |
|  4 | wangwu   | 123456   |       | 2023-05-18 17:36:28 | 2023-05-18 17:36:28 |     1 |
+----+----------+----------+-------+---------------------+---------------------+-------+
3 rows in set (0.00 sec)

創(chuàng)建文章表實體類

@Data
public class ArticleInfo {
    private int id;
    private String title;
    private String content;
    private LocalDateTime createtime;
    private LocalDateTime updatrtime;
    private int uid;
    private int rcount;
    private int state;
}

擴展類

package com.example.demo.entity.vo;
import com.example.demo.entity.ArticleInfo;
import lombok.Data;
@Data
public class ArticleInfoVO extends ArticleInfo {
    private String username;
}

在Mapper中創(chuàng)建接口

package com.example.demo.mapper;
 
import com.example.demo.entity.vo.ArticleInfoVO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
 
@Mapper
public interface ArticleMapper {
    //查詢文章詳情
    ArticleInfoVO getDetail(@Param("id")Integer id);
}

在mybatis包下創(chuàng)建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>

創(chuàng)建測試類

@SpringBootTest
class ArticleMapperTest {
    @Autowired
    private ArticleMapper articleMapper;
    @Test
    void getDetail() {
        ArticleInfoVO articleInfoVO = articleMapper.getDetail(1);
        System.out.println(articleInfoVO);
    }
}

執(zhí)行單元測試

JDBC執(zhí)行是正確的,但是返回只有username,并沒有查詢到父類的屬性

其實是lombok出現(xiàn)了問題,打印時沒包含父類的屬性

解決辦法:手動設(shè)置toString

public class ArticleInfoVO extends ArticleInfo {
    private String username;
    @Override
    public String toString() {
        return "ArticleInfoVO{" +
                "username='" + username + '\'' +
                "} " + super.toString();
    }
}

查看字節(jié)碼

 再次執(zhí)行 

JDBC Connection [HikariProxyConnection@166022233 wrapping com.mysql.cj.jdbc.ConnectionImpl@5dbb50f3] will not be managed by Spring
==>  Preparing: select a.*,u.username from articleinfo a left join userinfo u on u.id = a.uid where a.id = ?
==> Parameters: 1(Integer)
<==    Columns: id, title, content, createtime, updatetime, uid, rcount, state, username
<==        Row: 1, Java, <<BLOB>>, 2023-05-15 09:12:59, 2023-05-15 09:12:59, 1, 1, 1, lisi
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3662bdff]
ArticleInfoVO{username='lisi'} ArticleInfo(id=1, title=Java, content=Java正文, createtime=2023-05-15T09:12:59, updatrtime=null, uid=1, rcount=1, state=1)

查詢一個用戶的所有文章

先將插入一條文章記錄

mysql> select*from articleinfo;
+----+-------+-----------+---------------------+---------------------+-----+--------+-------+
| id | title | content   | createtime          | updatetime          | uid | rcount | state |
+----+-------+-----------+---------------------+---------------------+-----+--------+-------+
|  1 | Java  | Java正文  | 2023-05-15 09:12:59 | 2023-05-15 09:12:59 |   1 |      1 |     1 |
|  2 | mysql | mysql正文 | 2023-05-19 11:14:49 | 2023-05-19 11:14:49 |   1 |      1 |     1 |
+----+-------+-----------+---------------------+---------------------+-----+--------+-------+
2 rows in set (0.00 sec)

其他代碼

//查詢一個用戶所有文章
    List<ArticleInfoVO> getListByUid(@Param("uid")Integer uid);
<select id="getListByUid" 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 getListByUid() {
        Integer uid =1;
        List<ArticleInfoVO> list = articleMapper.getListByUid(uid);
        //使用多線程的方式,順序可能會不同
        list.stream().parallel().forEach(System.out::println);
    }

執(zhí)行

總結(jié)

到此這篇關(guān)于MyBatis查詢數(shù)據(jù)庫的文章就介紹到這了,更多相關(guān)MyBatis查詢數(shù)據(jù)庫內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論