MyBatis select查询(resultType/resultMap)和延迟加载

MyBatis select标签, 常用元素有:id、parameterType、resultType、resultMap等

    id:配合Mapper的全限定名,联合成为一个唯一的标识,用户标识这条SQL。

    parameterType:表示这条SQL接受的参数类型,可以是MyBatis系统定义或者自定义的别名

    resultType:表示这条SQL返回的结果类型,与parameterType一样,可以是系统定义的别名,也可以是类的全限定名。

    resultMap:它是映射器的引用,将执行强大的映射功能。resultMap也提供了自定义映射的POJO类型。 

我们可以使用resultType和resultMap中的一个,但不能同时使用。

id在命名空间中唯一的标识符,可以被用来引用这条语句。
parameterType将会传入这条语句的参数类的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过 TypeHandler 推断出具体传入语句的参数,默认值为 unset。
resultType从这条语句中返回的期望类型的类的完全限定名或别名。注意如果是集合情形,那应该是集合可以包含的类型,而不能是集合本身。使用 resultType 或 resultMap,但不能同时使用。
resultMap外部 resultMap 的命名引用。结果集的映射是 MyBatis 最强大的特性,对其有一个很好的理解的话,许多复杂映射的情形都能迎刃而解。使用 resultMap 或 resultType,但不能同时使用。

 

一、resultType元素

   resultType属性:要求结果集的列名和属性名必须要匹配, 若不匹配时,可以使用SQL语句的AS别名(不推荐) 或者 设置开启自动驼峰命名规则映射 或者使用 resultMap属性。

1、查询一条记录, 返回 POJO类 或者返回MyBatis封装好的 Map集合(key是列名称,value是列对应的值)

     POJO类

	public User getUser(Integer id);

	<!-- id - 对应接口中的方法名
	     resultType - 从这条语句中返回的期望类型的类完全限定名或别名 -->
	<select id="getUser" resultType="cn.jq.mybatis.model.User">
		select * from t_user where id = #{id}
	</select>
                        User user = userMapper.getUser(1);
			System.out.println(user);
----
User [id=1, username=admin, pazzword=172eee54aa664e9dd0536b063796e54e, state=1, regDate=Sun Oct 14 00:00:00 CST 2018]

     Map集合(key是列名称,value是列对应的值)

	public Map<String, Object> selectUserMap(int id);

	<select id="selectUserMap" resultType="map">
		select * from t_user where id = #{id} 
	</select>
                        Map<String, Object> userMap = userMapper.selectUserMap(1);
			System.out.println(userMap);
----
{reg_date=2018-10-14 00:00:00.0, pazzword=172eee54aa664e9dd0536b063796e54e, id=1, state=1, username=admin}

2、查询所有结果,返回 List集合 Map集合

    List集合

	public List<User> selectUserAll();

	<!--  返回类型为集合时,resultType只需指定List中单行记录的类型即可
	     resultType - 从这条语句中返回的期望类型的类完全限定名或别名 -->
	<select id="selectUserAll" resultType="cn.jq.mybatis.model.User">
		select * from t_user
	</select>
			List<User> userlist = userMapper.selectUserAll();
			System.out.println(Arrays.asList(userlist));
