Hibernate多对多操作步骤

来源:互联网 发布:叮叮软件下载 编辑:程序博客网 时间:2024/06/10 02:12

== 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;
      如果改为立即检索;---则可能提取出所有的权限对象;
   如果再配有反向的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();
  所有操作完毕后,无需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"
            
 

 

 

 

             
                                  

 

 

 


 

原创粉丝点击