Mybatis之@MapKey的实现
目录
- 前言
- 案例演示
- 代码准备
- 创建myBATis-config.XML
- 创建MapKeyMapper.xml
- 创建接口MapKeyMapper
- 创建测试类MapKeyTest
- 单行不使用@MapKey注解
- 多行不使用@MapKey注解
- 单行使用@MapKey注解
- 多行使用@MapKey注解
- 源码解析
- selectOne
- selectMap
- DefaultMapResultHandler实例化
- handleResult
前言
演示返回单行、多行http://www.devze.com数据,使用@MapKey和不使用@MapKey注解的区别,然后通过源码解析产生各种结果的原因
案例演示
分别演示下列四种情况
- 单行不使用@MapKey注解
- 多行不使用@MapKey注解
- 单行使用@MapKey注解
- 多行使用@MapKey注解
代码准备
创建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"> <transactiojsnManager 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>
创建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>
创建接口MapKeyMapper
public interface MapKeyMapper { Map<String, Object> getBlogMapById(Integer id); Map<String, Object> listBlogMap(); }
创建测试类MapKeyTest
@Slf4j public class MapKeyTest { private SqlSessionFactory sqlSessionFactory; @BeforeEach public void init() { InputStream inputStream = Configu编程rationTest.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注解
执行测试方法singleRowTest
正确返回,map格式为 Map<String,Object>
多行不使用@MapKey注解
执行测试方法multiLineTest
异常返回,抛出 TooManyResultsException
单行使用@MapKey注解
给接口方法添加@MapKey注解
@MapKey("id") Map<String, Object> getBlogMapById(Integer id);
执行测试方法singleRowTest
正确返回,map格式为 Map<Long,Map<String,Object>>
多行使用@MapKey注解
给接口方法添加@MapKey注解
@MapKey("id") Map<String, Object> listBlogMap();
执行测试方法multiLineTest
正确返回,map格式为 Map<Long, Map<String,Objehttp://www.devze.comct>>
源码解析
默认情况下,Mybatis会通过MapperMethod的 execute 方法对将要执行的方法进行分发。
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的值决定是执行executeForMap还是selectOne方法
返回类型为map,存在@MapKey注解,执行executeForMap,否则执行selectOne方法
selectOne
执行selectOne方法,如果返回的条目数大于1,则抛出异常。测试案例2(多行不使用@MapKey注解)就是因为返回的条目数大于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的实现的文章就介绍到这了,更多相关Mybatis @MapKey内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文android章希望大家以后多多支持编程客栈(www.devze.com)!
精彩评论