hibernate复习第四天

本文详细介绍了ORM中多对多关系的处理方法,包括中间表的设计与配置,以及多态查询的不同策略。探讨了如何通过不同类型的表结构来支持多态查询,并解释了Session安全性管理的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


回顾:
        PO的状态;
        cascade级联操作
        事务控制
一, 多对多
     Student 中有一个course的set 集合; Course中有一个Student的set 集合;
     数据库中没有办法直接表示多对多;
     必须有一个中间表;
     t_student       s_c         t_course
        sid          fsid   fcid        cid
        s1           s1     c1         c1
        s2           s1     c2        c2
        s3           s2     c1         c3
                       s3     c3
     多对多表:
create table t_student(
    sid number(11) primary key,
    name varchar(15) not null,
    stuId varchar(30) unique not null
 );
 create table t_course(
    cid number(11) primary key,
    name varchar(20) not null,
    courseId varchar(30) unique not null
 );
 create table t_enrollment(
    fsid number(11) references t_student(sid),
    fcid number(11) references t_course(cid),
    constraint many2many_534oijhsd34
    primary key(fsid,fcid)
 );
 
xml配置文件:

Student.xml
     <class name="Student" table="T_STUDENT">
  <id name="sid" column="sid">
   <generator class="native" />
  </id>
   <property name="name"  />
   <property name="stuId" />
   <set name="courses"  table="s_c"  cascade="save-update" inverse="true"><!--inverse="true" 写在一端就行了 -->
        <key column="fsid" />  <!--关系的另一方的表中与本表关联的外键字段; -->
        <many-to-many class="Course" column="fcid" /> <!-- Course表在中间表对应的外键字段-->
   </set>
    </class>
   
    多对多的set与一对多的set的意思不一样;这里映射的是中间表;
   
    属性的映射;
    name="courses" 对应的是一个表, 不是一个字段;
    key  表示关系的另一方(关联表)的外键;  column="fsid" 是Student表在关联表中的外键,
                                                            表示了一个一对多关系;
    class 是集合里元素的类型是Course; 多对多的关系, column="fcid"是Course表在关联表中外键,
                                                            表示了另外一个一对多;
   
    PO的角度;<many-to-many>  说明了多对多的关系;
     在设计的时候有可能将多对多关系变成一对多的关系;
     加一个选课类即可;学生和选课对象变成一对多的关系;
     一个选课对象只能对一个学生;一个学生对应多个选课对象;
    
 Course.xml 
 
    <class name="Course" table="T_COURSE">
  <id name="cid" column="cid">
   <generator class="native" />
  </id>
   <property name="name"  />
   <property name="courseId" />
   <set name="students" table="s_c"   cascade="save-update" >
        <key column="fcid" />
        <many-to-many class="Student" column="fsid" />
   </set>
 </class>
 
 二, 查询:
 
    传过来的搞不清楚是游离态还是暂态就用saveOrUpdate();
    Smalltalk 语言的语法; a 对象调用一个x方法返回a对象, 继续调用y 方法仍返回a 对象;
    返回void时也返回自己;
    s=(Student)session.createQuery("from Student s where stuID =: stuID")
                               .setString("stuID",stuID)
                               .uniqueResult();
    其他查询:
   
    "from Student s where stuName  like :stuName"
    连接表查询:面向对象的写法:
    "select s.name,c.name from Student s join s.courses  c"
 
    内连接:
        是保证两个表中所有的行都要满足连接条件;
        并不是所有的学生都有选课记录;
    外连接:
    会使用一方表中的所有记录去和另一表中的记录按条件匹配
   
    左右外连接 只是一种形式:与 (+) 本质上是一样的:  
    Left  Outer Join 包含了左表中的全部行(表达式中第一个表)
    Right Outer Join 包括了右表中的全部行(表达式中第二个表)
    也就是说在oracle中+号放在=右边相当于左连接,而+号放在=左边相当于右连接
   
    就地加工成 component (组件) NamePair : 细粒度对象;
    用作报表;
   
    对两个实体进行join操作;每一个学生选的所有课;
   
    "select new com.NamePair(s.name, c.name)from Student s join s.courses  c"
   
    用的时候才加载; 延迟加载;集合里的对象只是代理;session关闭就不行了;
    dao里写session不好;
   
