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

