前言:
在項目中,某些實體類之間肯定有關鍵關系,比如一對一,一對多等。在hibernate 中用
one to one
和
one to many
,而mybatis 中就用
association
collection
。
association: 一對一關聯(has one)
collection:一對多關聯(has many)
注意,隻有在做select查詢時才會用到這兩個标簽,都有三種用法,且用法類似。
一、association的三種用法:
先看如下代碼(省略set、get方法):
public class User {
private Integer userId;
private String userName;
private Integer age;
private Card card;//一個人一張身份證,1對1
}
public class Card {
private Integer cardId;
private String cardNum;//身份證号
private String address;//位址
}
public interface UserDao {
/**
* 通過userId查詢user資訊
* @param userId
* @return
*/
User queryById(int userId);
}
<select id="queryById" parameterType="int" resultMap="userMap">
SELECT u.user_name,u.age,c.card_id,c.card_num,c.address
FROM tb_user u,tb_card c
WHERE u.card_id=c.card_id
AND
u.user_id=#{userId}
</select>
以上是實體類、dao層的設計以及在UserDao.xml中queryById方法的sql語句的編寫,因為不論用association的哪種方式,sql語句都是一樣的寫,不同的隻是userMap的寫法,是以這裡先給出這段代碼。User詢Card是一對一關系,在資料庫中,tb_user表通過外鍵card_id關聯tb_card表。下面分别用association的三種用法來實作queryById方法。
1、第一種用法:association中使用select
這種方法需要再定義CardDao.java,如下:
public interface CardDao {
Card queryCardById(int cardId);
}
在CardDao.xml中實作該方法:
<select id="queryCardById" parameterType="int" resultType="Card">
SELECT *
FROM tb_card
WHERE card_id=#{cardId}
</select>
然後再看UserDao.xml中是如何引用這個方法的:
<resultMap type="User" id="userMap">
<result property="userName"
column="user_name"/>
<result property="age"
column="age"/>
<association property="card"
column="card_id"
select="com.zhu.ssm.dao.
CardDao.queryCardById">
</association>
</resultMap>
在這裡直接通過select引用CardDao的queryById方法。個人感覺這種方法比較麻煩,因為還要在CardDao裡定義queryCardById方法并且實作再引用才有用,不過這種方法思路清晰,易于了解。
2、第二種方法,嵌套resultMap
<resultMap type="Card" id="cardMap">
<id property="cardId"
column="card_id"/>
<result property="cardNum"
column="card_num"/>
<result property="address"
column="address"/>
</resultMap>
<resultMap type="User" id="userMap">
<result property="userName"
column="user_name"/>
<result property="age"
column="age"/>
<association property="card"
resultMap="cardMap">
</association>
</resultMap>
第二種方法就是在UserDao.xml中先定義一個Card的resultMap,然後在User的resultMap的association标簽中通過resultMap="cardMap"引用。這種方法相比于第一種方法較為簡單。
3、第三種方法:嵌套resultMap簡化版
<resultMap type="User" id="userMap">
<result property="userName"
column="user_name"/>
<result property="age"
column="age"/>
<association
property="card"
column="card_id"
javaType="Card">
<id property="cardId"
column="card_id"/>
<result property="cardNum"
column="card_num"/>
<result property="address"
column="address"/>
</association>
</resultMap>
這種方法就把Card的resultMap定義在了association 标簽裡面,通過javaType來指定是哪個類的resultMap,個人認為這種方法最簡單,缺點就是cardMap不能複用。具體用哪種方法,視情況而定。
二、collection的三種用法:
一個土豪有多個手機,看如下代碼:
User實體類
public class User{
private Integer userId;
private String userName;
private Integer age;
private List<MobilePhone> mobilePhone;//土豪,多個手機,1對多
}
手機類
public class MobilePhone {
private Integer mobilePhoneId;
private String brand;//品牌
private double price;//價格
private User user;//主人
}
dao層
public interface UserDao {
/**
* 通過userId查詢user資訊
* @param userId
* @return
*/
User queryById(int userId);
}
UserDao.xml中的select查詢語句
<select id="queryById" parameterType="int" resultMap="userMap">
SELECT u.user_name,u.age,
m.brand,m.price
FROM tb_user u,tb_mobile_phone m
WHERE m.user_id=u.user_id
AND
u.user_id=#{userId}
</select>
資料庫中,tb_mobile_phone中user_id作為外鍵。那麼下面來看resultMap如何定義:
1、第一種方法:用select,跟association 中使用select類似:
先定義 MobilePhoneDao.java
public interface MobilePhoneDao {
List<MobilePhone> queryMbByUserId(int userId);
}
然後實作該方法 MobilePhoneDao.xml
<resultMap type="MobilePhone"
id="mobilePhoneMap">
<id property="mobilePhoneId"
column="user_id"/>
<result property="brand"
column="brand"/>
<result property="price"
column="price"/>
<association property="user"
column="user_id" select=
"com.zhu.ssm.dao.UserDao.queryById">
</association>
</resultMap>
<select id="queryMbByUserId" parameterType="int" resultMap="mobilePhoneMap">
SELECT brand,price
FROM tb_mobile_phone
WHERE user_id=#{userId}
</select>
做好以上準備工作,那就可以在UserDao.xml中引用了
<resultMap type="User" id="userMap">
<id property="userId" column="user_id"/>
<result property="userName"
column="user_name"/>
<result property="age"
column="age"/>
<collection property="mobilePhone"
column="user_id"
select="com.zhu.ssm.dao
.MobilePhoneDao.queryMbByUserId">
</collection>
</resultMap>
這種方法和association的第一種用法幾乎是一樣的不同之處就是mobilePhMap中用到了association ,queryMbByUserId中要使用mobilePhoneMap,而不能直接使用resultType。
2、第二種方法:嵌套resultMap
<resultMap type="MobilePhone" id="mobilephoneMap">
<id column="mobile_phone_id" property="mobilePhoneId"/>
<result column="brand" property="brand" />
<result column="price" property="price" /></resultMap>
<resultMap type="User" id="userMap">
<result property="userName" column="user_name"/>
<result property="age" column="age"/>
<collection property="mobilePhone" resultMap="mobilephoneMap" >
</collection>
</resultMap>
定義好這兩個resultMap,再引用UserMap就行了。
<resultMap type="User" id="userMap">
<result property="userName" column="user_name"/>
<result property="age" column="age"/>
<collection property="mobilePhone"
column="user_id"
ofType="MobilePhone">
<id column="mobile_phone_id" property="mobilePhoneId" />
<result column="brand"
property="brand" />
<result column="price"
property="price" />
</collection>
</resultMap>
這種方法需要注意,一定要有ofType,collection 裝的元素類型是啥ofType的值就是啥,這個一定不能少。
注意:
所有resultMap中的type、select 标簽中的resultType以及association中的javaType,collection中的ofType,這裡隻寫了類名,是因為在mybatis-config.xml中配置了typeAliases,否則就要寫該類的全類名。配置如下:
<typeAliases>
<packagename="com.zhu.smm.entity"/>
</typeAliases>
總結:
1、association表示的是has one的關系,一對一時使用。user has one card,是以在user的resultMap中接收card時應該用association;
2、collection表示的是has many的關系,一對多時使用。user has many mobilePhone,是以在user的resultMap中接收mobilePhone時應該用collection 。
3、都有三種用法,且非常類似,resultMap要複用建議第二種方法,不需要複用建議第三種方法。
4、特别注意表中主鍵字段要有所區分,不能都寫成id,要寫成user_id、card_id,反正要有所區分,不然查詢的時候會查不到完整的資料。