----
[[User [id=1, username=admin, pazzword=172eee54aa664e9dd0536b063796e54e, state=1, regDate=Sun Oct 14 00:00:00 CST 2018], User [id=2, username=user, pazzword=3be7f713d9321e812231bb838448385d, state=1, regDate=Mon Oct 15 00:00:00 CST 2018]]

    Map集合

    Map<Integer,User>,Map中的key是User的id,Map的值是User对象,实现它的关键是我们要在接口的方法上加一个注解,告诉Mybatis用哪个字段做Map的key.

	@MapKey("id")
	public Map<Integer, User> selectUserMap();

	<select id="selectUserMap" resultType="map">
		select * from t_user
	</select>
			Map<Integer, User> userMap = userMapper.selectUserMap();
			System.out.println(Arrays.asList(userMap));
----
[{1={reg_date=2018-10-14 00:00:00.0, pazzword=172eee54aa664e9dd0536b063796e54e, id=1, state=1, username=admin}, 2={reg_date=2018-10-15 00:00:00.0, pazzword=3be7f713d9321e812231bb838448385d, id=2, state=1, username=user}]

 

二、resultMap元素

使用场景很广泛:

  • 字段有自定义的转化规则
  • 复杂的多表查询

1、使用resultMap自定义数据库字段名称和JavaBean的属性名称的对应关系

	public User getUser(Integer id);

	<select id="getUser" resultMap="user_map">
		select * from t_user where id = #{id} 
	</select>
	
	<resultMap type="cn.jq.mybatis.model.User" id="user_map">
		<!-- 主键的映射关系 
			 column - 数据库的列名 不区分大小写
			 property - model类中的属性名 区分大小写 -->
		<id column="id" property="id"/>
		<!-- 非主键的映射关系 -->
		<result column="username" property="username"/>
		<result column="pazzword" property="pazzword"/>
		<result column="state" property="state"/>
		<result column="reg_date" property="regDate"/>
	</resultMap>

			User user = userMapper.getUser(1);
			System.out.println(user);
----
User [id=1, username=admin, pazzword=172eee54aa664e9dd0536b063796e54e, state=1, regDate=Sun Oct 14 00:00:00 CST 2018]

2、使用resultMap实现关联查询 ( 类(引用)类型成员属性 )使用 association 标签

    假设  一个用户对应一个角色,

    1)使用 association标签实现关联查询, 两个表的重复字段通过别名识别

          association 标签 :类(引用)类型成员属性映射 
                property - 对应属性名
                javaType - 类的具体类型

   

	public User getUser(Integer id);

        <select id="getUser" resultMap="user_map">
		select 
			t.id,
			t.username, 
			t.pazzword,
			t.state,
			t.reg_date regDate,
			r.id rid,
			r.roleName,
			r.state rstate
		from t_user t, t_role r 
		where t.role_id = r.id and t.id = #{id} 
	</select>
        <resultMap type="cn.jq.mybatis.model.User" id="user_map">
		<!-- 主键的映射关系 -->
		<id column="id" property="id"/>
		<!-- 非主键的映射关系 -->
		<result column="username" property="username"/>
		<result column="pazzword" property="pazzword"/>
		<result column="state" property="state"/>
		<result column="reg_date" property="regDate"/>
		<!-- 类(引用)类型成员属性映射 
				property - 对应属性名
				javaType - 类的具体类型 -->
		<association property="role" javaType="cn.jq.mybatis.model.Role">
			<!-- column - 关联列的列名或者别名  -->
			<id column="rid" property="id"/>
			<result column="rolename" property="roleName"/>
			<result column="rstate" property="state"/>
		</association>
	</resultMap>

			User user = userMapper.getUser(1);
			System.out.println(user);
----
User [id=1, username=admin, pazzword=172eee54aa664e9dd0536b063796e54e, state=1, regDate=Sun Oct 14 00:00:00 CST 2018, role=Role [id=1, roleName=超级管理员, state=0]]

     

2)使用 association标签分步实现关联查询(传递一个参数)

     分步查询通常应用于关联表查询,将查询sql拆分,分步查询与关联表查询的不同:

      从代码层面来说:关联表查询能够有效的简化代码编写逻辑,减小代码编写难度,同时避免BUG(代码多了,bug就多了);

      而分步查询则能够增强代码的可用性

      从功能上说:关联表查询毕竟只需要查询一次数据库,对于业务量较小的系统来说,效率更高,数据库压 力相对较小;

      分步查询虽然需要多次查询数据,但是这也意味着能够更好地使用数据缓存服务,且缓存的   数据耦合度低,利用率高,而且单次查询效率很高,数据库压力较小(对于业务量较大的系统来说)。还有一点则是数据库锁的问题,毕竟关联查询是多表同时使用,分步查询每次只操作一个表。 

role

public Role getRole(Integer id);

<mapper namespace="cn.jq.mybatis.dao.RoleMapper">
	<select id="getRole" resultType="cn.jq.mybatis.model.Role">
		select * from t_role where id = #{id}
	</select>
