mybtis中的級聯關係(關聯關係、集合關係)association、collection(一對一關係、一對多關係、多對多關係)

mybatis映射文件的結構參見:https://blog.csdn.net/IT_CREATE/article/details/85687293

 

  • 當我們在做查詢時,多個表之間可能存在着級聯關係

比如丈夫表和妻子表,丈夫表裏面含有妻子的外鍵,那麼我們在做查詢的時候,我們就在想我們只需要丈夫信息不需要妻子信息的時候,就只查詢丈夫的基本信息,而不用連妻子信息一起查詢出來,當我們需要的時候,再查詢丈夫的時候一起把妻子的信息一起查出來。

那麼這裏我們就需要用到懶加載,去解決這種一對一,多對多等這種關係。不過在這種關係中需要注意的是:不能循環調用彼此的方法,意思就是我在結果集中調用另外一個方法,那麼這個方法的結果集不能反過來再調用我,說起來很抽象。

舉個簡單例子:假設丈夫有妻子外鍵,妻子有丈夫外鍵,查找丈夫信息時把妻子信息查出來,查妻子時把丈夫信息查出來(下面就進行了相互調用,是錯誤的方式

    <!-- 丈夫結果集映射 -->
	<resultMap type="HusbandBean" id="husMap">
		<id property="id" column="id" javaType="long"></id>
		<result property="husbandName" column="husband_name"
			javaType="string" />
		<!-- association 關聯、關係 用於在映射覆合對象屬性 的值的時候,去調用select屬性對應的方法查詢結果 -->
		<!-- select 屬性,代表在映射覆合屬性時,需要調用的查詢方法,語法:namespace.meth名 -->
		<!-- column="fk_wife_id" 代表需要向select調用的方法中,傳入的值 -->

		<!-- fetchType="lazy" 需要對wife對象進行懶加載(延遲加載) ,調用下面妻子查詢方法-->
		<association property="wifeBean" javaType="WifeBean"
			fetchType="lazy" column="fk_wife_id" select="getWifeBeanById"></association>
	</resultMap>

	<!-- 查詢丈夫信息方法 -->
	<select id="getHusbandBeanById" resultMap="husMap">
		select
		id,husband_name,fk_wife_id from t_husband where id = #{id}
	</select>

	<!-- 妻子結果集映射 -->
	<resultMap type="WifeBean" id="wifMap">
		<id property="id" column="id" javaType="long"></id>
		<result property="wifeName" column="wife_name"
			javaType="string" />
		
		<!--調用上面的getHusbandBeanById,這裏不允許使用,因爲丈夫查詢過程中調用了妻子的查詢方法,如果調用就形成了循環-->
		<association property="husbandBean" javaType="HusbandBean"
			fetchType="lazy" column="fk_husband_id" select="getHusbandBeanById"></association>
	</resultMap>

	<!-- 查詢妻子信息方法 -->
	<select id="getWifeBeanById" resultMap="wifMap">
		select
		id,wife_name,fk_husband_id from t_wife where id = #{id}
	</select>

解決辦法就是去掉妻子中的<association></association>標籤避免循環,然後重新寫以上的兩個方法及映射結果集,妻子中含有association,丈夫結果集中去掉association,只不過這時就有四個方法四個結果映射集。這種雙方包含對方外鍵的情況基本不會這樣設計。

        <!-- 丈夫結果集映射 -->
	<resultMap type="HusbandBean" id="husMap">
		<id property="id" column="id" javaType="long"></id>
		<result property="husbandName" column="husband_name"
			javaType="string" />
		<!-- association 關聯、關係 用於在映射覆合對象屬性 的值的時候,去調用select屬性對應的方法查詢結果 -->
		<!-- select 屬性,代表在映射覆合屬性時,需要調用的查詢方法,語法:namespace.meth名 -->
		<!-- column="fk_wife_id" 代表需要向select調用的方法中,傳入的值 -->

		<!-- fetchType="lazy" 需要對wife對象進行懶加載(延遲加載) ,調用下面妻子查詢方法 -->
		<association property="wifeBean" javaType="WifeBean"
			fetchType="lazy" column="fk_wife_id" select="getWifeBeanById"></association>
	</resultMap>

	<!-- 查詢丈夫信息方法 -->
	<select id="getHusbandBeanById" resultMap="husMap">
		select
		id,husband_name,fk_wife_id from t_husband where id = #{id}
	</select>

	<!-- 妻子結果集映射 -->
	<resultMap type="WifeBean" id="wifMap">
		<id property="id" column="id" javaType="long"></id>
		<result property="wifeName" column="wife_name"
			javaType="string" />
	</resultMap>

	<!-- 查詢妻子信息方法 -->
	<select id="getWifeBeanById" resultMap="wifMap">
		select
		id,wife_name,fk_husband_id from t_wife where id = #{id}
	</select>
        <!-- 丈夫結果集映射2 -->
	<resultMap type="HusbandBean" id="husMap2">
		<id property="id" column="id" javaType="long"></id>
		<result property="husbandName" column="husband_name"
			javaType="string" />
	</resultMap>

	<!-- 查詢丈夫信息方法2 -->
	<select id="getHusbandBeanById2" resultMap="husMap2">
		select
		id,husband_name from t_husband where id = #{id}
	</select>
	
	<!-- 妻子結果集映射2 -->
	<resultMap type="WifeBean" id="wifMap2">
		<id property="id" column="id" javaType="long"></id>
		<result property="wifeName" column="wife_name"
			javaType="string" />

		<!--調用上面的getHusbandBeanById,這裏不允許使用,因爲丈夫查詢過程中調用了妻子的查詢方法,如果調用就形成了循環 -->
		<association property="husbandBean" javaType="HusbandBean"
			fetchType="lazy" column="fk_husband_id" select="getHusbandBeanById2"></association>
	</resultMap>

	<!-- 查詢妻子信息方法2 -->
	<select id="getWifeBeanById2" resultMap="wifMap2">
		select
		id,wife_name,fk_husband_id from t_wife where id = #{id}
	</select>

查詢丈夫就用getHusbandBeanById,查詢妻子就用getWifeBeanById2,這樣就分離了,避免循環套用

 

1)關聯關係(就是一個對象中含有另外一個對象)association

