1. 程式人生 > >MyBatis中resultType、resultMap元素和分步關聯查詢

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

不要注重例項業務, 學習其中知識點。