一对多的关系
在学生与班级对象模型中,通常多个学生实体对应一个班级,反过来,一个班级对应多个学生.
一对多的关系在数据库层面没有任何变动,还是两张表,学生表与班级表,学生表中有一个外键引用班级表的主键.
建立两张表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);
}
}
在学生与班级对象模型中,通常多个学生实体对应一个班级,反过来,一个班级对应多个学生.
一对多的关系在数据库层面没有任何变动,还是两张表,学生表与班级表,学生表中有一个外键引用班级表的主键.
建立两张表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);
}
}