</mapper>

user

  select::表明当前属性是调用select指定方法查出的结果 是XXXMapper.xml中namespace。方法名
  column:指定将哪一列的值传给这个方法

        public User getUser(Integer id);

	<select id="getUser" resultMap="user_map">
		select * from t_user where id = #{id}
	</select>
	<resultMap type="cn.jq.mybatis.model.User" id="user_map">
		<!-- 主键的映射关系 -->
		<id column="id" property="id"/>
		<!-- 非主键的映射关系 -->
		<result column="username" property="username"/>
		<result column="pazzword" property="pazzword"/>
		<result column="state" property="state"/>
		<result column="reg_date" property="regDate"/>
		<!-- 类(引用)类型成员属性映射 
				property - 对应属性名
				select - 对应属性名的实现接口.id名(即方法名) 
				column - 传过去的数据库列名(有别名用别名)-->
		<association property="role" select="cn.jq.mybatis.dao.RoleMapper.getRole" column="role_id">
		</association>
	</resultMap>

			User user = userMapper.getUser(1);
			System.out.println(user);
----
User [id=1, username=admin, pazzword=172eee54aa664e9dd0536b063796e54e, state=1, regDate=Sun Oct 14 00:00:00 CST 2018, role=Role [id=1, roleName=超级管理员, state=0]]

3、使用resultMap实现关联查询 ( 集合 List/Set 类型成员属性 使用 collection 标签

     假设  一个角色对应多个用户,

     1)使用 collection 标签实现关联查询, 两个表的重复字段通过别名识别

         collection 标签 :集合类型成员属性映射 
               property - 对应属性名
               ofType - 设置集合中存放的数据的类型

  

	public Role getRoleOfUser(Integer id);

	<select id="getRoleOfUser" resultMap="role_map">
		select
			r.id,
			r.rolename,
			r.state,
			t.id tid,
			t.username,
			t.pazzword,
			t.state tstate,
			t.reg_date regDate 
		from t_role r, t_user t 
		where r.id=t.role_id and r.id = #{id}
	</select>
	<resultMap type="cn.jq.mybatis.model.Role" id="role_map">
		<id property="id" column="id"/>
		<result property="roleName" column="rolename"/>
		<result property="state" column="state"/>
		<!-- 集合类型成员属性映射 
			property - 对应属性名
			ofType - 设置集合中存放的数据的类型 -->
		<collection property="users" ofType="cn.jq.mybatis.model.User">
			<id property="id" column="tid"/>
			<result property="username" column="username"/>
			<result property="pazzword" column="pazzword"/>
			<result property="state" column="tstate"/>
			<result property="regDate" column="regDate"/>
		</collection>
	</resultMap>

			Role role = roleMapper.getRoleOfUser(1);
			System.out.println(role);
----
Role [id=1, roleName=超级管理员, state=0, users=[User [id=1, username=admin, pazzword=172eee54aa664e9dd0536b063796e54e, state=1, regDate=Sun Oct 14 00:00:00 CST 2018], User [id=2, username=user, pazzword=3be7f713d9321e812231bb838448385d, state=1, regDate=Mon Oct 15 00:00:00 CST 2018]]]

   

    2)使用 collection 标签分步实现关联查询(传递一个参数)

     user

	public List<User> selectUserByRoleid(Integer roleId);

	<select id="selectUserByRoleid" resultType="cn.jq.mybatis.model.User">
		select * from t_user where role_id = #{roleId}
	</select>

     role

         select - 对应属性名的实现接口.id名(即方法名) 
         column - 传过去的数据库表的字段别名(无别名用列名)

	public Role getRoleOfUser(Integer id);

	<select id="getRoleOfUser" resultMap="role_map">
		select * from t_role where id = #{id}
	</select>
	<resultMap type="cn.jq.mybatis.model.Role" id="role_map">
		<id property="id" column="id"/>
		<result property="roleName" column="rolename"/>
		<result property="state" column="state"/>
		<!-- 集合类型成员属性映射 
			property - 对应属性名
			select - 对应属性名的实现接口.id名(即方法名) 
			column - 传过去的参数别名(无别名用列名)-->
		<collection property="users" select="cn.jq.mybatis.dao.UserMapper.selectUserByRoleid" column="id">
		</collection>
	</resultMap>

