※table per subclass(joined-subclass)
※準備資料
DROP TABLE STUDENT; DROP TABLE MAKER; DROP TABLE CHESS; CREATE TABLE CHESS ( ID NUMBER(5), NAME VARCHAR(10), PRICE NUMBER(5), PRODUCT_DATE DATE, CONSTRAINT PK_CHESS PRIMARY KEY(ID) ); CREATE TABLE STUDENT( ID NUMBER(5), SCORE NUMBER(3), SCHOOL VARCHAR(20), CONSTRAINT PK_STUDENT PRIMARY KEY(ID), CONSTRAINT FK_STUDENT_ID FOREIGN KEY(ID) REFERENCES CHESS(ID) ON DELETE CASCADE ); CREATE TABLE MAKER( ID NUMBER(5), SALARY NUMBER(6), COMPANY VARCHAR(20), CONSTRAINT PK_MAKER PRIMARY KEY(ID), CONSTRAINT FK_MAKER_ID FOREIGN KEY(ID) REFERENCES CHESS(ID) ON DELETE CASCADE );
※和table per concrete class相比較,差在多一張CHESS表
※XML設定
Chess.java
public abstract class Chess {
private Integer id;
private String name;
private Integer price;
private Date productDate;
//setter/getter...
}
※Chess.java、Student.java、Maker.java和table per concrete class (Hibernate3.x 十六)一樣
Student.java
public class Student extends Chess {
private Integer score;
private String school;
//setter/getter...
}
Maker.java
public class Maker extends Chess {
private Integer salary;
private String company;
//setter/getter...
}
Chess.hbm.xml
<id name="id" type="java.lang.Integer"> <column name="ID" /> <generator class="assigned" /> </id> <property name="name" type="java.lang.String"> <column name="NAME" /> </property> <property name="price" type="java.lang.Integer"> <column name="PRICE" /> </property> <property name="productDate" type="java.util.Date"> <column name="PRODUCT_DATE" /> </property> <joined-subclass name="vo.Student" table="STUDENT"> <key column="id" /> <property name="score" type="java.lang.Integer"> <column name="SCORE" /> </property> <property name="school" type="java.lang.String"> <column name="SCHOOL" /> </property> </joined-subclass> <joined-subclass name="vo.Maker" table="MAKER"> <key column="id" /> <property name="salary" type="java.lang.Integer"> <column name="SALARY" /> </property> <property name="company" type="java.lang.String"> <column name="COMPANY" /> </property> </joined-subclass>
※和table per concrete class的union-subclass很像,將union-subclass改成joined-class,然後將對應的key(也就是FK)寫出來即可,一定要放在第一行
測試類別
SessionFactory sf = HibernateUtil2.getSessionFactory();
Session s1 = sf.openSession();
Session s2 = sf.openSession();
Transaction tx1 = s1.beginTransaction();
Transaction tx2 = s2.beginTransaction();
try {
System.out.println("-----測試學生-----");
Student stu = new Student();
stu.setId(1);
stu.setName("象棋");
stu.setPrice(50);
stu.setProductDate(new Date(100, 0, 1));
stu.setScore(78);
stu.setSchool("家裡蹲大學");
s1.save(stu);
tx1.commit();
Student stuRtn = (Student) s1.get(Student.class, 1);
System.out.println("學校名:" + stuRtn.getSchool());
System.out.println("-----測試員工-----");
Maker mak = new Maker();
mak.setId(2);
mak.setName("五子棋");
mak.setPrice(30);
mak.setProductDate(new Date(102, 11, 12));
mak.setSalary(43000);
mak.setCompany("少林寺管委會");
s2.save(mak);
tx2.commit();
Maker makRtn = (Maker) s2.load(Maker.class, 2);
System.out.println("公司名:" + makRtn.getCompany());
} catch (Exception e) {
System.err.println("例外錯誤!");
e.printStackTrace();
tx1.rollback();
tx2.rollback();
} finally {
if (s1.isOpen()) {
s1.close();
}
if (s2.isOpen()) {
s2.close();
}
}
※hibernate.cfg.xml只要多一行<mapping resource="vo/Chess.hbm.xml" />
※catch裡的rollback如果寫在第一行,在commit之後有錯,會到catch,執行完rollback後會直接到finally,編譯居然沒問題,也就是catch後面的程式碼沒執行
如果load/get一個沒有記錄的資料會null或exception,然後null在「.」也是exception,這時因為rollback在第一行,所以錯在哪一行和訊息沒有印出來,只會出現「org.hibernate.TransactionException: Transaction not successfully started」,而且資料還新增成功,因為已經先commit,後面才出錯
修改成兩個表一次commit
Session s = HibernateUtil2.getSession();
Transaction tx = s.beginTransaction();
try {
System.out.println("-----測試學生-----");
Student stu = new Student();
stu.setId(1);
stu.setName("象棋");
stu.setPrice(50);
stu.setProductDate(new Date(100, 0, 1));
stu.setScore(78);
stu.setSchool("家裡蹲大學");
s.save(stu);
Student stuRtn = (Student) s.get(Student.class, 1);
System.out.println("學校名:" + stuRtn.getSchool());
System.out.println("-----測試員工-----");
Maker mak = new Maker();
mak.setId(2);
mak.setName("五子棋");
mak.setPrice(30);
mak.setProductDate(new Date(102, 11, 12));
mak.setSalary(43000);
mak.setCompany("少林寺管委會");
s.save(mak);
Maker makRtn = (Maker) s.load(Maker.class, 2);
System.out.println("公司名:" + makRtn.getCompany());
tx.commit();
} catch (Exception e) {
System.err.println("例外錯誤!");
e.printStackTrace();
tx.rollback();
tx.rollback();
} finally {
if (s.isOpen()) {
s.close();
}
}
※雖然解決了一次commit的問題,但尤於key是FK,所以Student和Maker的key不能重復,這是沒辦法的
※注意控制台出的select訊息是select xxx from Student student0_, CHESS student0_1_ ,所以是join,會有效能慢的問題
※Annotation設定
hibernate.cfg.xml
<mapping class="vo.Chess" /> <mapping class="vo.Student" /> <mapping class="vo.Maker" />
Chess.java
@Inheritance(strategy = InheritanceType.JOINED)
@Entity
@Table(name = "CHESS")
public abstract class Chess {
private Integer id;
private String name;
private Integer price;
private Date productDate;
@Id
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
@Column(name = "PRODUCT_DATE")
public Date getProductDate() {
return productDate;
}
public void setProductDate(Date productDate) {
this.productDate = productDate;
}
}
※@Id一定要打以外,其他@Column如和資料庫同名可不打,而productDate因不同,所以要打
Student.java
@Inheritance(strategy = InheritanceType.JOINED)
@Entity
public class Student extends Chess {
//...
}
※因為Column和資料庫全同名,所以只要設定class上頭的annotation
Maker.java
@Inheritance(strategy = InheritanceType.JOINED)
@Entity
public class Maker extends Chess {
//...
}
※因為Column和資料庫全同名,所以只要設定class上頭的annotation
※測試類一樣
沒有留言:
張貼留言