SSM框架學習-MyBatis篇 SQL映射文件——實現高級結果映射(多表查詢)
問題情境:比如有張表,用戶和用戶詳情,這兩張表裏面沒長表都有一個id字段,這兩個表的id字段都是對應的。
實體類裏面分別對應兩個實體類,user和userdetail,還有一個很重要的實體類,叫做“用戶+用戶詳情”(userwithdetail),這個實體類首先繼承了user,裏面的元素是前面的userdetail這個對象。
比如我想要查詢一個用戶,我還想知道他的詳情,我就要在數據庫裏面select它一下,要返回userwithdetail 這個對象,因爲這這個對象既繼承了父類User,還包括了對應的對象userDetail。那麼這麼複雜的結構,肯定會使用到多表查詢。
mybatis對於處理簡單的單表查詢,用resultType就可以解決 但是對於多表查詢,都要使用resultMap進行詳細的描述 告訴mybatis怎麼封裝。
自頂向下的先實踐一下多表查詢:
1、數據庫定義user和userdetail的兩張表。這個就不多贅述。
對應的實體類,前面已經說過。其中user和userdetail都實現serializable,UserWithDetail 繼承了User
2、mybatis的配置文件先聲明一下兩個要用到的Mapper文件,這個也不多贅述
3、首先先寫一個方法,就按照id查詢一個用戶吧。這個寫法應該沒毛病。給User和UserDetail兩張表
起一個別名。然後兩表聯合查詢。
<select id="queryById" resultMap="userWithDetailMap">
select t1.id as uid ,t1.phone,t1.password,t1.create_date,t1.status,
t2.id as udid,t2.address,t2.cid
from user t1,user_detail t2
<where>
t1.id=u_id
and t1.id =#{id}
</where>
</select>
4、由於從user t1,user_detail t2這兩張表裏面查詢數據,單純的語句已經不知道返回的數據的封裝規則是什麼了。resultType就不能解決問題了,那我們就定義一個resultMap
<resultMap id="userBaseMap" type="com.sdbit.ylh.entity.UserWithDetail">
<!--user的基本信息-->
<id property="id" column="uid"/>
<result property="phone" column="phone"/>
<result property="password" column="password"/>
<result property="createDate" column="create_date"/>
<result property="status" column="status"/>
</resultMap>
這裏先定義一個基本的user信息而不是userdetail,原因是這個resultmap竟然還可以繼承,爲了以後寫方便,就先給它寫一個basemap,對錶中的數據進行映射,先說說裏面的屬性
- property:映射數據庫列(column)的實體與對象(JavaBean)的對應元素的屬性。這裏是User類的元素。
- column:數據庫列名
- id:id算是一個比較特殊的property,用來映射數據庫主鍵列與對象對應的元素,這裏是User的uid元素
那user的對應屬性如此,可是最後結果還有一個userdetail對象需要我們去封裝,這個應該怎麼解決呢?
那麼就需要用到上面說的resultMap的繼承。
5、這裏在寫一個resultMap,id的值爲userWithDetailMap
<resultMap id="userWithDetailMap" extends="userBaseMap" type="com.sdbit.ylh.entity.UserWithDetail">
<association property="userDetail" javaType="com.sdbit.ylh.entity.UserDetail">
<id property="id" column="udid"/>
<result property="address" column="address"></result>
<result property="cid" column="cid"></result>
</association>
</resultMap>
這裏就用到了association這個屬性,這個屬性就專門用來處理一對一的情況。這裏持有的是userDetail這一個對象,然後我們需要告訴mybatis它類型是對應實體類中的 com.sdbit.ylh.entity.UserWithDetail這個類,
這個類對應的表的屬性,和他們對應的類裏面的元素。我們在裏面繼續聲明即可,和上面一樣id和property
完事之後在看看上面指定的resultmap,就一目瞭然了。
程序成功運行,查詢出一條數據user+userdetail
還有一種封裝resultMap更簡單的方式,但是不是官方推薦的那種,也可以使用(這裏沒有使用繼承!):
實踐一下分步查詢:
分步查詢(如果查詢太複雜,可以使用分步查詢)
意思就是,當查詢很複雜的時候,我們可以先寫一個sql語句進行單表查詢,然後再在resultMap裏面再次執行一次別的sql語句
這個sql語句可以是別的mapper裏面的語句。
具體怎麼實現呢?下面就是實踐演示。
1、首先定義一個“別的”mapper,這裏叫做UserDetailMapper,顧名思義,就是專門對UserDetail的這個表進行查詢。
因爲最後我們想要得到的結果是User+UserDetail=UserWithDetail。
2、在sql的xml文件裏寫一個簡單的select,把UserDetail表裏面對應id的記錄查找出來。
3、回到UserMapper.xml,我們首先封裝一個resultMap,
<resultMap id="userWithDetailMap3" extends="userBaseMap" type="com.sdbit.ylh.entity.UserWithDetail">
<association property="userDetail"
select="com.sdbit.ylh.mapper.UserDetailMapper.queryByUserId"
column="uid">
</association>
</resultMap>
在這個語句中可以看到,association裏面的property指向的就是userwithDetail裏面的userDetail,那麼這個userDetail對象從哪裏來呢?就從select引用com.sdbit.ylh.mapper.UserDetailMapper下面的queryByUserId方法裏來,但是上面這個uid是從哪裏來呢??
那麼我們在sql語句書寫的時候,就要包含resultMap需要的列,我們現在就來寫分步查詢的最後一個sql
<select id="queryByIdByStep" resultMap="userWithDetailMap3">
select t1.id as uid ,t1.phone,t1.password,t1.create_date,t1.status
from user t1
<where>
and t1.id =#{id}
</where>
</select>
那麼這裏的uid就封裝好了給resultMap。resultmap就可以執行第二步查詢。完成了兩次查詢後UserWithDetail這個對象才完美的被數據填滿。
如上就完成了使用association處理一對一的關聯關係。
1對1的關聯關係總結:
- 學會了使用association來實現多表查詢,對實體類和數據庫這兩方的映射
- 處理多表查詢中出現bean包含bean的兩種處理方式,官方的和簡單的
- resultMap的繼承的寫法。
- 使用定義resultMap來實現分步查詢,使用association,甚至可以跨mapper調用方法查詢