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]]]
不要注重例項業務, 學習其中知識點。