先要搞清楚什么是多对一。我们讲在班级-学生(高中时代,而不是大学时代)关系中,班级处于关系中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,因为它被依赖,所以无法直接删除,否则对应的操作会发生异常。