Mybatis之@MapKey的實現(xiàn)
前言
演示返回單行、多行數(shù)據(jù),使用@MapKey和不使用@MapKey注解的區(qū)別,然后通過源碼解析產生各種結果的原因
案例演示
分別演示下列四種情況
- 單行不使用@MapKey注解
- 多行不使用@MapKey注解
- 單行使用@MapKey注解
- 多行使用@MapKey注解
代碼準備
創(chuàng)建mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties>
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</properties>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<environments default="default">
<environment id="default">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/MapKeyMapper.xml"/>
</mappers>
</configuration>創(chuàng)建MapKeyMapper.xml
<?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.ys.mybatis.mapper.MapKeyMapper">
<select id="getBlogMapById" resultType="map">
select id, title from blog where id = #{id}
</select>
<select id="listBlogMap" resultType="map">
select id, title from blog
</select>
</mapper>創(chuàng)建接口MapKeyMapper
public interface MapKeyMapper {
Map<String, Object> getBlogMapById(Integer id);
Map<String, Object> listBlogMap();
}創(chuàng)建測試類MapKeyTest
@Slf4j
public class MapKeyTest {
private SqlSessionFactory sqlSessionFactory;
@BeforeEach
public void init() {
InputStream inputStream = ConfigurationTest.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void singleRowTest() {
SqlSession sqlSession = sqlSessionFactory.openSession();
MapKeyMapper mapper = sqlSession.getMapper(MapKeyMapper.class);
Map<String, Object> map = mapper.getBlogMapById(1);
System.out.println(map);
}
@Test
public void multiLineTest() {
SqlSession sqlSession = sqlSessionFactory.openSession();
MapKeyMapper mapper = sqlSession.getMapper(MapKeyMapper.class);
Map<String, Object> map = mapper.listBlogMap();
System.out.println(map);
}
}單行不使用@MapKey注解
執(zhí)行測試方法singleRowTest

正確返回,map格式為 Map<String,Object>
多行不使用@MapKey注解
執(zhí)行測試方法multiLineTest

異常返回,拋出 TooManyResultsException
單行使用@MapKey注解
給接口方法添加@MapKey注解
@MapKey("id")
Map<String, Object> getBlogMapById(Integer id);執(zhí)行測試方法singleRowTest

正確返回,map格式為 Map<Long,Map<String,Object>>
多行使用@MapKey注解
給接口方法添加@MapKey注解
@MapKey("id")
Map<String, Object> listBlogMap();執(zhí)行測試方法multiLineTest

正確返回,map格式為 Map<Long, Map<String,Object>>
源碼解析
默認情況下,Mybatis會通過MapperMethod的 execute 方法對將要執(zhí)行的方法進行分發(fā)。
MapperMethod結構如下:
public class MapperMethod {
private final SqlCommand command;
private final MethodSignature method;
public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
this.command = new SqlCommand(config, mapperInterface, method);
this.method = new MethodSignature(config, mapperInterface, method);
}
}MapperMethod實例化的過程中,會實例化其內部屬性MethodSignature


通過源碼我們得出:如果接口方法上存在@MapKey注解,returnsMap 屬性就為true
returnsMap的值決定是執(zhí)行executeForMap還是selectOne方法

返回類型為map,存在@MapKey注解,執(zhí)行executeForMap,否則執(zhí)行selectOne方法
selectOne

執(zhí)行selectOne方法,如果返回的條目數(shù)大于1,則拋出異常。測試案例2(多行不使用@MapKey注解)就是因為返回的條目數(shù)大于1,拋出了TooManyResultsException異常
selectMap

DefaultMapResultHandler實例化

DefaultMapResultHandler實例化的過程中,會實例化其內部屬性mappedResults,該屬性的類型為Map
handleResult

通過@MapKey指定的key獲取value,再以該value為key,原始value為value,put到mappedResults中,最終將這個mappedResults返回。因為原始value的類型是Map<String,Object>,@MapKey指定的key的類型是Long,所以最終返回類型是Map<Long,Map<String,Object>>
到此這篇關于Mybatis之@MapKey的實現(xiàn)的文章就介紹到這了,更多相關Mybatis @MapKey內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SpringBoot使用Caffeine實現(xiàn)緩存的示例代碼
本文主要介紹了SpringBoot使用Caffeine實現(xiàn)緩存的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-07-07
盤點總結SpringBoot自帶工具類使用提升開發(fā)效率
這篇文章主要為大家介紹了盤點總結SpringBoot自帶工具類使用提升開發(fā)效率,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-12-12
IDEA整合Dubbo+Zookeeper+SpringBoot實現(xiàn)
初學者,想自己動手做一個簡單的demo,本文主要介紹了IDEA整合Dubbo+Zookeeper+SpringBoot實現(xiàn),需要的朋友們下面隨著小編來一起學習學習吧2021-06-06
基于Cookie與Session的Servlet?API會話管理操作
這篇文章主要為大家介紹了基于Cookie與Session的Servlet?API會話管理操作詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-08-08
SpringMVC中的SimpleUrlHandlerMapping用法詳解
這篇文章主要介紹了SpringMVC中的SimpleUrlHandlerMapping用法詳解,SimpleUrlHandlerMapping是Spring MVC中適用性最強的Handler Mapping類,允許明確指定URL模式和Handler的映射關系,有兩種方式聲明SimpleUrlHandlerMapping,需要的朋友可以參考下2023-10-10