這裏用妻子對象和丈夫對象(分別對應表妻子表,丈夫表,丈夫表中有妻子的外鍵)

HusbandBean:(對應表屬性:id,hus_name,age,fk_wife_id)

private Integer id;
private String husbandName;
private Integer age;
private WifeBean wife;

WifeBean:(對應表屬性:id,wife_name,age)

private Integer id;
private String wifeName;
private Integer age;

 

丈夫接口的方法:

HusbandBean getHusbandBeanById(@Param("id")int id);

丈夫xml映射對應的查詢方法:

<select id="getHusbandBeanById" resultMap="husMap2">
	select id,hus_name,age,fk_wife_id from t_hus where id = #{id}
</select>

對於表中我們需要查詢的列,需要和對象的屬性進行映射,在xml的映射配置中的結果集映射中我們就該使用<association></association>標籤去解決關聯關係。

<resultMap type="HusbandBean" id="husMap2">
		<id property="id" column="id" javaType="int"></id>
		<result property="husbandName" column="hus_name" javaType="string"/>
		<result property="age" column="age" javaType="int"/>
		<!-- association 關聯、關係  用於在映射覆合對象屬性 的值的時候,去調用select屬性對應的方法查詢結果 -->
		<!-- select 屬性,代表在映射覆合屬性時,需要調用的查詢方法,語法:namespace.meth名 -->
		<!-- column="fk_wife_id" 代表需要向select調用的方法中,傳入的值 -->
		
		<!-- fetchType="lazy" 需要對wife對象進行懶加載(延遲加載)傳下去的是妻子外鍵值,也就是妻子的id -->
		<association property="wife" javaType="WifeBean" fetchType="lazy" column="fk_wife_id" select="com.ali.mybatis01.o2omag.mapper.WifeMapper.getWifeBeanById"></association>	
	</resultMap>

<association></association>標籤中select中的屬性(調用關聯對象的查詢方法):比如這裏,就是去調用了妻子中的查詢方式,如果在同一篇配置文件中,可以直接寫調用的方法名,也就是該方法的id,如果調用的是不同的配置中的方法,那麼就要寫全路徑;fetchType就是加載類型,這裏用懶加載才實現用時纔去查詢。

 

妻子接口方法:

WifeBean getWifeBeanById(@Param("id") int id);

妻子xml映射對應的查詢方法:

妻子的通過id查詢的方法:(返回用resultType的話,並且用對象去接收返回結果那麼必須取別名,和類的屬性一致,才能接受到數據)resultType接受數據可以是對象、Map、基本數據類型,引用數據類型。

<select id="getWifeBeanById" resultType="WifeBean">
		select id,wife_name as wifeName,age from t_wife where id = #{id};
</select>

 

2)集合關係(就是一個對象中含有其他對象的集合)collection

 

  • 一對多的關係

      比如老師和學生的關係,一個老師可以有多個學生,那麼老師就含有學生的一個集合,那麼情況與上述情況類似,那麼這些學生中就會含有這個老師的外鍵,那麼我們在查詢老師信息的時候也要實現懶加載,當我們需要學生信息才查詢,不需要學生信息就只去查詢老師自身的信息。

 

