天天看点

hibernate复习第四天

回顾:

        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才能和数据库同步;