SSM框架的學(xué)習(xí)與應(yīng)用(Spring + Spring MVC + MyBatis)-Java EE企業(yè)級應(yīng)用開發(fā)學(xué)習(xí)記錄(第二天)Mybatis的深入學(xué)習(xí)(增刪改查的操作)
上一篇我們的項目搭建好了,也寫了簡答的Junit測試類進行測試,可以正確映射到數(shù)據(jù)庫中。
那么這篇文章來深入學(xué)習(xí)一下以下幾個點:
- 了解MyBatis的核心對象SqlSessionFactoryBuilder以及它的作用
- 掌握MyBatis核心配置文件以及元素的使用。
- 掌握MyBatis映射文件及其元素的使用。
一、什么是MyBatis的核心對象?
可以看到紅色框住的這部分代碼,我們使用了SqlSessionFactoryBuilder().build(reader)來創(chuàng)建MyBatis的SqlSessionFactory的一個實例。
稍微解釋一下代碼吧(這是一種鏈?zhǔn)讲僮鳎沟么a更為緊湊方便閱讀):
-
SqlSessionFactoryBuilder()
:這是 MyBatis 框架提供的 SqlSessionFactoryBuilder 類的構(gòu)造方法,用于創(chuàng)建 SqlSessionFactory 實例的構(gòu)建器。 -
build(reader)
:這是 SqlSessionFactoryBuilder 類的build
方法,用于**構(gòu)建 SqlSessionFactory 實例。**該方法需要一個 Reader 參數(shù),該 Reader 包含了 MyBatis 配置文件的內(nèi)容。通常,配置文件名為mybatis-config.xml
。
? 但是呢,寫入數(shù)據(jù)庫的操作是SqlSession對象完成的,所以我們上面創(chuàng)建了SqlSessionFactory的實例就是為了通過其中的build()方法創(chuàng)建出一個SqlSession對象,這樣才能進行數(shù)據(jù)庫操作。
//創(chuàng)建SqlSession實例
SqlSession session = sqlSessionFactory.openSession();
//調(diào)用方法,傳入?yún)?shù)進行查詢\插入\更新\刪除等操作
PasswordMS passwordMS = session.selectOne("findById",1);//SqlSession中查詢單個對象的方法,若是要查詢多條則要使用selectList(),方法不同返回值也不同。
//日志輸出信息查看返回結(jié)果
logger.info("姓名:"+passwordMS.getAccount()+",密碼:"+passwordMS.getPassword()+",網(wǎng)站:"+passwordMS.getWebsiteName());
//關(guān)閉session
session.close();
因此SqlSessionFactoryBuilder通常被認為是Mybatis的核心對象?。ㄈ羰巧厦娴拇a解釋,還是不太懂的話,建議去看看我的其他倆個專欄,先把Java基礎(chǔ)和Java高級編程學(xué)習(xí)這倆專欄學(xué)習(xí)看完,或者也可以單獨看一下Java方法詳解這一篇文章,即可理解大概的邏輯思路。)
SqlSessionFactoryBuilder中有多個重載的build()方法
? 可以看出都是構(gòu)建出SqlSessionFactory對象, 通過以上代碼可知,配置信息可以通過InputStream(字節(jié)流)、Reader(字符流)、Configuration(類)三種形式提供給SqlSessionFactoryBuilder的build()方法。
我們是以讀取XML文件的方式構(gòu)造SqlSessionFactory對象
//字符流 讀取配置文件
Reader reader = Resources.getResourceAsReader("配置文件位置");
// 根據(jù)配置文件構(gòu)建SqlSessionFactory
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(reader);
-----------------------------------------------------------------------------
//字節(jié)流 讀取配置文件
InputStream inputStream = Resources.getResourceAsStream("配置文件位置");
// 根據(jù)配置文件構(gòu)建SqlSessionFactory
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(inputStream);
----------------------------------------------------------------------------
//類方式可以自己去嘗試編寫一下,開發(fā)中常用這種方式
? SqlSessionFactory對象是線程安全的,它一旦被創(chuàng)建,在整個應(yīng)用程序執(zhí)行期間都會存在。如果我們多次創(chuàng)建同一個數(shù)據(jù)庫的SqlSessionFactory對象,那么該數(shù)據(jù)庫的資源將很容易被耗盡。通常每一個數(shù)據(jù)庫都只創(chuàng)建一個SqlSessionFactory對象,所以在構(gòu)建SqlSessionFactory對象時,建議使用單例模式。
通過SqlSessionFactory的openSession()方法創(chuàng)建出SqlSession來操作數(shù)據(jù)庫
方法名稱 | 描述 |
---|---|
SqlSession openSession() | 開啟一個事務(wù)。 |
SqlSession openSession(Boolean autoCommit) | 參數(shù)autoCommit可設(shè)置是否開啟事務(wù)。 |
SqlSession openSession(Connection connection) | 參數(shù)connection可提供自定義連接。 |
SqlSession openSession(TransactionIsolationLevel level) | 參數(shù)level可設(shè)置隔離級別。 |
SqlSession openSession(ExecutorType execType) | 參數(shù)execType有三個可選值。 |
SqlSession openSession(ExecutorType execType,Boolean autoCommit) | 參數(shù)execType有三個可選值。 |
SqlSession openSession(ExecutorType execType, Connection connection) | 參數(shù)ExecutorType有三個可選值。 |
openSession(ExecutorType execType)簡稱execType參數(shù)值 有三個可選值:
- ExecutorType.SIMPLE:表示為每條語句創(chuàng)建一條新的預(yù)處理語句。
- ExecutorType.REUSE:表示會復(fù)用預(yù)處理語句。
- ExecutorType.BATCH:表示會批量執(zhí)行所有更新語句。
簡單理解,知道有這些方法設(shè)置就行后面才會用到。
SqlSession對象的作用
? SqlSession是MyBatis框架中另一個重要的對象,它是應(yīng)用程序與持久層之間執(zhí)行交互操作的一個單線程對象,主要作用是執(zhí)行持久化操作,類似于JDBC中的Connection。SqlSession對象包含了執(zhí)行SQL操作的方法,由于其底層封裝了JDBC連接,所以可以直接使用SqlSession對象來執(zhí)行已映射的SQL語句。
以下是一些常見的 SqlSession
方法:
-
selectOne(String statement, Object parameter): 執(zhí)行查詢并返回單個結(jié)果對象。
statement
是 SQL 語句的唯一標(biāo)識符,parameter
是查詢所需的參數(shù)。 -
selectList(String statement, Object parameter): 執(zhí)行查詢并返回結(jié)果列表。與
selectOne
類似,只是返回多個結(jié)果。 -
insert(String statement, Object parameter): 執(zhí)行插入操作,插入一條數(shù)據(jù)。
-
update(String statement, Object parameter): 執(zhí)行更新操作,更新數(shù)據(jù)。
-
delete(String statement, Object parameter): 執(zhí)行刪除操作,刪除數(shù)據(jù)。
-
commit(): 提交事務(wù)。
-
rollback(): 回滾事務(wù)。
-
close(): 關(guān)閉
SqlSession
實例。 -
getMapper(Class type): 獲取一個 Mapper 接口的實例,通過該實例可以調(diào)用映射文件中配置的 SQL 語句。
示例使用:
SqlSession session = sqlSessionFactory.openSession();
// 查詢單個結(jié)果
User user = session.selectOne("getUserById", 1);
// 查詢結(jié)果列表
List<User> userList = session.selectList("getAllUsers");
// 插入數(shù)據(jù)
User newUser = new User("John", "john@example.com");
int rowsInserted = session.insert("insertUser", newUser);
// 更新數(shù)據(jù)
User updatedUser = new User(1, "UpdatedName", "updated@example.com");
int rowsUpdated = session.update("updateUser", updatedUser);
// 刪除數(shù)據(jù)
int rowsDeleted = session.delete("deleteUser", 1);
// 提交事務(wù)
session.commit();
// 關(guān)閉 SqlSession
session.close();
上述示例中的方法參數(shù) "getUserById"
、"getAllUsers"
、"insertUser"
、"updateUser"
、"deleteUser"
是 MyBatis 配置文件中定義的 SQL 語句的唯一標(biāo)識符。這些標(biāo)識符與映射文件中的配置相對應(yīng),可以在映射文件中查找具體的 SQL 語句。
PS(名詞科普):提交事務(wù)
? 在數(shù)據(jù)庫中,事務(wù)(Transaction)是指一系列的數(shù)據(jù)庫操作,這些操作被當(dāng)作一個單獨的工作單元來執(zhí)行。事務(wù)的目的是確保數(shù)據(jù)庫的一組操作要么全部執(zhí)行成功,要么全部失敗,以保持?jǐn)?shù)據(jù)的一致性和完整性。
提交事務(wù)(Commit Transaction)是指將之前在一個事務(wù)中進行的一系列數(shù)據(jù)庫操作永久地保存到數(shù)據(jù)庫中,使這些操作對其他事務(wù)可見。當(dāng)你執(zhí)行提交事務(wù)操作時,數(shù)據(jù)庫會將所有的變更持久保存,而且這些變更對其他事務(wù)和查詢都是可見的。如果事務(wù)中的所有操作都執(zhí)行成功,那么提交事務(wù)會將這些操作永久保存到數(shù)據(jù)庫中。如果事務(wù)中的任何一個操作失敗,那么整個事務(wù)都會被回滾(Rollback),即取消之前的操作,使數(shù)據(jù)庫回到事務(wù)開始前的狀態(tài)。
提交事務(wù)是數(shù)據(jù)庫管理系統(tǒng)中確保數(shù)據(jù)一致性和持久性的重要機制之一,它確保了在事務(wù)執(zhí)行完畢后,對數(shù)據(jù)的變更是持久保存的,而不會因為系統(tǒng)崩潰等情況而丟失。
SqlSession對象的使用范圍:
? 每一個線程都應(yīng)該有一個自己的SqlSession對象,并且該對象不能共享。SqlSession對象是線程不安全的,因此其使用范圍最好在一次請求或一個方法中,絕不能將其放在類的靜態(tài)字段、對象字段或任何類型的管理范圍(如Servlet的HttpSession)中使用。SqlSession對象使用完之后,要及時的關(guān)閉,SqlSession對象通常放在finally塊中關(guān)閉,代碼如下所示。
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
// 此處執(zhí)行持久化操作
} finally { sqlSession.close(); }
二、MyBatis核心配置文件
其中的主要元素如下:
以下是一些核心配置文件和配置項的含義(“”內(nèi)的要重點掌握一下):
- properties: 用于指定一些全局的屬性和變量,這些屬性可以在整個配置文件中使用。
- “settings”: 用于配置 MyBatis 的全局性設(shè)置,例如緩存、延遲加載等。
- ”typeAliases“: 用于配置類型別名,使得在映射文件中可以使用簡短的別名來引用 Java 類。
- typeHandlers: 用于配置類型處理器,用于將數(shù)據(jù)庫中的數(shù)據(jù)類型映射為 Java 類型。
- objectFactory: 用于配置對象工廠,可以通過對象工廠來創(chuàng)建結(jié)果對象的實例。
- plugins: 用于配置插件,插件可以攔截 MyBatis 的一些操作,擴展其功能。
- environments: 用于配置不同的運行環(huán)境,比如開發(fā)環(huán)境、測試環(huán)境和生產(chǎn)環(huán)境。
-
environment: 在
environments
中配置的運行環(huán)境,可以指定transactionManager
和dataSource
。 - transactionManager: 用于配置事務(wù)管理器,管理數(shù)據(jù)庫連接的生命周期和事務(wù)的提交與回滾。
- dataSource: 用于配置數(shù)據(jù)源,包括數(shù)據(jù)庫連接的基本信息。
- mappers: 用于指定映射器接口的位置,即映射文件的位置。
? 元素是整個XML配置文件的根元素,相當(dāng)于MyBatis各元素的管理員。有很多子元素,MyBatis的核心配置就是通過這些子元素完成的,子元素的順序盡量按照上述的編號順序,并且需要在 標(biāo)簽對中即可。
這里重點講一下****的配置元素:
配置參數(shù) | 描述 |
---|---|
cacheEnabled | 用于配置是否開啟緩存。 |
lazyLoadingEnabled | 延遲加載的全局開關(guān)。 |
aggressiveLazyLoading | 關(guān)聯(lián)對象屬性的延遲加載開關(guān)。 |
multipleResultSetsEnabled | 是否允許單一語句返回多結(jié)果集(需要兼容驅(qū)動)。 |
useColumnLabel | 使用列標(biāo)簽代替列名。 |
useGeneratedKeys | 允許JDBC支持自動生成主鍵,需要驅(qū)動兼容。 |
autoMappingBehavior | 指定MyBatis應(yīng)如何自動映射列到字段或?qū)傩浴?/td> |
defaultExecutorType | 配置默認的執(zhí)行器。 |
defaultStatementTimeout | 配置超時時間,它決定驅(qū)動等待數(shù)據(jù)庫響應(yīng)的秒數(shù)。 |
mapUnderscoreToCamelCase | 是否開啟自動駝峰命名規(guī)則(camel case)映射。 |
jdbcTypeForNull | 當(dāng)沒有為參數(shù)提供特定的JDBC類型時,為空值指定JDBC類型。 |
格式如下:
<settings>
<!-- 是否開啟緩存 -->
<setting name="cacheEnabled" value="true" />
<!-- 是否開啟延遲加載,如果開啟,所有關(guān)聯(lián)對象都會延遲加載 -->
<setting name="lazyLoadingEnabled" value="true" />
<!-- 是否開啟關(guān)聯(lián)對象屬性的延遲加載,如果開啟,對任意延遲屬性的調(diào)用都
會使用帶有延遲加載屬性的對象向完整加載,否則每種屬性都按需加載 -->
<setting name="aggressiveLazyLoading" value="true" />
...
</settings>
這里重點講一下typeAiases元素:
? 核心配置文件若要引用一個POJO實體類,需要輸入POJO實體類的全限定類名,而全限定類名比較冗長,如果直接輸入,很容易拼寫錯誤。例如,POJO實體類User的全限定類名是com.itheima.pojo.User,未設(shè)置別名之前,映射文件的select語句塊若要引用POJO類User,必須使用其全限定類名,引用代碼如下。
<select id="findById" parameterType="int" resultType="com.example.pojo.User">
select * from users where id = #{id}
</select>
設(shè)置別名的方式如下:
①在元素下,使用多個元素為每一個全限定類逐個配置別名。
<typeAliases>
<typeAlias alias="User" type="com.example.pojo.User"/>
<typeAlias alias="Student" type="com.example.pojo.Student"/>
<typeAlias alias="Employee" type="com.example.pojo.Employee"/>
<typeAlias alias="Animal" type="com.example.pojo.Animal"/>
</typeAliases>
<environments>
②通過自動掃描包的形式自定義別名。
<typeAliases>
<package name="com.example.pojo"/>
</typeAliases>
<environments>
? 注意要放在 environments上面,不然程序會報錯,Error building SqlSession。
? 除了可以使用typeAliases元素為實體類自定義別名外,MyBatis框架還為許多常見的Java類型(如數(shù)值、字符串、日期和集合等)提供了相應(yīng)的默認別名。例如別名_byte映射類型byte、_long映射類型long等,別名可以在MyBatis中直接使用,但由于別名不區(qū)分大小寫,所以在使用時要注意重復(fù)定義的覆蓋問題。
? 并且設(shè)置完別名以后,pojo包里面的類都會自動識別,所以Mapper.xml文件里面也需要修改一下。如下圖得從pojo.PasswordMS 修改?成 PasswordMS:
三、MyBatis映射文件及其元素的使用
上一篇文章,我們后面自己寫一個插入的sql語句,現(xiàn)在要檢測一下能不能正確的映射到數(shù)據(jù)庫中。
結(jié)果發(fā)現(xiàn),程序一直轉(zhuǎn)動,但是不能在終端輸入,也沒辦法繼續(xù)進行。神奇的是也不報錯,在我查閱資料后發(fā)現(xiàn),原因如下
? 在JUnit測試中,無法直接通過終端輸入?yún)?shù)。JUnit測試是自動化測試,在測試過程中是無法進行交互操作的。
解決辦法:pom中引入Mockito,就可以模擬用戶輸入了
<!-- Mockito 依賴 -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.0.0</version>
<scope>test</scope>
</dependency>
測試類也要修改
lass PasswordMSTest {
private Logger logger= Logger.getLogger(PasswordMSTest.class);
private InputStream originalSystemIn;
private ByteArrayInputStream simulatedInput;
@BeforeEach
public void setUp() {
originalSystemIn = System.in;
}
@AfterEach
public void tearDown() {
System.setIn(originalSystemIn);
}
@org.junit.jupiter.api.Test
void insertOneIntoPasswordMS() {
//讀取文件名:
String resources="mybatis-config.xml";
//創(chuàng)建流
Reader reader = null;
try{
reader = Resources.getResourceAsReader(resources);
}catch (IOException e){
e.printStackTrace();
}
//這里就是你模擬輸入用戶輸入的數(shù)據(jù)
String input = "John\n123456\n1234567890\nexample1.com\nhttps://example1.com\nicon.png\nSocial\n";
// 將標(biāo)準(zhǔn)輸入重定向到模擬輸入流
InputStream inputStream = new ByteArrayInputStream(input.getBytes());
System.setIn(inputStream);
PasswordMS passwordMS=new PasswordMS();
Scanner scanner = new Scanner(System.in);
System.out.println("請輸入你想要存儲的賬號名:");
passwordMS.setAccount(scanner.nextLine());
System.out.println("請輸入你想要存儲的賬號密碼:");
passwordMS.setPassword(scanner.nextLine());
System.out.println("請輸入你想要存儲的與該賬號綁定的手機號:");
passwordMS.setPhoneNumber(scanner.nextLine());
System.out.println("請輸入你想要存儲的賬號所屬網(wǎng)站名:");
passwordMS.setWebsiteName(scanner.nextLine());
System.out.println("請輸入你想要存儲的網(wǎng)址URL:");
passwordMS.setWebsiteURL(scanner.nextLine());
System.out.println("請輸入網(wǎng)站的縮略圖或者圖標(biāo):");
String WebsiteImage=scanner.nextLine();
Optional<String> optionalS = Optional.ofNullable(WebsiteImage);
passwordMS.setWebsiteImage(optionalS.orElse("Sorry 還沒有"));//這里使用了optional對象來判斷是否為空,空則為默認值
System.out.println("請輸入該賬號的描述比如類別:");
passwordMS.setAccountDescription(scanner.nextLine());
//初始化mybatis數(shù)據(jù)庫,創(chuàng)建SqlSessionFactory類的實例
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
//創(chuàng)建SqlSession實例
SqlSession session = sqlSessionFactory.openSession();
//傳入?yún)?shù)查詢,返回結(jié)果
session.insert("insertOne",passwordMS);
session.commit();
session.close();
}
}
輸出結(jié)果如下:
數(shù)據(jù)庫中也成功插入記錄
現(xiàn)在回過頭來看,每個測試類其實有很大一部分都是重復(fù)的
這段代碼的作用是打開mybatis-config.xml文件,用它連上數(shù)據(jù)庫,然后打開數(shù)據(jù)連接,這段代碼經(jīng)常會在進行數(shù)據(jù)操作之前用到,但是我們又不想每次都復(fù)制粘貼它,這時我們可以把它封裝起來。直接調(diào)用。
操作如下:
①java包下新建一個package為utils(一般默認為工具包)
②utils包下新建一個類為:MyBatisUtil.java
代碼如下:
package utils;
import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MyBatisUtil {
private static SqlSessionFactory factory;
static{在靜態(tài)代碼塊中,factory只會被創(chuàng)建一次
System.out.println("static factory===============");
try {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
factory = new SqlSessionFactoryBuilder().build(is);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static SqlSession createSqlSession(){
return factory.openSession(false);//true為自動提交事務(wù)
}
public static void closeSqlSession(SqlSession sqlSession){
if(null != sqlSession)
sqlSession.close();
}
}
? 通過以上”靜態(tài)類“的方式來保證Sql Session Factory實例只被創(chuàng)建一次,當(dāng)然,最佳的解決方案是使用Spring框架來管理Sql Session Factory的單例模式生命周期。關(guān)于和Spring的集成,我們會在后面使用到中進行講解。
完成以上步驟以后,我們就能去優(yōu)化我們的測試類了
進行測試,還是能夠正常運行,也能寫入數(shù)據(jù)庫進行交互。
使用Mybatis進行數(shù)據(jù)修改、刪除操作
自行編寫補充mapper映射文件嗷
總結(jié)
? 這是第二天對SSM框架的學(xué)習(xí),深入了解了Mybatis的核心對象SqlSessionFactoryBuilder,掌握MyBatis核心配置文件以及元素的使用,也掌握MyBatis映射文件及其元素的使用。想要跟著學(xué)習(xí)的可以去我的資源里面找對應(yīng)的文件下載,我的md文件也會發(fā)上去,項目文件會上傳可以自己跟著學(xué)習(xí)一下。
PS:sql語句自己編寫┗|`O′|┛ 嗷~~
作者:Stevedash文章來源:http://www.zghlxwxcb.cn/news/detail-664983.html
發(fā)表于:2023年8月21日 22點45分文章來源地址http://www.zghlxwxcb.cn/news/detail-664983.html
注:本文內(nèi)容基于個人學(xué)習(xí)理解,如有錯誤或疏漏,歡迎指正。感謝閱讀!如果覺得有幫助,請點贊和分享。
到了這里,關(guān)于SSM框架的學(xué)習(xí)與應(yīng)用(Spring + Spring MVC + MyBatis)-Java EE企業(yè)級應(yīng)用開發(fā)學(xué)習(xí)記錄(第二天)Mybatis的深入學(xué)習(xí)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!