MyBatis中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属性

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的属性名称的对应关系

数据表上的字段名称和JavaBean上的属性名称不一致时:

    1)在sql语句上起别名

    2)设置全局变量mapUnderscoreToCamelCase让符合驼峰命名约定的两个名字建立关联

    3)使用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拆分,分步查询与关联表查询的不同:

   从代码层面来说:关联表查询能够有效的简化代码编写逻辑,减小代码编写难度,同时避免B-U-G(代码多了,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>

三、延迟加载(懒加载)

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

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

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

false (true in ≤3.4.1)

jdbcTypeForNull 当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。 某些驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。 JdbcType 常量. 大多都为: NULL, VARCHAR and OTHER OTHER

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

	<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"/>
	</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]]]

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

猜你喜欢

转载自blog.csdn.net/qq_42402854/article/details/84111051
今日推荐