前言
公司近期新的小專案要移植到JBoss
,意味者強迫升級JDK
啦!
pull
專案下來,開分支自己研究一下已經訂好的架構,嘗試加上新的endpoint
玩玩看。很好奇如果沒有那些複雜的抽象,最小可運作的程式會是長什麼樣子,再回來體會一下什麼叫過度設計(誤)。本篇不會附上過多實際的程式碼,取而代之是試誤過程中遇到的問題,實際檢視
log
並且排除問題後,再回來跟copilot
的覆盤記錄。什麼是MyBatis
下列是詢問結果:
MyBatis 是一個持久化框架,用於簡化 Java 應用程序與資料庫之間的交互。它的主要功能包括:
- ORM(對象關係映射)框架:MyBatis 提供了簡單而靈活的 ORM 功能,通過 XML 或註解將 SQL 查詢與 Java 方法關聯。
- SQL 自動映射:MyBatis 可以將 SQL 查詢結果自動映射為 Java 對象,減少手動編碼的繁瑣過程。
- 動態 SQL:支持動態生成 SQL 語句,基於參數條件構建複雜的查詢語句。
- 緩存機制:提供一級緩存和二級緩存,提高查詢性能。
- 簡潔靈活:相對於其他 ORM 框架(如 Hibernate),MyBatis 更加輕量級和靈活,適合複雜 SQL 查詢的需求。
恩,不懂的人光是第一句話就陣亡了,對吧?
不妨試者想想,在沒有這些持久化框架persistence framework
的情況下,要怎麼透過java
程式跟資料庫
溝通,進行資料操作?
- 自己建立JDBC connection
- 寫SQL透過cursor拿到資料
- 進行物件轉換
- 交易管理
諸如此類純手動需要花費很大心力的作業,可以都透過框架幫助處理。
專案架構
src/
|-- main/
| |-- java/
| |-- com/
| |-- example/
| |-- demo/
| |-- DemoApplication.java
| |-- controller/
| |-- StudentController.java
| |-- mapper/
| |-- StudentMapper.java
| |-- model/
| |-- Student.java
| |-- service/
| |-- StudentService.java
|-- main/resources/
| |-- application.properties
| |-- mapper/
| |-- StudentMapper.xml
請copilot
提供給我一個最簡單的RESTful API
,只要get request拿
取學生資料表全部資訊回傳json
格式,架構示例如上。
運作過程簡述會是:
- 瀏覽器或是測試工具發送請求到指定
url endpoint
url endpoint
對應到controller
內特定的方法進行處理- 該方法決定呼叫哪些
service
進行處理 service
透過Mapper
對資料庫操作,拿回指定資料,轉換成model
再回傳
Mybatis
負責的部分是提供了Mapper Interface
,其中簡單的小專案可以採用把SQL
寫在Annotation
中,複雜語法或大型專案,則可以選擇另外定義XML
檔案。
下面問著問著就變成USER
了,不過不影響觀念上的本質。
Annotation
@Mapper
public interface UserMapper {
@Select("SELECT id, name, email FROM users WHERE id = #{id}")
User selectUser(int id);
}
也可以把SQL
另外定義成常數,再放入annotation
XML
@Mapper
public interface UserMapper {
User selectUser(@Param("id") int id);
}
<?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.UserMapper">
<select id="selectUser" resultType="com.example.User">
SELECT id, name, email
FROM users
WHERE id = #{id}
</select>
</mapper>
官方文件似乎是建議使用XML,可以做較多變化跟處理,我自己則有幾個開發上不太喜歡的地方:
- XML編輯上沒有語法提示,或者要另外安裝擴充套件
- 配置上有需多小地方要注意
- 動態SQL會讓版面變的破碎,除錯時要多做處理
後記
解決MyBatis:There is no setter for property named
問題是發生在執行SQL後,拿到資料要轉換成對應的model
發生的狀況。網路上只找到幾個可能的狀況:
resultMap
中,轉換的property
有空格- 配置路徑是否有打錯
- 真的沒實作
setter
一開始我是採用record
進行實作,使用Annotation
正常運作,但透過XML
才發生問題,問了得到下列答覆:
這個問題確實很有趣!在使用 @Select
註解時,與 XML 配置相比,有一些差異可能影響 record
類的行為。
- MyBatis Mapper 註解:當你使用
@Select
註解時,MyBatis 會更加依賴構造函數參數而不是setter
方法來實例化對象。因為record
類本身就是不可變的,MyBatis 可以自動識別構造函數並使用它來創建對象。這與 XML 配置時依賴setter
方法的行為有所不同。 - 語法與配置:通過註解方式,配置更加簡潔,避免了大量的 XML 配置文件。對於一些簡單的查詢和操作,使用註解的方式更直接,也更符合現代開發習慣。
- 註解解析:在運行時,MyBatis 處理註解和處理 XML 配置的方式可能會有所不同。註解直接與 Java 代碼綁定,解析過程更緊密,而 XML 配置需要額外的映射步驟。
意思是record
是immutable
的設計,所以本來就沒有提供setter,
而XML
配置的mapper
是認setter
來進行轉換處理,跟Annotation
不一樣,是透過constructor
進行轉換。
沒辦法,為了制度及一些相容性問題,只好改回去使用Lombok
的@Data
。