前言:在項目中,某些實(shí)體類之間肯定有關(guān)鍵關(guān)系,比如一對一,一對多等。在hibernate 中用 one to one和 one to many,而mybatis 中就用 association和 collection。 association: 一對一關(guān)聯(lián)(has one)collection:一對多關(guān)聯(lián)(has many) 注意,只有在做select查詢時才會用到這兩個標(biāo)簽,都有三種用法,且用法類似。 一、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>
以上是實(shí)體類、dao層的設(shè)計以及在UserDao.xml中queryById方法的sql語句的編寫,因?yàn)椴徽撚胊ssociation的哪種方式,sql語句都是一樣的寫,不同的只是userMap的寫法,所以這里先給出這段代碼。User詢Card是一對一關(guān)系,在數(shù)據(jù)庫中,tbuser表通過外鍵cardid關(guān)聯(lián)tb_card表。下面分別用association的三種用法來實(shí)現(xiàn)queryById方法。 1、第一種用法:association中使用select這種方法需要再定義CardDao.java,如下: public interface CardDao {
Card queryCardById(int cardId);
}
在CardDao.xml中實(shí)現(xiàn)該方法: <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方法。個人感覺這種方法比較麻煩,因?yàn)檫€要在CardDao里定義queryCardById方法并且實(shí)現(xiàn)再引用才有用,不過這種方法思路清晰,易于理解。 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標(biāo)簽中通過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 標(biāo)簽里面,通過javaType來指定是哪個類的resultMap,個人認(rèn)為這種方法最簡單,缺點(diǎn)就是cardMap不能復(fù)用。具體用哪種方法,視情況而定。 二、collection的三種用法:一個土豪有多個手機(jī),看如下代碼: User實(shí)體類 public class User{
private Integer userId;
private String userName;
private Integer age;
private List<MobilePhone> mobilePhone;//土豪,多個手機(jī),1對多
}
手機(jī)類 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>
數(shù)據(jù)庫中,tbmobilephone中user_id作為外鍵。那么下面來看resultMap如何定義: 1、第一種方法:用select,跟association 中使用select類似:先定義 MobilePhoneDao.java public interface MobilePhoneDao {
List<MobilePhone> queryMbByUserId(int userId);
}
然后實(shí)現(xiàn)該方法 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>
做好以上準(zhǔn)備工作,那就可以在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就行了。 3、第三種方法:嵌套resultMap簡化版<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 標(biāo)簽中的resultType以及association中的javaType,collection中的ofType,這里只寫了類名,是因?yàn)樵趍ybatis-config.xml中配置了typeAliases,否則就要寫該類的全類名。配置如下: <typeAliases>
<packagename="com.zhu.smm.entity"/>
</typeAliases>
總結(jié):1、association表示的是has one的關(guān)系,一對一時使用。user has one card,所以在user的resultMap中接收card時應(yīng)該用association; 2、collection表示的是has many的關(guān)系,一對多時使用。user has many mobilePhone,所以在user的resultMap中接收mobilePhone時應(yīng)該用collection 。 3、都有三種用法,且非常類似,resultMap要復(fù)用建議第二種方法,不需要復(fù)用建議第三種方法。 4、特別注意表中主鍵字段要有所區(qū)分,不能都寫成id,要寫成userid、cardid,反正要有所區(qū)分,不然查詢的時候會查不到完整的數(shù)據(jù)。
|