Hibernate的一个优势就是处理关联关系时比单纯使用JDBC更方便。
单向N-1关联如N个学生对应一个班主任,这时需要在学生(N的一方)表中添加所属的班主任的字段。因为从班主任表中并不清楚班主任带了哪些学生,所以是学生向班主任的单向关联。
POJO类
Student.java
注意通常在持久化类中将时间日期类型设置为java.util.Date
,而不是它的子类java.sql.Date
,然后在hbm映射文件中type="date"
即可,这个Hibernate映射类型是连接两种日期的桥梁。
package myPOJO;
import java.io.Serializable;
import java.util.Date;
//学生POJO类
public class Student implements Serializable {
private Integer id;// 逻辑主键
private String stuNo;// 学生学号
private String stuName;// 学生姓名
private Date dtIn;// 入学时间
private Teacher tchr;// 班主任,Techer对象的引用
// 无参构造器
public Student() {
}
// 有参构造器,不要提供逻辑主键
public Student(String stuNo, String stuName, Date dtIn, Teacher tchr) {
this.stuName = stuName;
this.stuNo = stuNo;
this.dtIn = dtIn;
this.tchr = tchr;
}
// getter和setter
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getStuNo() {
return stuNo;
}
public void setStuNo(String stuNo) {
this.stuNo = stuNo;
}
public Date getDtIn() {
return dtIn;
}
public void setDtIn(Date dtIn) {
this.dtIn = dtIn;
}
public Teacher getTchr() {
return tchr;
}
public void setTchr(Teacher tchr) {
this.tchr = tchr;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
}
Teacher.java
package myPOJO;
import java.io.Serializable;
//教师POJO类
public class Teacher implements Serializable {
private Integer id;// 逻辑主键
private String tchrNo;// 教师工号
private String tchrName;// 教师姓名
private Integer mny;// 月收入
// 无参构造器
public Teacher() {
}
// 有参构造器,不要提供逻辑主键
public Teacher(String tchrNo, String tchrName, Integer mny) {
this.tchrNo = tchrNo;
this.tchrName = tchrName;
this.mny = mny;
}
// getter和setter
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTchrNo() {
return tchrNo;
}
public void setTchrNo(String tchrNo) {
this.tchrNo = tchrNo;
}
public String getTchrName() {
return tchrName;
}
public void setTchrName(String tchrName) {
this.tchrName = tchrName;
}
public Integer getMny() {
return mny;
}
public void setMny(Integer mny) {
this.mny = mny;
}
}
映射文件
和对应的POJO类放在一个路径下。
Student.hbm.xml
在单向N-1关联中的N方的POJO类需要组合1方的引用,并且需要在N方的映射文件中使用<many-to-one>
标签配置N-1关联关系。
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--指出包名,也可以不指出而在后面使用包名.类名 -->
<hibernate-mapping package="myPOJO">
<!--指出类名(如果前面没有指出包名,这里需要包名.类名),映射到的数据库中的表名 -->
<class name="Student" table="StudentTable">
<!--主键的名称,对应于数据库表中的字段名,类型 -->
<id name="id" column="ID" type="int">
<!--主键生成器,指定生成策略,native则由Hibernate根据DBMS自选 -->
<generator class="native" />
</id>
<!--非主属性(学号):属性名,对应表中字段名,类型,是否非空 -->
<property name="stuNo" column="STUNO" type="string" not-null="true" />
<!--还可以这样写(姓名) -->
<property name="stuName" type="string" not-null="true">
<column name="STUNAME" />
</property>
<!--非主属性(入学时间):属性名,对应表中字段名,类型,是否非空 -->
<property name="dtIn" column="DATEIN" type="date" not-null="true" />
<!--N-1映射(班主任):属性名,对应表中字段名,所引用的类的类名 ,是否非空,级联策略-->
<many-to-one name="tchr" column="TEACHER_ID" class="Teacher" not-null="false" cascade="all"/>
</class>
</hibernate-mapping>
Teacher.hbm.xml
单向N-1映射中的1方不需要对该映射做任何改动和配置。
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--指出包名,也可以不指出而在后面使用包名.类名 -->
<hibernate-mapping package="myPOJO">
<!--指出类名(如果前面没有指出包名,这里需要包名.类名),映射到的数据库中的表名 -->
<class name="Teacher" table="TeacherTable">
<!--主键的名称,对应于数据库表中的字段名,类型 -->
<id name="id" column="ID" type="int">
<!--主键生成器,指定生成策略,native则由Hibernate根据DBMS自选 -->
<generator class="native" />
</id>
<!--非主属性(工号):属性名,对应表中字段名,类型,是否非空 -->
<property name="tchrNo" column="TCHRNO" type="string" not-null="true" />
<!--还可以这样写(姓名) -->
<property name="tchrName" type="string" not-null="true">
<column name="TCHRNAME" />
</property>
<!--非主属性(月收入):属性名,对应表中字段名,类型,是否非空 -->
<property name="mny" column="MONEY" type="int" not-null="false" />
<!--单向N-1映射中的1方不需要对该映射做任何改动和配置-->
</class>
</hibernate-mapping>
DAO类
通过数据访问类中的静态方法来对PO进行数据操作,更加OOP和方便。
StudentDAO.java
package myDAO;
import myPOJO.Student;
import myTools.HibernateUtils;
import org.hibernate.Session;
import org.hibernate.Transaction;
//Student类POJO的数据访问类,使用了Hibernate工具类
public class StudentDAO {
// 在数据库中添加一个Student
public static void addStudent(Student stu) {
// 获取Session对象
Session sssn = HibernateUtils.getSession();
// 开启事务
Transaction trnsctn = sssn.beginTransaction();
// 保存持久化对象
sssn.save(stu);
// 提交事务
trnsctn.commit();
// 关闭Session实例并且把ThreadLocal中的副本清除
HibernateUtils.closeSession();
}
// 其它操作...
}
TeacherDAO.java
package myDAO;
import myPOJO.Teacher;
import myTools.HibernateUtils;
import org.hibernate.Session;
import org.hibernate.Transaction;
//Teacher类POJO的数据访问类,使用了Hibernate工具类
public class TeacherDAO {
// 在数据库中添加一个Teacher
public static void addTeacher(Teacher tchr) {
// 获取Session对象
Session sssn = HibernateUtils.getSession();
// 开启事务
Transaction trnsctn = sssn.beginTransaction();
// 保存持久化对象
sssn.save(tchr);
// 提交事务
trnsctn.commit();
// 关闭Session实例并且把ThreadLocal中的副本清除
HibernateUtils.closeSession();
}
// 其它操作...
}
配置文件
key-value的配置文件没改,只在xml配置文件中更改了注册映射。
hibernate.cfg.xml
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<!-- Hibernate配置文件 -->
<!-- 为了方便,在这里只做了注册映射文件的事情 -->
<!-- 另外的一些配置以key=value的形式写在hibernate.properties里 -->
<hibernate-configuration>
<session-factory>
<!-- 注册Student类的ORM映射文件 -->
<mapping resource="myPOJO/Student.hbm.xml" />
<!-- 注册Teacher类的ORM映射文件 -->
<mapping resource="myPOJO/Teacher.hbm.xml" />
</session-factory>
</hibernate-configuration>
主类
import java.util.Date;
import myDAO.StudentDAO;
import myDAO.TeacherDAO;
import myPOJO.Student;
import myPOJO.Teacher;
//测试学生到班主任的N-1关系映射
public class Main {
// 主方法
public static void main(String[] args) {
// 添加一个老师
System.out.println("----添加一个老师作为班主任----");
Teacher tchr = new Teacher("T0001", "大司马", 500);
TeacherDAO.addTeacher(tchr);
// 添加两个该老师的学生,学生对老师是单向N-1关系
System.out.println("----为该老师添加两个学生----");
Student stu1 = new Student("S0001", "刘知昊", new Date(), tchr);
StudentDAO.addStudent(stu1);
Student stu2 = new Student("S0002", "刘傻逼", new Date(), tchr);
StudentDAO.addStudent(stu2);
System.out.println("----操作已经全部执行完,可以查看数据库了----");
}
}
运行结果
控制台输出
----添加一个老师作为班主任----
Hibernate: insert into TeacherTable (TCHRNO, TCHRNAME, MONEY) values (?, ?, ?)
----为该老师添加两个学生----
Hibernate: insert into StudentTable (STUNO, STUNAME, DATEIN, TEACHER_ID) values (?, ?, ?, ?)
Hibernate: update TeacherTable set TCHRNO=?, TCHRNAME=?, MONEY=? where ID=?
Hibernate: insert into StudentTable (STUNO, STUNAME, DATEIN, TEACHER_ID) values (?, ?, ?, ?)
Hibernate: update TeacherTable set TCHRNO=?, TCHRNAME=?, MONEY=? where ID=?
----操作已经全部执行完,可以查看数据库了----
查看数据库
尝试删除
删除Teacher表中受Student表使用的行时,会被禁止。