Java開發(fā)可離不開的@Mapper注解舉例詳解
前言
最近在學(xué) Java 編程的時候,碰到的一個超級厲害的 “小助手”,叫 @Mapper 注解。你們知道我平時搗鼓那些項目的時候,和數(shù)據(jù)庫打交道那叫一個頭疼,各種復(fù)雜的操作,寫得代碼又臭又長。但自從我用上了 @Mapper 注解,哎呀媽呀,就像給我的編程之路開了掛,代碼變得簡潔明了,開發(fā)效率蹭蹭地往上漲,整個人都輕松多了。而且我跟你們說,我去實習(xí)的時候發(fā)現(xiàn),還有了解行業(yè)信息的時候,那些大公司、小公司,大部分搞 Java 開發(fā)的項目里都在用這個注解,要是咱掌握了,不管是以后找工作,還是在公司里想要升職加薪,那都更有優(yōu)勢,就好像握住了一把開啟職場大門的金鑰匙,所以大家可得跟著我好好學(xué)學(xué)。
啥是 @Mapper,給家人講明白
(一)通俗解釋
咱先通俗地講講 @Mapper 注解是啥。你們就把它想象成一個超級快遞員,咱們寫的 Java 代碼呢,就像是一個個寄件人和收件人,數(shù)據(jù)庫呢,就是那個大倉庫。這個 @Mapper 注解快遞員,就在 Java 代碼和數(shù)據(jù)庫之間跑來跑去,傳遞數(shù)據(jù)。比如說,咱們要往數(shù)據(jù)庫里存?zhèn)€新用戶的信息,或者從數(shù)據(jù)庫里把某個用戶的資料找出來,只要給這個快遞員下達指令,也就是在代碼里用好 @Mapper 注解,它就能麻溜地把數(shù)據(jù)存儲、查詢這些事兒給辦好,讓咱們不用操心那些復(fù)雜的底層操作,輕松實現(xiàn)咱們想要的功能,是不是很神奇?
(二)專業(yè)剖析
再深入一點,從專業(yè)角度來說,@Mapper 注解在 MyBatis 框架里可是個關(guān)鍵角色。MyBatis 是啥呢?它是一個超好用的持久層框架,能幫咱們把 Java 程序和數(shù)據(jù)庫連接得穩(wěn)穩(wěn)當當。而 @Mapper 注解呢,就是在這個連接過程中起重要作用。它讓咱們可以通過定義接口,在接口里寫各種方法,這些方法呢,又能和咱們寫在 XML 文件里,或者直接用注解寫的 SQL 語句一一對應(yīng)起來,實現(xiàn)精準的數(shù)據(jù)庫交互。比如說,咱們在接口里定義一個查找用戶的方法,然后用 @Mapper 注解標記這個接口,再配上對應(yīng)的 SQL 語句,當咱們在 Java 代碼里調(diào)用這個接口方法的時候,MyBatis 就知道要去數(shù)據(jù)庫里執(zhí)行哪條 SQL 語句,把咱們想要的數(shù)據(jù)找回來,是不是覺得這背后的設(shè)計很精妙?
動手實操,代碼搞起
(一)環(huán)境搭建準備
光說不練假把式,咱們現(xiàn)在就動手實操起來。第一步,得搭建開發(fā)環(huán)境,就像蓋房子得先打地基一樣。咱們先創(chuàng)建一個 Maven 項目,要是不知道 Maven 是啥,它就像是一個貼心的管家,幫咱們把項目需要的各種庫文件都管得井井有條。在咱們常用的開發(fā)工具里,像 Intellij IDEA,打開之后,按照向?qū)б徊揭徊絹?,先填好項目的基本信息,比?“Group”(一般是公司域名倒著寫,咱們自己練手就隨便填個,像 “com.example”)、“Artifact”(項目名,自己起個喜歡的就行,像 “demo-project”)。然后,在項目的 pom.xml 文件里,得添加 MyBatis 以及咱們要連接的數(shù)據(jù)庫驅(qū)動依賴。比如說,如果咱們連接 MySQL 數(shù)據(jù)庫,就得加上這些:
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
這里的 “org.mybatis.spring.boot:mybatis-spring-boot-starter” 就是 MyBatis 在 Spring Boot 項目里的啟動器,它把 MyBatis 相關(guān)的東西都整合好了,方便咱們使用;“mysql:mysql-connector-java” 就是連接 MySQL 的驅(qū)動。把這些依賴加好,咱們的開發(fā)環(huán)境就算是搭好了,就可以開始下一步啦。
(二)定義實體類
環(huán)境搭好了,接下來咱們定義實體類。以用戶信息為例,咱們在項目的 “com.example.entity” 目錄下(要是沒有這個目錄,就新建一個),創(chuàng)建一個 User 實體類,代碼如下:
package com.example.entity;
public class User {
private Long id;
// 用戶ID,每個用戶獨一無二的標識
private String name;
// 用戶姓名
private String email;
// 用戶郵箱
// 這里得生成get、set方法,方便MyBatis存取數(shù)據(jù)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
這個 User 實體類就像是一個裝用戶信息的小盒子,里面的屬性對應(yīng)著數(shù)據(jù)庫里用戶表的字段,通過 get、set 方法,MyBatis 就能方便地把數(shù)據(jù)取出來放進去,是不是很好理解?
(三)創(chuàng)建 Mapper 接口
有了實體類,咱們接著創(chuàng)建 Mapper 接口。在 “com.example.mapper” 目錄下(同樣,沒有就新建),創(chuàng)建一個 UserMapper 接口,代碼如下:
package com.example.mapper;
import com.example.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Update;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface UserMapper {
@Insert("INSERT INTO user (name, email) VALUES (#{name}, #{email})")
void insertUser(User user);
@Delete("DELETE FROM user WHERE id = #{id}")
void deleteUserById(Long id);
@Update("UPDATE user SET name = #{name}, email = #{email} WHERE id = #{id}")
void updateUser(User user);
@Select("SELECT * FROM user WHERE id = #{id}")
User selectUserById(Long id);
@Select("SELECT * FROM user")
List<User> selectAllUsers();
}
這里的 @Mapper 注解就像給這個接口貼上了一個特殊的標簽,告訴 MyBatis 這個接口很重要,要重點關(guān)注。接口里的每個方法,都對應(yīng)著一條 SQL 操作,像插入用戶信息、刪除用戶、更新用戶資料、根據(jù) ID 查找用戶、查找所有用戶,咱們都用對應(yīng)的 @Insert、@Delete、@Update、@Select 注解把 SQL 語句寫在方法上,而且注意看,這些 SQL 語句里的 #{參數(shù)名},就能自動把咱們傳入的 User 實體類里的對應(yīng)屬性值取出來,用到 SQL 語句里,是不是超級智能?
(四)編寫 SQL 語句
剛才咱們在 Mapper 接口里已經(jīng)寫了一些簡單的 SQL 語句,不過有時候,咱們的需求會更復(fù)雜一點。比如說,咱們要根據(jù)用戶的姓名和郵箱模糊查詢用戶,這時候就可以用動態(tài) SQL。在 UserMapper 接口里,咱們再加一個方法:
@Select("<script>" +
"SELECT * FROM user " +
"<where>" +
"<if test='name!= null'>" +
"AND name LIKE '%${name}%'" +
"</if>" +
"<if test='email!= null'>" +
"AND email LIKE '%${email}%'" +
"</if>" +
"</where>" +
"</script>")
List<User> selectUsersByNameAndEmail(User user);
這里用了<if>標簽來判斷傳入的用戶姓名和郵箱是不是為空,如果不為空,就拼接到 SQL 語句里,實現(xiàn)模糊查詢,是不是很靈活?而且注意,這里用的是參數(shù)名,它和參數(shù)名有點不一樣,{參數(shù)名} 是直接把參數(shù)值拼接到 SQL 語句里,適合這種模糊查詢的場景,不過要注意防止 SQL 注入哦,咱們后面再詳細說。
(五)配置文件完善
代碼寫得差不多了,咱們還得完善配置文件。在 Spring Boot 項目里,一般是在 application.properties 或者 application.xml 文件里設(shè)置數(shù)據(jù)庫連接信息。比如說,在 application.properties 文件里,咱們得寫上這些:
spring.datasource.url=jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC spring.datasource.username=root spring.datasource.password=123456 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
這里的 “spring.datasource.url” 就是數(shù)據(jù)庫的連接地址,“localhost” 表示本地數(shù)據(jù)庫,“3306” 是 MySQL 的默認端口,“mydb” 是數(shù)據(jù)庫名,后面的參數(shù) “useSSL=false” 是說不用 SSL 加密連接(在本地測試可以這樣,正式環(huán)境可能需要根據(jù)情況調(diào)整),“serverTimezone=UTC” 是設(shè)置時區(qū),避免時間上的一些問題;“spring.datasource.username” 和 “spring.datasource.password” 就是登錄數(shù)據(jù)庫的用戶名和密碼,這得根據(jù)咱們自己安裝數(shù)據(jù)庫時設(shè)置的來填;“spring.datasource.driver-class-name” 就是指定數(shù)據(jù)庫驅(qū)動類,這里是 MySQL 的驅(qū)動。把這些配置寫好,就像給咱們的程序指明了數(shù)據(jù)倉庫的位置,它就能順利找到數(shù)據(jù)庫,開始干活啦。
(六)測試驗證功能
最后,咱們得測試驗證一下咱們寫的代碼是不是好使。咱們在項目的測試類里,比如說 “com.example.test” 目錄下(沒有就新建),創(chuàng)建一個 UserMapperTest 類,代碼如下:
package com.example.test;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import com.example.entity.User;
import com.example.mapper.UserMapper;
import java.util.List;
@SpringBootTest
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
public void testInsertUser() {
User user = new User();
user.setName("張三");
user.setEmail("zhangsan@example.com");
userMapper.insertUser(user);
}
@Test
public void testSelectUserById() {
Long id = 1L;
User user = userMapper.selectUserById(id);
assert user!= null;
System.out.println("用戶姓名:" + user.getName() + ", 郵箱:" + user.getEmail());
}
@Test
public void testSelectAllUsers() {
List<User> userList = userMapper.selectAllUsers();
for (User user : userList) {
System.out.println("用戶姓名:" + user.getName() + ", 郵箱:" + user.getEmail());
}
}
}
這里用了 Spring Boot 的測試框架,通過 @Autowired 注解把咱們之前寫的 UserMapper 接口注入進來,然后在各個測試方法里,分別調(diào)用插入用戶、根據(jù) ID 查找用戶、查找所有用戶的方法,用斷言來驗證結(jié)果,比如說查找用戶的時候,斷言找到的用戶不為空,這樣就能確保咱們的代碼能正常工作,就像考試后核對答案一樣,心里踏實多了。
深入探索,高級玩法揭秘
(一)動態(tài) SQL 語句運用
剛才咱們簡單介紹了動態(tài) SQL,現(xiàn)在深入講講。除了剛才用的<if>標簽,還有<choose>、<where>等標簽也很常用。比如說,咱們要實現(xiàn)一個復(fù)雜的查詢,根據(jù)不同的條件查找用戶,有時候按姓名查,有時候按郵箱查,有時候按年齡范圍查,這時候就可以用<choose>標簽,代碼如下:
@Select("<script>" +
"SELECT * FROM user " +
"<where>" +
"<choose>" +
"<when test='name!= null'>" +
"AND name LIKE '%${name}%'" +
"</when>" +
"<when test='email!= null'>" +
"AND email LIKE '%${email}%'" +
"</when>" +
"<when test='age!= null'>" +
"AND age BETWEEN #{age.start} AND #{age.end}" +
"</when>" +
"</choose>" +
"</where>" +
"</script>")
List<User> selectUsersByCondition(User user, AgeRange age);
這里假設(shè)咱們還有一個 AgeRange 類,用來表示年齡范圍,通過<choose>標簽,咱們可以根據(jù)傳入的不同條件,靈活地生成不同的 SQL 語句,滿足各種復(fù)雜的查詢需求,是不是很強大?
(二)關(guān)聯(lián)查詢與結(jié)果映射
再來講講關(guān)聯(lián)查詢,比如說咱們的項目里有用戶表和訂單表,一個用戶可能有多個訂單,咱們有時候需要查詢用戶及其訂單信息,這時候就可以用 @Results、@ResultMap 注解。首先,咱們得在 UserMapper 接口里定義一個方法:
@Select("SELECT u.*, o.* FROM user u LEFT JOIN order o ON u.id = o.user_id")
@Results(id = "userWithOrdersResult", value = {
@Result(property = "id", column = "u.id"),
@Result(property = "name", column = "u.name"),
@Result(property = "email", column = "u.email"),
@Result(property = "orders", javaType = List.class, many = @Many(select = "com.example.mapper.OrderMapper.selectOrdersByUserId")),
})
User getUserWithOrders(Long id);
這里的 @Select 注解寫了關(guān)聯(lián)查詢的 SQL 語句,通過 LEFT JOIN 把用戶表和訂單表連接起來。@Results 注解用來定義結(jié)果映射,把查詢結(jié)果正確地映射到 User 實體類和它關(guān)聯(lián)的訂單列表上,其中 @Result 注解對應(yīng)著每個屬性的映射,對于訂單列表,咱們用 @Result 的 many 屬性,指定了一個子查詢,通過調(diào)用 OrderMapper 接口的 selectOrdersByUserId 方法,獲取用戶的訂單信息,是不是很巧妙?
常見問題排雷
(一)注解失效問題
在使用 @Mapper 注解的時候,有時候會遇到注解失效的問題。比如說,咱們明明寫了 @Mapper 注解,但是 MyBatis 好像沒看到一樣,接口方法調(diào)用就報錯。這可能是因為咱們沒有正確配置 MyBatis,讓它掃描到咱們的 Mapper 接口。在 Spring Boot 項目里,如果咱們用的是注解驅(qū)動的方式,得確保在啟動類上加上 @MapperScan 注解,指定 Mapper 接口所在的包,比如:
package com.example;
import org.springframework.boot.SpringBootApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.MapperScan;
@SpringBootApplication
@MapperScan("com.example.mapper")
public class DemoApplication {
public static void main(String[] args) {
SpringBootApplication.run(DemoApplication.class, args);
}
}
這里的 @MapperScan ("com.example.mapper") 就告訴 Spring Boot,去 “com.example.mapper” 這個包下掃描所有的 Mapper 接口,這樣就能解決注解失效的問題啦。
(二)SQL 語法錯誤排查
還有一個常見的問題就是 SQL 語法錯誤。咱們寫 SQL 語句的時候,不小心寫錯了,比如說少寫了個引號,或者關(guān)鍵字拼錯了,這時候程序運行就會報錯。遇到這種情況,咱們得學(xué)會從報錯信息里快速定位問題。一般來說,MyBatis 會給出比較詳細的報錯信息,告訴咱們是哪個 SQL 語句出錯了,在哪個位置,咱們根據(jù)這些信息,仔細檢查 SQL 語句,就能找到錯誤并改正。比如說,報錯信息里說 “near 'FROM user WHERE id = #{id}': syntax error”,咱們就知道是在 “FROM user WHERE id = #{id}” 這個語句里有語法錯誤,可能是少了個空格,或者關(guān)鍵字寫錯了,仔細一看,原來是 “DELETE” 寫成了 “DELET”,改正之后就沒問題啦。
總結(jié)
到此這篇關(guān)于Java中@Mapper注解舉例詳解的文章就介紹到這了,更多相關(guān)Java的@Mapper注解內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java.lang.Runtime.exec() Payload知識點詳解
在本篇文章里小編給大家整理的是一篇關(guān)于java.lang.Runtime.exec() Payload知識點相關(guān)內(nèi)容,有興趣的朋友們學(xué)習(xí)下。2020-03-03
MyBatis Plus like參數(shù)為百分號%查詢結(jié)果異常原因分析及解決
文章指出在MyBatisPlus使用LIKE查詢時,用戶輸入的%可能導(dǎo)致通配符誤匹配,推薦使用ESCAPE轉(zhuǎn)義功能,將%轉(zhuǎn)換為普通字符,既支持模糊查詢又避免全表匹配,提升準確性和性能2025-09-09
Spring整合SpringMVC與Mybatis(SSM)實現(xiàn)完整登錄功能流程詳解
開學(xué)學(xué)校開始講servlet 后期要求做一個登錄功能,這個使用SSM先只做個簡單的只帶登錄功能的,且項目使用了MyBatis-Plus來簡化開發(fā)流程??辞闆r決定要不要升級功能或者換個寫法2022-09-09
SpringBoot+Mybatis plus實現(xiàn)多數(shù)據(jù)源整合的實踐
本文主要介紹了SpringBoot+Mybatis plus實現(xiàn)多數(shù)據(jù)源整合的實踐,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-10-10
SpringBoot集成SFTP客戶端實現(xiàn)文件上傳下載實例
這篇文章主要為大家介紹了SpringBoot集成SFTP客戶端實現(xiàn)文件上傳下載實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-08-08
springboot jpaRepository為何一定要對Entity序列化
這篇文章主要介紹了springboot jpaRepository為何一定要對Entity序列化,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12

