hibernate入门三之关联映射(一对多和多对一)
提示;本文的操作是在入门一和二上面的
hibernate对映射类型
在开始是学习的时候,我以为一对多和多对一是同样的,后来发现不是这样,比如说班主任和班级里的学生,一个班级可能有多个学生,但是只有一个班主任,学生和班主任的关系是多对一,班主任和学生的关系是一对多,两者之间的区别在于它们的指向性
- 一对一(one-to-one )
- 一对多(ont-to-many)
- 多对一(many-to-one)
- 多对多(many-to-many)
一对多(ont-to-many)和多对一(many-to-one)最常见和做常用的映射类型
一对多(ont-to-many)
1、创建班级表和学生表,通过外键进行关联(
alter table Students add constraint fk_students_gid foreign key (gid) references grade(gid);
)
2、创建班级表和学生表的实体类(属性/默认构造器、带参构造器、get和set方法,toString方法)
private int gid;
private String gname;
private String gdesc;
// 在一方定义一个多方的集合
private Set<Students> students = new HashSet<Students>();
//其他。。。略 }
public class Students { private int sid; private String sname; private String gender; private Date birthday; //private String address; private Blob pictur; private Address address; //其他。。。略 }
3、创建Grade.hbm.xml(我的Stuendt.hbm.xml已经配置好了)
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.hibernate.entity.Grade" table="grade"> <id name="gid" column="gid" type="int"> <generator class="increment"></generator> </id> <property name="gname" type="java.lang.String"> <column name="gname"/> </property> <property name="gdesc" type="java.lang.String"> <column name="gdesc"/> </property> <!--单项的一对多的关系--> <set name="students" table="Students"> <!--指定的关联外键列--> <key column="gid"></key> <one-to-many class="com.hibernate.entity.Students"/> </set> </class> </hibernate-mapping>
4、在cfg.xml中配置映射文件路径
<!--指定映射文件的路径--> <mapping resource="com/hibernate/entity/Grade.hbm.xml"/> <mapping resource="com/hibernate/entity/Students.hbm.xml"/>
5、创建HibernateUtil类
public class HibernadUtil { private static SessionFactory sessionFactory; private static Session session; static { StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure().build(); sessionFactory = new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory(); } //获取SessionFacory public static SessionFactory getSessionFacory() { return sessionFactory; } //获取session public static Session getSession() { return sessionFactory.openSession(); } //关闭session public static void closeSession(Session session) { if (null != session) { session.close(); } }
6、进行测试
public class TestStudentsAndGrade { public static void main(String[] args) { //add(); //findStudensByGrade(); //update(); deleteStudentsBySid(); } //给表中插入数据 public static void add() { Grade grade = new Grade("道班", "道一"); Students s = new Students("道一", "男", new Date()); Students s2 = new Students("阴阳", "男", new Date()); Students s3 = new Students("三生", "女", new Date()); System.out.println(grade.getStudents().add(s)); //如果希望在学生表中添加对应道班级编号,需要在班级中添加学生,建立关联关系 grade.getStudents().add(s); grade.getStudents().add(s2); grade.getStudents().add(s3); Session session = HibernadUtil.getSession(); //开启事务 Transaction transaction = session.beginTransaction(); session.save(grade); session.save(s); session.save(s2); session.save(s3); transaction.commit(); HibernadUtil.closeSession(session); } //查询班级中包含的学生 public static void findStudensByGrade() { //获取session Session session = HibernadUtil.getSession(); //获取班级信息 Grade grade = session.get(Grade.class, 1); //输出班级信息 System.out.println(grade.getGname() + "," + grade.getGdesc()); //找出班级信息,然后找出班级学生信息 Set<Students> students = grade.getStudents(); for (Students stu:students ) { System.out.println(stu); } } //修改学生信息 public static void update(){ Grade grade =new Grade("道","道二"); Session session = HibernadUtil.getSession(); Transaction transaction = session.beginTransaction(); //修改学生所在班级信息(grade班级信息为自增长,别一不小心玩过头了) Students students = session.get(Students.class, 2); grade.getStudents().add(students); session.save(grade); transaction.commit(); HibernadUtil.closeSession(session); } //从班级中删除学生信息 public static void deleteStudentsBySid(){ Session session = HibernadUtil.getSession(); Transaction transaction = session.beginTransaction(); Students students = session.get(Students.class,9); session.delete(students); transaction.commit(); HibernadUtil.closeSession(session); } }
7、一对多中的set元素属性
多对一(many-to-one)
描述:多对一多关系和关系数据库中外键的参照关系最匹配,即在已方的表中的一个外键参考另一个表中的主键
实现:通过多方持有一方的引用实现,需要在“多”的一端使用<many-to-one>配置
1、在多方定义一个一方的引用,如(private Grade grade;)(属性/默认构造器、带参构造器、get和set方法,toString方法)
public class Students { private int sid; private String sname; private String gender; private Date birthday; //private String address; private Blob pictur; private Address address; private int gid; //在多方定义一个一方的引用 private Grade grade;
//其他。。。略
}
2、增加配置文件属性(如果有上一步的话,则需要修改相应的属性,删掉grade.hbm.xml中的set元素,在Stuent.hbm.xml中添加<many-to-one>属性)
友情提示:相比于one-to-many,many-to-one是直接写的,不用添加set属性
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.hibernate.entity.Students" table="Students"> <!--id表示表的主键--> <id name="sid" type="int"> <column name="SID"/> <!--表的生成策略--> <generator class="native"/> </id> <property name="sname" type="java.lang.String"> <column name="SNAME"/> </property> <property name="gender" type="java.lang.String"> <column name="GENDER"/> </property> <property name="birthday" type="time"> <column name="BIRTHDAY"/> </property> <property name="pictur" type="java.sql.Blob"> <column name="PICTUR"/> </property> <component name="address" class="com.hibernate.entity.Address" > <property name="postcode" column="POSTCODE" type="java.lang.String"/> <property name="phone" column="PHONE" type="java.lang.String"/> <property name="address" column="ADDRESS" type="java.lang.String"/> </component> <many-to-one name="grade" class="com.hibernate.entity.Grade" column="gid"></many-to-one> </class>
3、进行测试
public class TestStudent { public static void main(String[] args) { save(); } //添加学生和班级 public static void save() { Grade grade = new Grade("道班", "道一"); Students s = new Students("道一", "男", new Date()); Students s2 = new Students("阴阳", "男", new Date()); Students s3 = new Students("三生", "女", new Date()); //设置关系 s.setGrade(grade); s2.setGrade(grade); s3.setGrade(grade); Session session = HibernadUtil.getSession(); Transaction transaction = session.beginTransaction(); session.save(grade); session.save(s); session.save(s2); session.save(s3); //提交事务 transaction.commit(); //关闭事务 HibernadUtil.closeSession(session); } }
同时配置 一对多(ont-to-many)和多对一(many-to-one)的关系(双向关联关系,可以双向查询,非常方便)
通过配置两个对应的hbm.xml实现(实体类也需要相应的配置)
一对多
<set name="students" table="Students"> <!--指定的关联外键列--> <key column="gid"></key> <one-to-many class="com.hibernate.entity.Students"/> </set>
多对一
<many-to-one name="grade" class="com.hibernate.entity.Grade" column="gid"></many-to-one>
代码关系建立(关系建立之后,执行之后会多出update语句,对性能会有影响,所以需要通过inverse属性去掉这两句话)
//设置关系(双向关系) grade.getStudents().add(s); grade.getStudents().add(s2); grade.getStudents().add(s3); s.setGrade(grade); s2.setGrade(grade); s3.setGrade(grade);
inverse属性的用法
- <set>节点的inverse属性指定关联关系的控制方向,默认由one方来维护
- 关联关系中,inverse=“false”,则为主动方,由主动方负责维护关联关系
- 在一对多关联中,只能设置one方的inverse为“true”,这将有助于性能改善
<!--单项的一对多的关系,inverse设置为true,由多方维护关联关系,-->
<set name="students" table="Students" inverse="true">
<!--指定的关联外间列-->
<key column="gid"></key>
<one-to-many class="com.hibernate.entity.Students"/>
</set>
cascade属性(级联操作)
<!--单项的一对多的关系,inverse设置为true,由多方维护关联关系 当进行保存和更新时级联操作所关联的对象--> <set name="students" table="Students" inverse="true"> <!--指定的关联外间列--> <key column="gid"></key> <one-to-many class="com.hibernate.entity.Students"/> </set>
相比于之前,只需要写(session.save(grade)就可以了
session.save(grade);//级联操作,班级对学生
学生对班级的级联操作配置方案
<many-to-one name="grade" class="com.hibernate.entity.Grade" column="gid" cascade="all"></many-to-one>
代码端则为
session.save(s); session.save(s2); session.save(s3);
//级联操作,学生对班级
测试(查询学生所在班级信息)
public static void findGradeByStudent() { Session session = HibernadUtil.getSession(); //一定要注意你数据里的数据,是否有这个学生id,否则会报错 Students students = session.get(Students.class, 31); System.out.println(students.getSname()+","+students.getGender()+","+students.getBirthday()); Grade grade=students.getGrade(); System.out.println(grade.getGname()+","+grade.getGdesc()); HibernadUtil.closeSession(session); }