J2EE系列之Hibernate4学习笔记(四)--关联关系一对多映射

xiaoxiao2021-02-27  321

以班级学生为例进行一对多关联的学习。这里实现班级到学生的单向关联。

一、班级学生一对多映射实现(单向)

1.在上一个工程的基础上新建一个班级类:Class

package com.test.model; public class Class { private long id; private String name; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } 2.写Class类的映射文件:

<hibernate-mapping package="com.test.model"> <class name="Class" table="t_class"> <id name="id" column="classId"> <generator class="native"></generator> </id> <property name="name" column="className"></property> </class> </hibernate-mapping>

3.在多的一方学生类Student中,添加一个Class类对象代表学生所属的班级:

package com.test.model; public class Student { private long id; private String name; private Class c; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Class getC() { return c; } public void setC(Class c) { this.c = c; } @Override public String toString() { return "Student [id=" + id + ", name=" + name + "]"; } } 4.修改Student类的映射文件:

<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.test.model"> <class name="Student" table="t_student"> <id name="id" column="stuId"> <generator class="native"></generator> </id> <property name="name" column="stuName"></property> <many-to-one name="c" column="classId" class="com.test.model.Class"></many-to-one> </class> </hibernate-mapping> 学生对象相对于其内部的班级属性而言属于多对一,这里使用<many-to-one>标签来配置关联关系,设定Student中元素c在数据库中的列名为classId,其作为外键关联Class的主键。

5.新建测试类:StudentTest

package com.test.service; import org.hibernate.Session; import org.hibernate.SessionFactory; import com.test.model.Student; import com.test.util.HibernateUtil; public class StudentTest { public static void main(String[] args) { SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); // 获取Session工厂 Session session=sessionFactory.openSession(); // 生成一个session session.beginTransaction(); // 开启事务 session.getTransaction().commit(); // 提交事务 session.close(); // 关闭session } } 6.删除数据库中已经存在的t_student表,运行测试函数,看到数据库中生成了t_student和t_class两个表。两个表的架构为:

7.接下来保存数据,修改StudentTest类:

package com.test.service; import com.test.model.Class; import org.hibernate.Session; import org.hibernate.SessionFactory; import com.test.model.Student; import com.test.util.HibernateUtil; public class StudentTest { public static void main(String[] args) { SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); // 获取Session工厂 Session session=sessionFactory.openSession(); // 生成一个session session.beginTransaction(); // 开启事务 Class c = new Class(); c.setName("08数学"); session.save(c); Student s1 = new Student(); s1.setName("张三"); s1.setC(c); Student s2 = new Student(); s2.setName("李四"); s2.setC(c); session.save(s1); session.save(s2); session.getTransaction().commit(); // 提交事务 session.close(); // 关闭session } } 运行程序,发现数据添加成功。

二、Junit4方法详解

上面测试方法中的开启工厂、开启事物、提交、关闭session等代码每次写测试方法都要重写,重复性很高。使用Junit4可以解决这些代码重复写的问题。Junit中常用的方法有如下几个:

setUpBeforeClass() 类初始化前调用; tearDownAfterClass() 类初始化后调用; setUp() 在测试方法前调用; tearDown() 在测试方法后调用;

1.新建一个Junit Test Case类:

把这四个方法都选中。

package com.test.service; import static org.junit.Assert.*; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; public class StudentTest2 { @BeforeClass public static void setUpBeforeClass() throws Exception { System.out.println("类初始化之前调用"); } @AfterClass public static void tearDownAfterClass() throws Exception { System.out.println("类初始化之后调用"); } @Before public void setUp() throws Exception { System.out.println("类测试方法之前调用"); } @After public void tearDown() throws Exception { System.out.println("类测试方法之后调用"); } @Test public void test() { System.out.println("测试方法"); } } 运行test方法,控制台输出为:

通过这个示例可以看到这几个方法的调用顺序。

现在新建一个测试类,只选择测试方法前、后调用两个方法,完成上面添加数据的功能。如下:

package com.test.service; import static org.junit.Assert.*; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.test.model.Class; import com.test.model.Student; import com.test.util.HibernateUtil; public class StudentTest3 { private SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); // 获取Session工厂 private Session session; @Before public void setUp() throws Exception { session=sessionFactory.openSession(); // 生成一个session session.beginTransaction(); // 开启事务 } @After public void tearDown() throws Exception { session.getTransaction().commit(); // 提交事务 session.close(); // 关闭session } @Test public void testClassAndStudentSave() { Class c = new Class(); c.setName("08数学"); session.save(c); Student s1 = new Student(); s1.setName("张三"); s1.setC(c); Student s2 = new Student(); s2.setName("李四"); s2.setC(c); session.save(s1); session.save(s2); } }

三、级联保存更新

在测试类中新建一个方法:

@Test public void testClassAndStudentSaveWithCascade() { Class c = new Class(); c.setName("08数学"); Student s1 = new Student(); s1.setName("张三"); s1.setC(c); Student s2 = new Student(); s2.setName("李四"); s2.setC(c); session.save(s1); session.save(s2); } 与上一个测试方法不同的是,这里没有保存class对象。在hibernate中,新建的对象属于临时对象,经过session.save保存后的对象属于持久化对象,持久化对象保存是session缓存中。如图:

下面我们运行这个测试方法,提示错误如下:

错误提示我们Class对象未持久化。这样我们的student对象也保存失败。

现在我们提出一个新的需求,在持久化多的一端的时候,自动级联保存和更新一的一端,即使为一的一端没有持久化。这里就需要用到hibernate级联保存的知识。在<many-to-one>标签中有一个cascade属性,这个属性的值默认是none。如果想要使用级联保存的话,需要把这个属性的值改成save-update。

<hibernate-mapping package="com.test.model"> <class name="Student" table="t_student"> <id name="id" column="stuId"> <generator class="native"></generator> </id> <property name="name" column="stuName"></property> <many-to-one name="c" column="classId" class="com.test.model.Class" cascade="save-update"></many-to-one> </class> </hibernate-mapping> 重新运行程序,数据保存成功。此时class类对象数据也保存到了数据库中,实现了级联保存。

转载请注明原文地址: https://www.6miu.com/read-1775.html

最新回复(0)