在开发中

    针对属性是单对象类型时,使用 association元素,通常直接使用多表查询操作,即内联查询

    针对属性是集合对象类型时,使用 collection元素,通常使用延迟加载,即额外SQL查询

三、延迟加载(也称懒加载)

     Hibernate中,涉及到关联查询的时候,懒加载是默认就开启着的

     延迟加载就是当在真正需要使用到数据时,才会发送SQL语句进行查询该数据。

     MyBatis 默认关闭延迟加载,需要我们在全局配置文件里手动配置, 也可在sql映射文件设置。

lazyLoadingEnabled延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态。true | falsefalse
aggressiveLazyLoading当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载(参考lazyLoadTriggerMethods).true | false

false (true in ≤3.4.1)

jdbcTypeForNull当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。 某些驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。JdbcType 常量. 大多都为: NULL, VARCHAR and OTHEROTHER
lazyLoadTriggerMethods指定哪个对象的方法触发一次延迟加载。用逗号分隔的方法列表。equals,clone,hashCode,toString

     开启的方法就是配置三个全局变量:

	<settings>
		<!-- 开启自动驼峰命名规则映射,即从经典数据库列名 A_COLUMN 到POJO类属性名 aColumn的类似映射。 -->
		<setting name="mapUnderscoreToCamelCase" value="true"/>
		<setting name="jdbcTypeForNull" value="NULL"/>
		<!-- 开启延迟加载 -->
		<setting name="lazyLoadingEnabled" value="true"/>
		<!-- 禁用积极延迟加载 -->
		<setting name="aggressiveLazyLoading" value="false"/>
		<!-- 延迟加载触发方法 -->
		<setting name="lazyLoadTriggerMethods" value="clone"/>
	</settings>	

.     如果想单个开启或禁用延迟加载,可以使用fetchType属性来实现

      fetchType="lazy" 表示使用懒加载   fetchType="eager"表示开启立即加载

<association property="role" select="cn.jq.mybatis.dao.RoleMapper.getRole" column="role_id" fetchType="eager">
		</association>

四、分步查询传入多参数

       不管是 association 标签还是 collection 标签,在分步查询的时候,都可以用column属性,给select指定的sql语句传入某列的值做参数,如果需要传入多个参数的话,可以把参数封装成Map对象,写成这个格式 column="{key1=column1,key2=column2}"

        key - 指接收参数的#{value} value值,

        column1 - 指传入的数据库表的字段别名(无别名用列名)  

把上面 二 -- 3 -- 2的实例, 业务改为, 查询 一个角色中的多用户state与role的state相同的user

use

        public List<User> selectUserByRoleid(Integer roleId, Integer rstate);

	<select id="selectUserByRoleid" resultType="cn.jq.mybatis.model.User">
		select * from t_user where role_id = #{roleId} and state = #{rstate}
	</select>

role

	public Role getRoleOfUser(Integer id);

	<select id="getRoleOfUser" resultMap="role_map">
		select * from t_role where id = #{id}
	</select>
	<resultMap type="cn.jq.mybatis.model.Role" id="role_map">
		<id property="id" column="id"/>
		<result property="roleName" column="rolename"/>
		<result property="state" column="state"/>
		<collection property="users" select="cn.jq.mybatis.dao.UserMapper.selectUserByRoleid" 
			column="{roleId=id,rstate state}">
		</collection>
	</resultMap>

			Role role = roleMapper.getRoleOfUser(1);
			System.out.println(role);
----
Role [id=1, roleName=超级管理员, state=0, users=[User [id=2, username=user, pazzword=3be7f713d9321e812231bb838448385d, state=0, regDate=Mon Oct 15 00:00:00 CST 2018]]]

 

  不要注重实例业务, 学习其中知识点。

ends~

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值