天天看點

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才能和資料庫同步;