三, 继承映射:
  1,  每个类建一个表
    特点:
           最接近于面向对象的结构;
           查询效率低,任何一个查询都要连接表;不利于做报表;
           在类比较多的情况下用这个;    
  2,  只有具体类才建表
    特点:
           查询效率也不是很高;
           对多态支持不好;
  3,  所有类对应一张表  (这种用的最多)
       特点:
           结构简单,就一个表,查询效率高,做报表也很方便;
           表太大,不太好维护,做索引不好做;子类的字段可以为空的;
  
   映射关系:
   Account:
   DebitAccount:  站在银行的角度,银行是借方;  courrency
   CheckAccount: 客户可以透支,银行是贷方;      overdraft
  
  
   3- 所有类一共一张表 -perhiarchy:  表里多了一个type字段;
 
       <discriminator  column="type" />   <!-- 区分字段,写在id后面,version前面; -->
       <subclass  name="DebitAccount" discriminator-value="D区分字段名">
              <property name="currency" />
       </subclass>
        模拟建表:
        create table t_account(
        aid number(15) primary key,
        ... //父类和子类的所有字段
        type varchar(20) not null
        );
       
   1- 一个类一个表-
        子表主键引用父表;
       
       <joined-subclass name="DebitAccount" table="t_DebitAccount">
           <property name="currency" />
           <key column="dfid" />    <!-- key的作用就是外键,子表引用父表的主键-->
       </joined-subclass>
  
           模拟建表:
           create table  t_account(
               aid number(11) primary key,
               ...//父类的所有字段
           );
       
           create table t_debitaccount(
                dfid number(11) primary key
                references t_account(aid),
                ...//子类的字段
            );
            create table t_checkaccount(
                cfid number(11) primary key
                references t_account(aid),
                ...//子类的字段
            );
    左外连接实现多态;
   
   2- 具体类对应表,父类没有表 -
        子类表中包含父类的字段和自己的字段;
        字段定义上有冗余,数据本身没有冗余;
        两个表之间没有关系; 单独写两个映射文件也是可以的;
      
        配置父类的属性;//两个表公用这些字段;名称相同;
        <union-subclass  name="DerbitAccount"  table="t_account_derbit">
            <property name="currency">
        </union-subclass>
       
        模拟建表:
        create table t_account_derbit(
                aid number(11) primary key,       
                ...//父类的属性    
                currency varchar(10) not null
                ...//子类的属性
         );

         create table t_account_check(
                pid number(11) primary key,
                 ...//父类的属性    
                 ...//子类的属性
         );
           
   多态怎么完成的:做了三个子查询;很复杂;效率低;
  
    映射关系原则:
    1)   不要求多态查询的话可以用一个具体类一个表;
    2)   要求多态查询的话,并且类少并且属性少用一个表;
    3)   要求多态类多并且大用一个类一个表;              
    一般都采取第二种;
  
   关联属性定义在父类比较好;配置时写在父类里;
   组件映射和集合映射明天讲;
  
四, session的安全性:
     把session作为参数时, 有可能在一个dao中用到了不同的session;这样很不安全;
     所以考虑和线程绑定,一个线程只用一个session;就能保证一系列的连续的任务用的是一个session;
     有一个绑定session和线程的工具:
     java.lang.ThreadLocal  是一个类;  jdk1.2就有了;
    
       原理:
           内部打开了一个Map;  key是线程对象, value是session对象;
           t1   object1
           t2   session1
       在t1线程里调用:TL.get();==>返回t1线程对应的object1;
       在t2线程里调用:TL.set(s1);==>设置t2线程的value为session1;
  
   在HbnUtil里维护一个静态的属性:
       private static final  ThreadLocal  threadLocal=new ThreadLocal();
       //一个线程一个session;
       public  static Session  getCurrentSession(){
            Session  s=(Session)threadLocal.get();//得到当前线程的session
            if(s==null){//如果为空,就打开一个session,并和当前线程关联起来;
                    s=sf.openSession();
                    threadLocal.set(s);
             }
             return  s;
        }
       //释放session;
       public static void close(){
            Session  s=(Session)threadLocal.get();
             if(s!=null && s.isopen()){//
                s.close(); //关闭当前线程的session
             }
             threadLocal.set(null);//和当前线程解除关联;
       }
      
       将dao中的属性session和 setSession()方法去掉;通过工具类得到当前线程的session;     
       当有一系列操作时, 用了几次session,保证是同一个session才能和数据库同步;
      
      
      

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值