先要搞清楚什麼是多對一。我們講在班級-學生(高中時代,而不是大學時代)關係中,班級處於關係中one的位置,因爲一個班級對應多個學生,所以學生處於many的位置。本篇文章也拿這個基本關係來做測試,看看在Hibernate中如何處理這種基本關係。
在此之前,我要聲明一個事情,千萬不要在數據庫中使用SQL的關鍵字或者保留字。無論是什麼數據庫都最好不要這樣做,因爲它會給你帶來無窮的麻煩,我親身體會了實體名爲order的痛苦。
好了,今天要操作的實體對象是grade(年級),屬性包括int gid,String gname,String gdesc;
student(學生),屬性包括int sid,String sname,String sex,Grade grade。
hbm.xml的配置文件不再說明。需要注意的是在單向多對一的關係中,需要在many的一端加上如下配置:
<many-to-one name="grade" class="edu.ctgu.hibernate.many2one.Grade">
<column name="GID" />
</many-to-one>
這樣在執行如下測試:
public class ManyToOneTest {
private SessionFactory factory = null;
private Session session = null;
private Transaction transaction = null;
@Before
public void testBefore(){
// 1.初始化配置文件加載配置信息,默認加載src目錄下的hibernate.cfg.xml文件
Configuration configuration = new Configuration().configure();
// 2.初始化SessionFactory
factory = configuration.buildSessionFactory();
// 3.打開Session
session = factory.openSession();
// 4.開啓事務
transaction = session.beginTransaction();
}
@After
public void testAfter(){
transaction.commit();
session.close();
factory.close();
}
@Test
public void test(){
}
}
後Hibernate會新建兩個表,併爲student增加一個外鍵,具體打印的SQL語句如下:
Hibernate:
create table GRADE (
GID integer not null auto_increment,
GNAME varchar(255),
GDESC varchar(255),
primary key (GID)
)
Hibernate:
create table STUDENT (
SID integer not null auto_increment,
SNAME varchar(255),
SEX varchar(255),
GID integer,
primary key (SID)
)
Hibernate:
alter table STUDENT
add constraint FKo3yntkpx77r18dsb45ak28no8
foreign key (GID)
references GRADE (GID)
好的,接下來討論在Hibernate中增刪查改需要注意的地方。
執行INSERT操作的save方法:
@Test
public void testSave(){
Grade grade = new Grade("高三", "即將參加人生最重要考試的人");
Student student = new Student("小明", "男");
Student student2 = new Student("小紅", "女");
student.setGrade(grade);
student2.setGrade(grade);
// 方式一:先插入one的一端,在插入many的一端
session.save(grade);
session.save(student);
session.save(student2);
// 方式二:先插入many的一端,在插入one的一端
/*session.save(student);
session.save(student2);
session.save(grade);*/
}
需要的注意的是在上面的方法中,方式一和方式二雖然處理完成的數據庫結果是一樣的,但是前者的效率比後者高。爲什麼呢?因爲many存在外鍵關聯one,可以說student依賴於grade。所以第一種方式只會產生三條insert語句。第二種方式則除了三條insert,還有兩條update語句。
執行SELECT操作的get方法:
@Test
public void testGet(){
Student student = session.get(Student.class, 1);
System.out.println(student.getSname());
// 實際需要的時候纔會執行對應的操作,得到的grade是代理對象
System.out.println(student.getGrade());
System.out.println(student.getGrade().getGdesc());
}
爲了提高查詢效率,Hibernate不會直接在查詢many的時候將one一起查詢出來,只有需要的時候纔會再次執行一次查詢語句。而且這裏需要注意的是得到的grade不是實際的對象而是一個代理對象。這樣的延遲加載也可能會出問題,如果中途Session被關閉,那麼就無法查詢到grade信息,出現懶加載異常。
執行UPDATE操作:
@Test
public void testUpdate(){
Student student = session.get(Student.class, 1);
student.setSname("小輝");
}
執行DELETE操作的delete方法:
@Test
public void testDelete(){
Student student = session.get(Student.class, 1);
session.delete(student);
}
這裏需要注意的是在manyToOne的關係中,一般不可以直接刪除one,也就是本例中的grade,因爲它被依賴,所以無法直接刪除,否則對應的操作會發生異常。