Mybatis Mapper接口和xml綁定的多種方式、內(nèi)部實(shí)現(xiàn)原理和過程解析
一、綁定方式
1. XML文件方式
在Mybatis中,我們需要?jiǎng)?chuàng)建一個(gè)與實(shí)體類對(duì)應(yīng)的Mapper接口,然后在該接口上添加方法,這些方法對(duì)應(yīng)著SQL語(yǔ)句。然后,我們需要?jiǎng)?chuàng)建一個(gè)XML文件,這個(gè)文件中包含了SQL語(yǔ)句和映射關(guān)系。
例如,我們有一個(gè)User實(shí)體類和一個(gè)UserMapper接口:
public interface UserMapper { User getUserById(int id); }
然后,我們可以創(chuàng)建一個(gè)名為UserMapper.xml的文件,內(nèi)容如下:
<mapper namespace="com.example.dao.UserMapper"> <select id="getUserById" resultType="com.example.entity.User"> SELECT * FROM user WHERE id = #{id} </select> </mapper>
在這個(gè)XML文件中,namespace屬性指定了Mapper接口的全限定名,id屬性指定了SQL語(yǔ)句的唯一標(biāo)識(shí)符,resultType屬性指定了查詢結(jié)果的類型。
2. 注解方式
Mybatis也支持通過注解的方式來(lái)進(jìn)行映射。首先,需要在Mapper接口上添加@Mapper注解,然后在方法上添加@Select、@Insert、@Update、@Delete等注解來(lái)指定SQL語(yǔ)句。
例如,我們可以將上面的UserMapper接口改為注解方式:
import org.apache.ibatis.annotations.*; @Mapper public interface UserMapper { @Select("SELECT * FROM user WHERE id = #{id}") User getUserById(int id); }
在這個(gè)例子中,@Mapper注解表示這是一個(gè)Mapper接口,@Select注解表示這是一個(gè)查詢語(yǔ)句,#{id}是參數(shù)占位符。
3. 需要注意
啟動(dòng)類上添加@MapperScan注解指定掃描路徑
@SpringBootApplication @MapperScan("com.example.mapper") // 指定掃描路徑 public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
不用@MapperScan注解,也可以在mybatis-config.xml中配置mapper映射文件的位置和命名空間
<configuration> <mappers> <mapper resource="com/example/mapper/UserMapper.xml"/> // 指定Mapper映射文件的位置和名稱 </mappers> </configuration>
二、實(shí)現(xiàn)原理
1. 原理
Mybatis的Mapper接口和xml綁定的原理主要依賴于JDK動(dòng)態(tài)代理技術(shù)。
而Mybatis中MapperProxy代理類是mybatis實(shí)現(xiàn)Mapper接口和xml綁定的核心類之一。它實(shí)現(xiàn)了InvocationHandler接口,用于攔截Mapper接口方法的調(diào)用,并將方法名和參數(shù)傳遞給SqlSession對(duì)象執(zhí)行相應(yīng)的SQL語(yǔ)句。
2. MapperProxy代理類的實(shí)現(xiàn)過程
- 首先,通過JDK動(dòng)態(tài)代理技術(shù)生成一個(gè)MapperProxy代理類實(shí)例。這個(gè)代理類實(shí)現(xiàn)了Mapper接口,并重寫了接口中的方法。
- 在重寫的方法中,MapperProxy會(huì)攔截方法調(diào)用,并將方法名和參數(shù)傳遞給SqlSession對(duì)象執(zhí)行相應(yīng)的SQL語(yǔ)句。
- SqlSession對(duì)象會(huì)根據(jù)Mapper接口的namespace值找到對(duì)應(yīng)的mapper.xml文件,并根據(jù)id值找到對(duì)應(yīng)的SQL語(yǔ)句。然后,根據(jù)返回值類型和參數(shù)類型等信息,生成相應(yīng)的Java代碼。這些Java代碼會(huì)包含對(duì)SqlSession的操作,例如查詢、更新等操作。最終,SqlSession對(duì)象會(huì)將這些Java代碼編譯成字節(jié)碼,并加載到JVM中運(yùn)行。
- 當(dāng)SQL語(yǔ)句執(zhí)行完畢后,SqlSession對(duì)象會(huì)將結(jié)果返回給MapperProxy代理類。然后,MapperProxy代理類會(huì)將結(jié)果映射為Java對(duì)象,并返回給調(diào)用者。
3. MapperProxy代理類源碼
下面是MapperProxy代理class的核心方法實(shí)現(xiàn):mybatis3.5.9
public class MapperProxy<T> implements InvocationHandler, Serializable { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, args); } else { return cachedInvoker(method).invoke(proxy, method, args, sqlSession); } } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } } private MapperMethodInvoker cachedInvoker(Method method) throws Throwable { try { return MapUtil.computeIfAbsent(methodCache, method, m -> { if (m.isDefault()) { try { if (privateLookupInMethod == null) { return new DefaultMethodInvoker(getMethodHandleJava8(method)); } else { return new DefaultMethodInvoker(getMethodHandleJava9(method)); } } catch (IllegalAccessException | InstantiationException | InvocationTargetException | NoSuchMethodException e) { throw new RuntimeException(e); } } else { return new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration())); } }); } catch (RuntimeException re) { Throwable cause = re.getCause(); throw cause == null ? re : cause; } } private MethodHandle getMethodHandleJava9(Method method) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { final Class<?> declaringClass = method.getDeclaringClass(); return ((Lookup) privateLookupInMethod.invoke(null, declaringClass, MethodHandles.lookup())).findSpecial( declaringClass, method.getName(), MethodType.methodType(method.getReturnType(), method.getParameterTypes()), declaringClass); } private MethodHandle getMethodHandleJava8(Method method) throws IllegalAccessException, InstantiationException, InvocationTargetException { final Class<?> declaringClass = method.getDeclaringClass(); return lookupConstructor.newInstance(declaringClass, ALLOWED_MODES).unreflectSpecial(method, declaringClass); } }
到此這篇關(guān)于Mybatis Mapper接口和xml綁定的多種方式、內(nèi)部實(shí)現(xiàn)原理和過程的文章就介紹到這了,更多相關(guān)Mybatis Mapper接口和xml綁定內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Mybatis 數(shù)據(jù)庫(kù)連接池的實(shí)現(xiàn)示例
在Java應(yīng)用程序中,與數(shù)據(jù)庫(kù)的連接是非常昂貴的,因此,當(dāng)我們使用MyBatis進(jìn)行數(shù)據(jù)操作時(shí),需要一個(gè)連接池來(lái)分配并管理這些連接,本文主要介紹了Mybatis 數(shù)據(jù)庫(kù)連接池的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下2023-10-10SpringBoot實(shí)現(xiàn)簡(jiǎn)單的登錄注冊(cè)的項(xiàng)目實(shí)戰(zhàn)
本文主要介紹了SpringBoot實(shí)現(xiàn)簡(jiǎn)單的登錄注冊(cè)的項(xiàng)目實(shí)戰(zhàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03基于IDEA查看maven依賴結(jié)構(gòu)流程解析
這篇文章主要介紹了基于IDEA查看maven依賴結(jié)構(gòu)流程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09spring中@Transactional?注解失效的原因及解決辦法
面試中經(jīng)常會(huì)被問到事務(wù)失效的場(chǎng)景有哪些,本文主要介紹了spring中@Transactional?注解失效的原因及解決辦法,具有一定的參考價(jià)值,感興趣的可以了解一下2024-06-06