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