== Hibernate_ManytoMany_(AssociationMapping之一)
(一) 關聯映射準備步驟:
1)Table加中間表,加關聯字段。無需建立主外鍵約束。 建立<usr表>、<authorization表>、及中間表<userauth表>。
2)關聯映射實現:
方案一)此時已有兩個1對*,可以用【兩個1對*】配置來實現。
缺點:配置復雜。連表查詢時,select語句生成多; 不建議采用。
方案二)用【一個 *—*】,來直接配置實現。
特點:隻寫一套映射配置—-<usr.hbm.xml> + Usr PO────→<authorization.hbm.xml> + Authorization PO隻涉及兩個PO類、兩個《 .hbm.xml》文件。
加瞭中間表,但並不加<中間表.hbm.xml> 和 PO類;
3)先用工具,生成兩個多端的單表配置;
4)兩端PO添加關聯屬性集合
private Set auths = new HashSet();
private Set users = new HashSet();
5)再添加 <表名.hbm.xml>中的關聯映射配置:
特點: 多對多 和 一對一 一樣,兩邊配置都十分對稱。
本質:可以看到多對多其實就是一對多;<set、lazy=、cascade=、inverse=、<key等都是按1對多來走的;
一對一、多對多 兩邊配置都十分對稱。
<set name="auths" table="userauth"—中間表名
azy="true"
cascade="all"—六種
inverse="false"
<key colume="userid"/>—–表中有關聯字段時,設置此項,中間表關聯本端的字段名
<many-to-many class="包名.Authorization" column="authid"/>
</set>
◇◇中間表的id,最好設置為自動增長;否則級聯插入時,中間表的主鍵id,因為沒法人工設置,隻能自動使用缺省值,就隻能插入一條;
(二)多對多的操作:
(1)級聯插入
—DAO:
/**
* 插入User PO記錄,級聯插入該用戶擁有的權限PO記錄;
* @param usr—臨時態User PO對象;
*/
public void addUsr(Usr usr){
Transaction tr=null;
Session session=null;
try{
session=HibernateSessionFactory.getSession();
tr=session.beginTransaction();
session.save(usr);//將級聯插入該用戶擁有的所有權限authorization PO記錄
tr.commit();
}catch(Exception e){
e.printStackTrace();
try{
tr.rollback();
}catch(HibernateException he){
he.printStackTrace();
}
}finally{
session.close();
}
}
—BO:張磊磊。
public static void main(String[] args) {
Usr usr=new Usr(); ————先做好一個新用戶;(臨時態)
usr.setAddress("changchun");
usr.setName("zhangsan");
usr.setMale("male");
usr.setId(225);//主鍵,App設置;DB中為varchar 或 int;
Authorization aut=new Authorization(); —–再做好幾個該用戶擁有的新權限;(臨時態)
aut.setColumnId(111);
aut.setAuthorize(new Integer(123));
aut.setInit(new Integer(124));
aut.setId(1008); //主鍵,
Authorization aut1=new Authorization();—–新權限;
aut1.setColumnId(112);
aut1.setAuthorize(new Integer(113));
aut1.setInit(new Integer(114));
aut1.setId(1009);
//建立兩種PO的關聯;
Set set1=usr.getAuthorization(); —先獲得關聯屬性集合Set;(HashSet)
set1.add(aut); //權限集合中加入權限PO;建立關聯
set1.add(aut1);
UsrDAO usrdao=new UsrDAO();—調用DAO方法,實現級聯插入;
usrdao.addUsr(usr);
}
結果:插左PO記錄,級聯插入中間表記錄,以及右PO記錄;
▲ 結論:多對多和一對一 一樣,可以隻配置單向關聯。
=========聯表查詢=====
//沒關聯記錄時,沒顯示。
//故意插入幾個關聯記錄,再試試。
問:可以隻配單邊映射配置,隻實現單向查詢嗎?
i)寫DAO內:《HibernateService.java》
[數據訪問方法] ducongan.
public List listAllUsrCascadeAuthorization() throws HibernateException{
List list = null;
Session session = null;
Transaction tx = null;
…………………………
list = session.createQuery("from Usr").list(); //查出Usr PO對象,自動聯表查出Authorization PO對象。
━━━━━━━━━━━
………………………… //是否級聯操作、聯表查詢,從上層Hibernate API無法看出,關鍵在.hbm.xml中。
return list;
}
註意:查出的list的意義。
5)BO (main)中,寫調用該DAO方法:
List list= DAO對象.listAllUsrCascadeAuthorization();
Usr userpo=(Usr)list.get(0); //這個是一個Usr PO對象。
Set st=userpo.getAuths(); //取出該Usr PO對象中的關聯屬性Set
//遍歷HashSet,it.next(),取出的是該Usr PO的一個權限PO。 —-曬曬老知識:Set隻能遍歷,不易於單個讀取。
//註意:檢索策略;User—-Authorization;默認使用延遲檢索;—所以,不要關閉Session;
如果改為立即檢索;—則可能提取出所有的權限對象;www.aiwalls.com
如果再配有反向的Authorization—-User;且為立即檢索,—則連鎖效應可能提取大量無用的關聯對象;
作業:撰寫代碼實現查詢,查出《usr表》中name='張局長' 的user用戶,其所擁有的各個(或第一個)權限,和其他哪些用戶同時擁有這些權限?
要求:必須列出張局長擁有哪些權限,及其權限名;
還要列出每個權限所有擁有者的用戶名;
答案:
—BO:
UserDao userDao = new UserDao();
User findUserByName = userDao.findUserByName("張局長");
System.out.println("張局長的ID號: "+findUserByName.getId());
Set auths = findUserByName.getAuths(); //▲延遲加載,關聯集合其中PO為代理對象;
//▲註意:因為是延遲加載,所以自動使用Hibernate實現的PersistenceSet,不能強制轉換回HashSet;
System.out.println("權限個數: "+auths.size()); //▲用到此PO時,臨時加載;
Iterator it = auths.iterator();
while(it.hasNext()){
Authorization az = (Authorization)it.next(); //◆取出一個權限對象; 用到此PO時,臨時加載;
System.out.println("==權限ID號為:"+az.getId()); //用到此PO屬性時,臨時加載屬性值;
System.out.println("權限號為:"+az.getAuth());
//提取該權限的所有用戶; 也是延遲加載;
Set users = az.getUsers();//拿到該權限的用戶集合;
Iterator iterator = users.iterator();//遍歷該用戶集合;
while(iterator.hasNext()){
User user = (User)iterator.next(); //◆取出一個擁有該權限的用戶; 用到此PO時,臨時加載;
System.out.println("\t擁有該權限的用戶:"+user.getName()+"\t用戶ID號: "+user.getId()); //用到此PO時,臨時加載;
}
}
//關閉Session;
//如果後續還要使用該Session,進行其他Dao操作,則僅關閉該Session緩存,但並不使其消失;
userDao.sessionClose(); www.aiwalls.com
所有操作完畢後,無需Session,此時應關閉Session使其消失;
userDao.closeSession();
數據例子: 《user表》中,1號的張局長,《userauth表》中,擁有:10號、22號權限;
4號 趙科長, 也擁有:10號;
5號 劉。。, ……:10號;
《userauth》表
┌───┬───┬───┐
│ id │ uid │ auid │
├───┼───┼───┤
│ 1 │ │ │
├───┼───┼───┤
│ 2 │ 1 │ 10 │
├───┼───┼───┤
│ 3 │ 2 │ 15 │
├───┼───┼───┤
│ 4 │ 1 │ 22 │
├───┼───┼───┤
│ 5 │ │ │
├───┼───┼───┤
│ │ │ │
├───┼───┼───┤
│ │ 5 │ 10 │
├───┼───┼───┤
│ │ 2 │ 22 │
└───┴───┴───┘
結果:全部延遲加載,連表查詢,用的是單表select語句實現。
總結:*-*的檢索策略,與1-*的檢索策略,相同;
━━━━━━━━━━━━━━━━━━
延遲加載:lazy="true"
立即加載:lazy="false" fetch="select"
預先抓取:lazy="false" fetch="join"
作者:oh_Mourinho