2025-04-22

== 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

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *