ResultMap自定义结果集
可以把查询返回的结果集封装成复杂的JavaBean对象
原来的ResultType属性,只能把查询到的结果集转换为简单的JavaBean
什么是简单的JavaBean对象?
- 不具有JavaBean和集合类型属性的对象
- 也就是不能建立ORM的多表关联映射
问题的引入:
如果字段标识符和数据表不一致,
例如实体类的user的密码字段,现在更改为pwd
数据表的字段依然为user_password
我们查询这个结果看看
所有的密码字段接受失败
那么,该如何解决这个问题?
方案一,在SQL语句中给这个字段起别名
再次测试,这个数据又能获取到了
但是这样的解决方案并不优雅
Mybatis提供了一个解决方案,使用ResultMap对字段标识进行映射绑定
测试结果,可行
一对一关系案例:
创建数据表
锁表 & 钥匙【一把锁就配一把钥匙】
CREATE TABLE t_lock( `id` INT PRIMARY KEY AUTO_INCREMENT, `name` VARCHAR(50) ); CREATE TABLE t_key( `id` INT PRIMARY KEY AUTO_INCREMENT, `name` VARCHAR(50), `lock_id` INT, FOREIGN KEY(`lock_id`) REFERENCES t_lock(`id`) );
添加数据
INSERT INTO t_lock(`name`) VALUES ('阿里巴巴'), ('联想'), ('华为'); INSERT INTO t_key(`name`,`lock_id`) VALUES ('马云',1), ('任正非',2), ('柳传志',3);
【写反了,唉就这样把】
创建ORM实体类
锁类
package cn.dai.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * @author ArkD42 * @file Mybatis * @create 2020 - 05 - 29 - 13:30 */ @Data @AllArgsConstructor @NoArgsConstructor public class Lock { private Integer id; private String name; }
钥匙类
package cn.dai.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * @author ArkD42 * @file Mybatis * @create 2020 - 05 - 29 - 13:32 */ @Data @NoArgsConstructor @AllArgsConstructor public class Key { private Integer id; private String name; // 注意这个设置的外键是来自这个锁对象的属性 private Lock lock; }
映射器【KeyMaper.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接口名称--> <mapper namespace="cn.dai.mapper.KeyMapper"> <select id="queryKeyById" resultType="cn.dai.pojo.Key" parameterType="java.lang.Integer"> SELECT * FROM t_key WHERE id = #{id} </select> </mapper>
注意!在这里采用的结果集类型,先看看结果如何
测试类
@Test public void sqlTest6(){ logger.info("- - - - TESTING - - - -"); SqlSession sqlSession = MybatisUtil.getSqlSession(true); KeyMapper keyMapper = sqlSession.getMapper(KeyMapper.class); Key key = keyMapper.queryKeyById(2); System.out.println(key); sqlSession.close(); }
结果:我们对应的锁类无法获取
我们需要一个关联查询来实现
首先从SQL语句实现
【查询钥匙表关联锁表,一起获取】
SELECT t_key.*,t_lock.name lock_name FROM t_key LEFT JOIN t_lock ON t_key.lock_id = t_lock.id WHERE t_key.id = #{id}
【就算是这样,没有类型匹配,返回的结果还是和上面一样,这里不展示了】
【留意SELECT子句筛选的字段】
所以需要通过结果集映射标签实现一些类型的绑定
使用默认的result标签处理
然后使用我们的结果集映射标签实现关联处理
<?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接口名称--> <mapper namespace="cn.dai.mapper.KeyMapper"> <!-- id 设置这个结果集映射标签的标识, type 设置需要转换出来的实体类对象的全限定类名 --> <resultMap id="key" type="key"> <!-- id标签负责 转换主键列 -> 实体类的属性 --> <id column="id" property="id"/> <!-- 非主键列 转换给 实体类属性 --> <result column="name" property="name"/> <!-- 一般匹配的字段不需要显示的写出来,因为是默认的了 --> <!-- property 对应的是实体类的属性 column 对应的是数据表的列 --> <result column="lock_id" property="lock.id" /> <result column="lock_name" property="lock.name" /> </resultMap> <!-- 这里的结果集映射就对应上面设置的id --> <select id="queryKeyById" resultMap="key" parameterType="int"> SELECT t_key.*,t_lock.name lock_name FROM t_key LEFT JOIN t_lock ON t_key.lock_id = t_lock.id WHERE t_key.id = #{id} </select> </mapper>
测试结果
千万要注意,要实现这个锁的名称的输出,就要留意上面的SELECT 筛选的字段
可以通过别名映射实现一些实体类的绑定
在这里是因为左外链接,所以可以看到,钥匙表是没有写这个表名的
或者使用Association标签实现映射
在结果集中设置关联映射标签,绑定属性标识和所对应的类型
其次声明关联表的属性映射
<association property="lock" javaType="cn.dai.pojo.Lock"> <id column="lock_id" property="id"/> <result column="lock_name" property="name" /> </association>
Association定义分布查询
什么意思?
可以通过一个查询得到子对象
分两种加载,立即加载和懒加载
一张表可能存在50多列,其中主要常用的是最前面的6列
后面的44列不一定马上需要,所以我们的查询应该拆分成两次查询
我们声明一个两步查询的方法
Key queryKeyByIdForTwoStep(Integer id);
对副表的二次查询在锁表中编写
package cn.dai.mapper; import cn.dai.pojo.Lock; /** * @author ArkD42 * @file Mybatis * @create 2020 - 05 - 30 - 11:59 */ public interface LockMapper { Lock queryLockById(Integer id); }
锁表的映射器
<?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接口名称--> <mapper namespace="cn.dai.mapper.LockMapper"> <select id="queryLockById" resultType="cn.dai.pojo.Lock" > select * from t_lock where id = #{id} </select> </mapper>
钥匙表的映射器
<resultMap id="key2" type="cn.dai.pojo.Key"> <id column="id" property="id"/> <result column="name" property="name"/> <!-- select 调用另外一个映射器的查询方法,来获取对象的结果 column 把这钥匙表的查询SQL的字段结果返回给这个关联查询调用【就是那个查询的参数】 --> <association property="lock" javaType="cn.dai.pojo.Lock" select="cn.dai.mapper.LockMapper.queryLockById" column="lock_id" /> </resultMap> <select id="queryKeyByIdForTwoStep" resultMap="key2" parameterType="int"> SELECT id,name,lock_id FROM t_key WHERE t_key.id = #{id} </select>
测试结果
可以看到这样查询分了两次执行,并且把字段的参数传递给下一个查询的使用
开启懒加载查询
即延迟加载,减少非必要性的查询
优化数据库性能,需要在全局配置中开启
<!-- 开启懒加载 --> <setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"/>
@Test public void sqlTest7(){ logger.info("- - - - TESTING - - - -"); SqlSession sqlSession = MybatisUtil.getSqlSession(true); KeyMapper keyMapper = sqlSession.getMapper(KeyMapper.class); Key key = keyMapper.queryKeyByIdForTwoStep(2); //System.out.println(key); //开启懒加载是什么效果?如果我们不调用附表的信息,第二个查询是不会调用的 System.out.println(key.getName()); sqlSession.close(); }
结果
实际作用远不止这些,详见官方文档:
https://mybatis.org/mybatis-3/zh/sqlmap-xml.html