這裏就舉例老師和學生(學生表中含有老師表的外鍵

TeacherBean:(表屬性 id,teacher_name,age)

private Integer id;
private String teacherName;
private Integer age;
	
/**
 * 站在老師的角度上來說,一個老師對應多個學生
 */
private List<StudentBean> stus;

StudentBean:(表屬性 id,student_name,age,fk_teacher_id)

private Integer id;
private String studentName;
private Integer age;
	
/**
 * 一個學生只對應一個老師
 */
private TeacherBean teacher;

 

老師接口方法:

TeacherBean getTeacherBeanById(@Param("id") int id);

在xml的映射配置中的結果集映射中我們就該使用<collection></collection>標籤去解決。

<!-- 查詢結果集中老師對象與表的映射關係 -->
	<resultMap type="TeacherBean" id="teacherMap">
		<id property="id" column="id" javaType="int"/>
		<result property="teacherName" column="teacher_name" javaType="string"/>
		<result property="age" column="age" javaType="int"/>
		
		<!-- 查1對1的時候,使用association ,查多的時候,使用collection,內部定義查詢學生的方法,把老師的id傳下去 -->
		<collection property="stus" javaType="java.util.List" fetchType="lazy" column="id" select="findStudentBeanByFkTeacherId"></collection>
	</resultMap>
	
	<!-- 查詢老師信息的方法-->
	<select id="getTeacherBeanById" resultMap="teacherMap">
		select id,teacher_name,age from t_teacher where id = #{id}	
	</select>
	
	<!-- 內部定義查詢學生的方法-->
	<select id="findStudentBeanByFkTeacherId" resultType="StudentBean">
		select id,student_name as studentName,age from t_student where fk_teacher_id = #{id}
	</select>

在上面的關聯關係中已經說了,不管是關聯association還是集合collection,它們在調用方法的時候,如果在同一篇文件中,select屬性可直接寫方法名(方法的id名),如果調用其他xml映射配置的方法,要寫全路徑名。

 

對於學生而言,在我這個例子裏面,一個學生對應一個老師,那麼,要想在查詢學生信息時,對老師的信息,也實現懶加載,就用第一種association方式,細節不多講了,上面已經寫了,直接看代碼。

學生接口方法:

StudentBean getStudentBeanById(@Param("id") int id);

學生xml的映射配置:

<!-- 學生結果集映射-->
	<resultMap type="StudentBean" id="studentMap">
		<id property="id" column="id" javaType="int"/>
		<result property="studentName" column="student_name" javaType="string"/>
		<result property="age" column="age" javaType="int"/>
		
		<!-- 調用老師信息查詢方式-,傳入老師外鍵(也就是對應老師的id)-->
		<association property="teacher" javaType="TeacherBean" fetchType="lazy" column="fk_teacher_id" select="getTeacherBeanById"></association>
	</resultMap>
	
	<!-- 學生信息查詢方式-->
	<select id="getStudentBeanById" resultMap="studentMap">
		select id,student_name,age,fk_teacher_id from t_student where id = #{id}
	</select>
	
	<!-- 老師信息查詢方式-->
	<select id="getTeacherBeanById" resultType="TeacherBean">
		select id,teacher_name as teacherName,age from t_teacher where id = #{id}	
	</select>

 

  • 多對多關係

      在上面的collecton介紹中,它用於了一對多的關係,同時他也用於多對多的關係,存在多對多關係的話,那麼雙方都不可能去寫具體的外鍵了,那麼就需要一箇中間表來將雙方的關係進行串聯起來。

這裏我就用玩家和遊戲的例子來進行,一個玩家可以選擇多個遊戲,一個遊戲可以對應多個玩家。那麼要實現查詢玩家時同時查詢出遊戲,查詢遊戲時查出玩家,看下面代碼。

PlayerBean:(表屬性:id,player_name)

private long id;
private String playerName;
private List<GameBean> games;

GameBean:(表屬性:id,game_name)

private long id;
private String gameName;
private List<PlayerBean> palyers;

中間表t_player_game屬性:id,fk_player_id,fk_game_id

 

玩家接口方法:

List<PlayerBean> findPlayerBeanListByObject(@Param("p") PlayerBean player);

玩家xml映射配置:

    <!--玩家的結果集映射-->
	<resultMap type="PlayerBean" id="playerMap">
		<id property="id" column="id" javaType="int"/>
		<result property="playerName" column="player_name" javaType="string"/>
		
		<!-- 調用方法,傳入玩家的id,通過方法中的中間表去找對應的遊戲id-->
		<collection property="games" javaType="java.util.List" fetchType="lazy" column="id" select="getGameBeanById"></collection>
	
	</resultMap>
	
	<!--通過中間表去查找關聯的遊戲,這裏用到了sql的內聯方式,fk_player_id = #{id}表示了內聯條件,通過這個可以條件關聯到相應的數據行,不會查百度-->
	<select id="getGameBeanById" resultType="GameBean">
		select g.id,g.game_name as gameName from t_game as g,t_player_game as pg 
		where g.id = pg.fk_game_id and fk_player_id = #{id}	
	</select>
	
	
	<!-- 玩家查詢方法,模糊查詢-->
	<select id="getPlayerBeanById" resultType="PlayerBean">
		select id,player_name as playerName from t_player where id = #{id};
	</select>
	
	<select id="findPlayerBeanListByObject" resultMap="playerMap">
		select id,player_name from t_player 
	
		<where>
			1=1
			<if test="p.playerName != null and p.playerName !=''">
				and player_name like concat(#{p.playerName},'%')
			</if>
		</where>
	</select>

同樣的,查詢遊戲的時候也是這種方法,只需要修改一部分代碼。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章