l 一对多的关系
在学生与班级对象模型中,通常多个学生实体对应一个班级,反过来,一个班级对应多个学生.
一对多的关系在数据库层面没有任何变动,还是两张表,学生表与班级表,学生表中有一个外键引用班级表的主键.
建立两张表students, myClass
students
CREATE TABLE `students` ( `id` varchar(32) NOT NULL, `name` varchar(20) default NULL, `age` int(11) default NULL, `birthday` date default NULL, `class_id` varchar(32) default NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
myClass
CREATE TABLE `myclass` ( `id` varchar(32) NOT NULL default '', `name` varchar(20) default NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
Model: Student
public class Student { private String id; private Myclass myclass; private String name; private Integer age; private Date birthday;
public Student() { }
public Student(Myclass myclass, String name, Integer age, Date birthday) { this.myclass = myclass; this.name = name; this.age = age; this.birthday = birthday; }
public String getId() { return this.id; }
public void setId(String id) { this.id = id; }
public Myclass getMyclass() { return this.myclass; }
public void setMyclass(Myclass myclass) { this.myclass = myclass; }
public String getName() { return this.name; }
public void setName(String name) { this.name = name; }
public Integer getAge() { return this.age; }
public void setAge(Integer age) { this.age = age; }
public Date getBirthday() { return this.birthday; }
public void setBirthday(Date birthday) { this.birthday = birthday; } } |
Student.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="chapter2.model.Students" table="students"> <id name="id" type="java.lang.String" column="id"> <generator class="uuid.hex" /> </id> <property name="name" type="java.lang.String" column="name" /> <property name="age" type="java.lang.Integer" column="age" /> <property name="birthday" type="java.util.Date" column="birthday" /> <many-to-one name="myclass" class="chapter2.model.Myclass" column="class_id" /> </class> </hibernate-mapping> |
可以看到学生这一块和昨天讲的内容没有任何区别.唯一要变动的是班级这一块,一个班级中有多个学生,那么我们应该很自然的想到班级类中应该有一个集合类,能够容纳该班级所有的学生, 我们先看一下班级Model类的变动:
public class Myclass { private String id; private String name; // 看到这里,这里运用了一个set集合(set集合的特点:不能够存放相同的元素),这个集合能够容纳该班级下所有的学生. private Set<Student> students = new HashSet<Student>();
public Myclass() { }
public Myclass(String name) { this.name = name; }
public String getId() { return this.id; }
public void setId(String id) { this.id = id; }
public String getName() { return this.name; }
public void setName(String name) { this.name = name; }
public Set<Student> getStudents() { return students; }
public void setStudents(Set<Student> students) { this.students = students; } } |
那么接下来,我们在配置文件中应该怎么配置呢?因为我们要让这个集合能够找到该班级下所有的学生类.
Myclass.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="chapter2.model.Myclass" table="myclass"> <id name="id" type="java.lang.String"> <column name="id" length="32" /> <generator class="uuid.hex"></generator> </id> <property name="name" type="java.lang.String"> <column name="name" length="20" /> </property> <set name="students"> <key column="class_id" /> <one-to-many class="chapter2.model.Student" /> </set> </class> </hibernate-mapping> |
主要是这里:
<set name="studentses">
<key column="class_id" />
<one-to-many class="chapter2.model.Student" />
</set>
name属性指定班级类中集合的属性名, key标签的column属性要对应数据库中学生表中外键字段,因为Hibernate查询的时候要知道用自己的主键去匹配学生表中的哪个字段. one-to-many告诉set集合应该装什么类型的对象,也告诉了Hibernate应该查哪张表.
Dao层:
MyclassDao
public class MyclassDao { public void create(Myclass myclass){ Session session = null; try{ session = HibernateUtil.getSession(); session.beginTransaction(); session.save(myclass); session.getTransaction().commit(); }catch(RuntimeException re){ session.getTransaction().rollback(); throw re; } }
public Myclass findById(Serializable s){ Session session = null; Myclass myclass = null; try{ session = HibernateUtil.getSession(); session.beginTransaction(); myclass = (Myclass) session.get(Myclass.class, s); session.getTransaction().commit(); }catch(RuntimeException re){ session.getTransaction().rollback(); throw re; } return myclass; } } |
StudentDao
public class StudentDao { public void create(Student student) { Session session = null; try { session = HibernateUtil.getSession(); session.beginTransaction(); session.save(student); session.getTransaction().commit(); } catch (RuntimeException re) { session.getTransaction().rollback(); throw re; } } } |
测试类:
先运行方法向数据库中添加数据
public class Test { public static void main(String[] args) { StudentDao studentDao = new StudentDao(); MyclassDao myclassDao = new MyclassDao();
Myclass myclass = new Myclass("java0801"); Student student1 = new Student(myclass, "张三", 25, new Date()); Student student2 = new Student(myclass, "李四", 25, new Date()); Student student3 = new Student(myclass, "王五", 25, new Date()); Student student4 = new Student(myclass, "赵六", 25, new Date()); Student student5 = new Student(myclass, "林七", 25, new Date()); Student student6 = new Student(myclass, "魏八", 25, new Date()); myclassDao.create(myclass); studentDao.create(student1); studentDao.create(student2); studentDao.create(student3); studentDao.create(student4); studentDao.create(student5); studentDao.create(student6); } } |
接下来,我们测试一下,看能否通过班级找到所有的学生
public class Test { public static void main(String[] args) { StudentDao studentDao = new StudentDao(); MyclassDao myclassDao = new MyclassDao();
Myclass myclass = myclassDao.findById("4028810027959bbc0127959bbd2f0001"); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } Set<Student> students = myclass.getStudents(); for(Student s : students){ System.out.println(s.getName()); } } } |
加入休眠, 是为了让大家看到一个延时提取的一个过程, 大家可以看下面
<set name="students" lazy="false">
<key column="class_id" />
<one-to-many class="chapter2.model.Student" />
</set>
将set标签这里加了一个属性lazy="false",再运行上面的程序,看一下是什么效果
我们上面的示例是在创建学生的时候,告诉学生你属于哪个班级, 有时候会有新来的员工等待分配的情况,那这种情况怎么模拟呢?
public class Test { public static void main(String[] args) { StudentDao studentDao = new StudentDao(); MyclassDao myclassDao = new MyclassDao();
//这里模拟新来的学生 Student student1 = new Student("胶卷", 25, new Date()); Student student2 = new Student("腾迅", 25, new Date()); Student student3 = new Student("网易", 25, new Date()); Student student4 = new Student("淘宝", 25, new Date()); Student student5 = new Student("百度", 25, new Date()); Student student6 = new Student("谷歌", 25, new Date()); //新学生入库 studentDao.create(student1); studentDao.create(student2); studentDao.create(student3); studentDao.create(student4); studentDao.create(student5); studentDao.create(student6);
try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); }
//学生打包 Set<Student> students = new HashSet<Student>(); students.add(student1); students.add(student2); students.add(student3); students.add(student4); students.add(student5); students.add(student6); //分配班级 Myclass myclass = myclassDao.findById("4028810027959bbc0127959bbd2f0001"); myclass.setStudents(students); //更新班级 myclassDao.update(myclass); } } |
加入延时,是为了让大家看到这里,刚加入学生时,学生的外键是空的.
如果这样做,会将以前存在的数据中的外键更新为空.进一步证明了持久对象的特点, 在事务开始与结束之间,对象的任何变化都会在数据库中体现出来.
为了避免这种情况发生,我们可以更改为下面的代码:
public class Test { public static void main(String[] args) { StudentDao studentDao = new StudentDao(); MyclassDao myclassDao = new MyclassDao();
//这里模拟新来的学生 Student student1 = new Student("胶卷", 25, new Date()); Student student2 = new Student("腾迅", 25, new Date()); Student student3 = new Student("网易", 25, new Date()); Student student4 = new Student("淘宝", 25, new Date()); Student student5 = new Student("百度", 25, new Date()); Student student6 = new Student("谷歌", 25, new Date()); //新学生入库 studentDao.create(student1); studentDao.create(student2); studentDao.create(student3); studentDao.create(student4); studentDao.create(student5); studentDao.create(student6);
try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); }
//分配班级 Myclass myclass = myclassDao.findById("4028810027959bbc0127959bbd2f0001"); //为了避免将原来学生的信息更新为空 Set<Student> students = myclass.getStudents(); students.add(student1); students.add(student2); students.add(student3); students.add(student4); students.add(student5); students.add(student6);
//更新班级 myclassDao.update(myclass); } } |