※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
※測試類一樣
沒有留言:
張貼留言