※XML設定
※Set
假設新的學期開始,每個人都有很多不同的課本,所以在資料庫增加兩個table,如下:
※前置作業
DROP TABLE PERSON PURGE; DROP TABLE BOOK PURGE; CREATE TABLE PERSON( PID VARCHAR(10) , PERSON_NAME VARCHAR(50) , CONSTRAINT PERSON_PK PRIMARY KEY(PID) ); CREATE TABLE BOOK( BID VARCHAR(50) , BOOK_NAME VARCHAR(200) , CONSTRAINT BOOK_FK FOREIGN KEY(BID) REFERENCES PERSON(PID) ON DELETE CASCADE );
Person.java
public class Person {
private Integer pid;
private String personName;
private Set<Object> xxx = new HashSet<Object>(0);
//setter/getter...
}
※不需要Book.java,集合映射會去找
Person.hbm.xml
<class name="vo.Person" table="PERSON"> <id name="pid" type="java.lang.Integer"> <column name="PID" /> <generator class="assigned" /> </id> <property name="personName" type="java.lang.String"> <column name="PERSON_NAME" /> </property> <set name="xxx" table="BOOK"> <!--lazy="false"> --> <key not-null="true"> <column name="BID" /> </key> <element type="java.lang.String" column="BOOK_NAME"/> </set> </class>
測試類:
Session s = HibernateUtil2.getSession();
Transaction tx = s.beginTransaction();
try {
Person p = new Person();
p.setPid(1);
p.setPersonName("john");
p.getXxx().add("國文");
p.getXxx().add("英文");
p.getXxx().add("英文");
p.getXxx().add(null);
s.saveOrUpdate(p);
tx.commit();
Person person = (Person) s.get(Person.class, 1);
//s.close();
System.out.println(person.getPersonName());
System.out.println(person.getXxx());
} catch (Exception e) {
System.err.println("例外錯誤!");
e.printStackTrace();
tx.rollback();
} finally {
if (s.isOpen()) {
s.close();
}
}
在控制台會顯示:
※第一次會執行select person,然後insert person,再連續執行三次的insert book
第二次發現資料庫有值時,inser person會變成delete book的動作,其他都一樣
※設定null是可以的,就算hbm.xml設定not-null="true"也沒用,其實我一直都在用3.6.10在測,屬性常常都沒什麼用,譬如前面的<property>或者它底下的<column>,我設定length,長度故意設的比資料庫還短,或者兩個都設,但還是新增修改成功
※上面的s.close()註解打開,一樣可以很順利執行完,應該是一級快取的關係
但如果只查詢且提找關閉,也就是把commit()上面的都註解掉且close打開,而且只查xxx,就會出「org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: vo.Person.xxx, no session or session was closed」的錯誤,這時就要把hbm.xml的lazy="false"註解打開即可解決,此時控制台會先執行select person後,再執行select book
再看一個例子:
Session s = HibernateUtil2.getSession();
Transaction tx = s.beginTransaction();
try {
Person person = (Person) s.get(Person.class, 1);
s.close(); // Detached
Set<Object> p = new HashSet<Object>();
p.addAll(person.getXxx());
p.add("數學");
person.setXxx(p);
HibernateUtil2.getSession().update(person); // Persistent
HibernateUtil2.getSession().beginTransaction().commit();
} catch (Exception e) {
System.err.println("例外錯誤!");
e.printStackTrace();
HibernateUtil2.getSession().beginTransaction().rollback();
} finally {
if (s.isOpen()) {
s.close();
}
}
※尤於一查到就close,所以狀態已變成Detached,包括tx都依賴s,都不能用了,所以後面都是從HibernateUtil2開頭
※控制台會先select person-->select book-->update person-->delete book-->insert book三次
可以看出會整個bid為1的全部刪除再新增
※delete時,因為準備資料那裡有加on delete cascade,所以會幫book刪除
如果沒加就出錯,反正以資料庫為準,hibernate不幫忙,就算在set加cascade="all",還是沒用,這點很奇怪
※List
※前置作業
DROP TABLE PERSON PURGE; DROP TABLE BOOK PURGE; CREATE TABLE PERSON( PID VARCHAR(10) , PERSON_NAME VARCHAR(50) , CONSTRAINT PERSON_PK PRIMARY KEY(PID) ); CREATE TABLE BOOK( BID VARCHAR(50) , BOOK_NAME VARCHAR(200) , IND NUMBER(3), CONSTRAINT BOOK_FK FOREIGN KEY(BID) REFERENCES PERSON(PID) ON DELETE CASCADE );
※尤於index為關鍵字,只好取ind
Person.hbm.xml
<class name="vo.Person" table="PERSON"> <id name="pid" type="java.lang.Integer"> <column name="PID" /> <generator class="assigned" /> </id> <property name="personName" type="java.lang.String"> <column name="PERSON_NAME" /> </property> <list name="xxx" table="BOOK" lazy="false"> <key> <column name="BID" /> </key> <index column="IND" /> <!-- <list-index column="IND" /> --> <element type="java.lang.String" column="BOOK_NAME"/> </list> </class>
※list底下一定要有index,不然會報錯
※list-index和index我試的結果都可以
※測試類都和Set一樣,此時可以重覆,ind欄位預設會從0遞增,可以用base屬性改變
※Array
和List很像,只是hbm.xml的list改成array,而vo將List改成String[],其他都和上面的List一樣,也是index和list-index都可以
屬性有些不太一樣,像lazy,在Array就沒有這個屬性
屬性有些不太一樣,像lazy,在Array就沒有這個屬性
※Bag
和List很像,但沒有index,所以前置作業和Set一樣,而hbm.xml將List改成bag,index或list-index不要,其他都和上面的List一樣,還是有lazy屬性※Map
※前置作業
DROP TABLE PERSON PURGE; DROP TABLE BOOK PURGE; CREATE TABLE PERSON( PID VARCHAR(10) , PERSON_NAME VARCHAR(50) , CONSTRAINT PERSON_PK PRIMARY KEY(PID) ); CREATE TABLE BOOK( BID VARCHAR(10) , BOOK_NAME VARCHAR(50) , BOOK_PRICE NUMBER(4), CONSTRAINT BOOK_FK FOREIGN KEY(BID) REFERENCES PERSON(PID) ON DELETE CASCADE );
※增加BOOK_PRICE,將書名和書的價錢挷在一起變成Map
Person.hbm.xml
<class name="vo.Person" table="PERSON"> <id name="pid" type="java.lang.Integer"> <column name="PID" /> <generator class="assigned" /> </id> <property name="personName" type="java.lang.String"> <column name="PERSON_NAME" /> </property> <map name="xxx" table="BOOK" lazy="false"> <key> <column name="BID" /> </key> <map-key type="java.lang.String" column="BOOK_NAME" /> <!-- <index column="BOOK_NAME" type="java.lang.String" /> --> <element type="java.lang.Integer" column="BOOK_PRICE"/> </map> </class>
※map-key也可以用List的index,就是註解那一行,而list-index就沒這種屬性了
Person.java
public class Person {
private Integer pid;
private String personName;
private Map<String, Integer> xxx = new HashMap<String, Integer>(0);
//setter/getter...
}
測試類:
Session s = HibernateUtil2.getSession();
Transaction tx = s.beginTransaction();
try {
Person p = new Person();
p.setPid(1);
p.setPersonName("john");
p.getXxx().put("國文", 120);
p.getXxx().put("英文", 80);
p.getXxx().put("數學", 60);
s.saveOrUpdate(p);
tx.commit();
Person person = (Person) s.get(Person.class, 1);
s.close();
System.out.println(person.getXxx());
} catch (Exception e) {
System.err.println("例外錯誤!");
e.printStackTrace();
HibernateUtil2.getSession().beginTransaction().rollback();
} finally {
if (s.isOpen()) {
s.close();
}
}
※Annotation設定
Set和Bag
@Entity
@Table(name = "PERSON")
public class Person {
@Id
private Integer pid;
@Column(name = "PERSON_NAME")
private String personName;
// @CollectionOfElements(targetElement=String.class, fetch = FetchType.EAGER) 已廢棄,用@ElementCollection
@ElementCollection(targetClass = String.class, fetch = FetchType.EAGER)
// @CollectionTable(name = "BOOK", joinColumns = { @JoinColumn(name = "BID")}) 和@JoinTable取其一,都可用
@JoinTable(name = "BOOK", joinColumns = { @JoinColumn(name = "BID") })
@Column(name = "BOOK_NAME")
private Set<Object> xxx = new HashSet<Object>();
//setter/getter...
}
※FetchType有LAZY和EAGER,EAGER就是急切,不懶的意思
※FetchType.LAZY 就是XML設定的fetch="select";
FetchType.EAGER就是XML設定的 fetch ="join"
List
//和Set一樣, 但多兩行,ooo要對應好, //不能和下面Array的Annotation混用,但不會報錯,只是IND永遠是Null,控制台的insert語句並不會包括IND @CollectionId(columns = @Column(name="IND", nullable=false), type=@Type(type="long"), generator = "ooo") @GenericGenerator(name="ooo",strategy="increment") private List<Object> xxx = new ArrayList<Object>();
※從1開始累加,我找不到像Array的base選項可以設定開始值,可能是以資料庫設定為主吧
※strategy共有13種,官網在這的5.1.2.2.1. Various additional generators
Array
//和Set一樣,不能和List的Annotation混用,會報錯 @IndexColumn(name = "IND", base = 1) private String[] xxx;
※base=1表示從1開始累加,XML也有
Map
@Entity
@Table(name = "PERSON")
public class Person {
@Id
private Integer pid;
@Column(name = "PERSON_NAME")
private String personName;
@ElementCollection(targetClass=Integer.class, fetch = FetchType.EAGER)
// @org.hibernate.annotations.MapKey(columns = { @Column(name = "BOOK_NAME", nullable = false) }) 已廢棄,用@MapKeyColumn
@MapKeyColumn(name = "BOOK_NAME")
@CollectionTable(name = "BOOK", joinColumns = { @JoinColumn(name = "BID") })
@Column(name = "BOOK_PRICE")
private Map<String, Integer> xxx = new HashMap<String, Integer>(0);
//setter/getter...
}
※用MapKey時,注意import哪一個package,所以我將全名打出來,不過反正已廢棄了
沒有留言:
張貼留言