一、一对多
Dempartment { private int id; private String name; private Set<Employee> employees = new HashSet<Employee>(); }
Employee { private int id; private String name; private Dempartment department; }
---Employee.hbm.xml <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="pde.ams.onetomany"> <class name="Employee" table="employee"> <id name="id"> <generator class="native" /> </id> <property name="name"></property> <many-to-one name="department" column="departmentId" class="Dempartment"></many-to-one> </class> </hibernate-mapping>
---Dempartment.hbm.xml <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="pde.ams.onetomany"> <class name="Dempartment" table="dempartment"> <id name="id"> <generator class="native" /> </id> <property name="name"></property> <!-- employees属性 是Employees对象 Dempartment与Employees的一对多的关系 --> <set name="employees"> <key column="departmentId"></key> <one-to-many class="Employee"/> </set> </class> </hibernate-mapping>
package pde.ams.onetomany; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.junit.Test; /** * @author 作者 macx: * @version 创建时间:2018年4月29日 下午1:40:06 类说明 */ public class App { private static SessionFactory sessionFactory = new Configuration()// .configure()// .addClass(Dempartment.class)// 加载指定类对应的映射文件(以类名为前缀,后缀为.hbm.xml的同一个包下的文件) .addClass(Employee.class)// 加载指定类对应的映射文件(以类名为前缀,后缀为.hbm.xml的同一个包下的文件) .buildSessionFactory(); @Test public void saveUser() { Session session = sessionFactory.openSession(); session.beginTransaction(); // --------------------------------------- // 创建对象 Dempartment department = new Dempartment(); department.setName("开发部1"); Employee employee1 = new Employee(); employee1.setName("张三"); Employee employee2 = new Employee(); employee2.setName("李四"); // 关联起来 employee1.setDepartment(department); employee2.setDepartment(department); department.getEmployees().add(employee1); department.getEmployees().add(employee2); // 保存 session.save(department); // 保存部门 session.save(employee1); session.save(employee2); // --------------------------------------- session.getTransaction().commit(); session.close(); } @Test public void getUser() { Session session = sessionFactory.openSession(); session.beginTransaction(); // --------------------------------------- // 获取部门,并显示关联的员工信息 Dempartment department = (Dempartment) session.get(Dempartment.class, 29); System.out.println("部门名称:" + department.getName()); System.out.println("关联的员工:" + department.getEmployees()); // // 获取员工,并显示关联的部门信息 Employee employee = (Employee) session.get(Employee.class, 1); System.out.println("员工姓名:" + employee.getName()); System.out.println("所属的部门:" + employee.getDepartment()); // --------------------------------------- session.getTransaction().commit(); session.close(); } // 移除关联关系 @Test public void testRemoveRelation() throws Exception { Session session = sessionFactory.openSession(); session.beginTransaction(); // --------------------------------------- // // 让员工不再属于原部门 // Employee employee = (Employee) session.get(Employee.class, 1); // employee.setDepartment(null); // 让Department不与任何Employee关联 Dempartment department = (Dempartment) session.get(Dempartment.class, 26); department.getEmployees().clear(); // --------------------------------------- session.getTransaction().commit(); session.close(); } // 删除(测试对关联对象的影响) @Test public void testDelete() throws Exception { Session session = sessionFactory.openSession(); session.beginTransaction(); // --------------------------------------- // // 删除员工,对关联的部门没有影响 // Employee employee = (Employee) session.get(Employee.class, 1); // session.delete(employee); // // 删除部门,如果有关联的员工,则会: // 1,inverse="false",这也是默认值,表示本方能维护关联关系(外键),这时会先把所有关联的员工都移除关系,再删除自己。 // 2,inverse="true",表示本方不能维护关联关系(外键),就会直接删除自己,这时会抛异常。 Dempartment department = (Dempartment) session.get(Dempartment.class, 2); session.delete(department); // --------------------------------------- session.getTransaction().commit(); session.close(); } }
二、多对多
public class Student { private int id; private String name; private Set<Teacher> teacherSet = new HashSet<Teacher>(); }
public class Teacher { private int id; private String name; private Set<Student> studentSet = new HashSet<Student>(); }
package pde.ams.manytomany; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.junit.Test; /** * @author 作者 macx: * @version 创建时间:2018年4月29日 下午1:40:06 类说明 */ public class App { private static SessionFactory sessionFactory = new Configuration()// .configure()// .addClass(Teacher.class)// 加载指定类对应的映射文件(以类名为前缀,后缀为.hbm.xml的同一个包下的文件) .addClass(Student.class)// 加载指定类对应的映射文件(以类名为前缀,后缀为.hbm.xml的同一个包下的文件) .buildSessionFactory(); @Test public void saveUser() { Session session = sessionFactory.openSession(); session.beginTransaction(); // --------------------------------------- // 创建对象 Teacher teacher1 = new Teacher(); teacher1.setName("赵老师"); Teacher teacher2 = new Teacher(); teacher2.setName("冯老师"); Student student1 = new Student(); student1.setName("张三"); Student student2 = new Student(); student2.setName("李四"); // 关联起来 teacher1.getStudentSet().add(student1); teacher1.getStudentSet().add(student2); teacher2.getStudentSet().add(student1); teacher2.getStudentSet().add(student2); student1.getTeacherSet().add(teacher1); student1.getTeacherSet().add(teacher2); student2.getTeacherSet().add(teacher1); student2.getTeacherSet().add(teacher2); // 保存 session.save(teacher1); session.save(teacher2); session.save(student1); session.save(student2); // --------------------------------------- session.getTransaction().commit(); session.close(); } @Test public void getUser() { Session session = sessionFactory.openSession(); session.beginTransaction(); // --------------------------------------- // 获取一个Student,并显示相关的Teacher信息 Student student = (Student) session.get(Student.class, 3); System.out.println("学生的姓名:" + student.getName()); System.out.println("此学生的老师:" + student.getTeacherSet()); // --------------------------------------- session.getTransaction().commit(); session.close(); } // 移除关联关系 @Test public void testRemoveRelation() throws Exception { Session session = sessionFactory.openSession(); session.beginTransaction(); // --------------------------------------- // 获取一个Student,并移除与所有老师的关联 Student student = (Student) session.get(Student.class, 5); student.getTeacherSet().clear(); // Teacher teacher = (Teacher) session.get(Teacher.class, 5); // teacher.getStudentSet().clear(); // --------------------------------------- session.getTransaction().commit(); session.close(); } // 删除(测试对关联对象的影响) @Test public void testDelete() throws Exception { Session session = sessionFactory.openSession(); session.beginTransaction(); // --------------------------------------- // 删除一个Student,如果有关联的老师,则: // 如果inverse="false",表示可以维护关联关系,这时会先删除关系,再删除自己。 // 如果inverse="true",表示不可以维护关联关系,这时会直接删除自己,会有异常。 Student student = (Student) session.get(Student.class, 5); session.delete(student); // --------------------------------------- session.getTransaction().commit(); session.close(); } }
三、级联 cascade
1、概念
当hibernate持久化一个临时对象时,在默认情况下,他不会自动持久化所关联的其他临时对象,而是会抛出TransientObjectException.如果设定many-to-one元素的cascade属性为save-update的话,可实现自动持久化所关联的对象。
级联指的是当主控方执行操作时,关联对象(被动方)是否同步执行同一操作。
2、级联风格
每个 Hibernate session 的基本操作 — 包括 persist(), merge(), saveOrUpdate(), delete(),lock(), refresh(),evict(), replicate() — 都有对应的级联风格(cascade style)。这些级联风格(cascade style)风格分别命名为persist, merge, save-update,delete, lock, refresh, evict, replicate。
级联风格 |
Session中的方法 |
persist |
persist() |
merge |
merge() |
save-update |
save()、update()、saveOrUpdate() |
delete |
delete() |
lock |
lock() |
refresh |
refresh() |
evict |
evict() |
replicate |
replicate() |
如果你希望一个操作被顺着关联关系级联传播,你必须在映射文件中指出这一点。
指定级联风格:
<one-to-one name="person" cascade="persist"/>
级联风格(cascadestyle)是可组合的:
<one-to-one name="person" cascade="persist,delete"/>
你可以使用 cascade="all" 来指定全部操作都顺着关联关系级联(cascaded)。默认值是cascade="none",即任何操作都不会被级联(cascaded)。
delete-orphan
A special cascade style, delete-orphan, applies only toone-to-many associations, and indicates that the delete() operation should beapplied to any child object that is removed from the association.
在对象–关系映射文件中, 用于映射持久化类之间关联关系的元素, 如<set>,<many-to-one> 和 <one-to-one> 都有一个 cascade属性。
四、一对一public class Person { private int id; private String name; private IdCard idCard; }
public class IdCard { private int id; private String number; private Person person; }
---IdCard.hbm.xml <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="pde.ams.onetoone"> <class name="IdCard" table="idCard"> <id name="id"> <generator class="native" /> </id> <property name="number"></property> <!-- person属性,表达IdCard与Person的一对一。 采用基于外键的一对一映射方式。 有外键方,就是多对一加上惟一性约束。 --> <many-to-one name="person" class="Person" column="personId" unique="true" cascade="save-update,delete"></many-to-one> </class> </hibernate-mapping>
---Person.hbm.xml <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="pde.ams.onetoone"> <class name="Person" table="person"> <id name="id"> <generator class="native" /> </id> <property name="name"></property> <!-- idCard属性,表达的是Person与IdCard的一对一。 采用基于外键的一对一映射方式。 无外键方,使用one-to-one,property-ref写的是对方映射中表达此一对一的属性 --> <one-to-one name="idCard" class="IdCard" property-ref="person" cascade="delete"></one-to-one> </class> </hibernate-mapping>
public class App { private static SessionFactory sessionFactory = new Configuration()// .configure()// .addClass(Person.class)// 加载指定类对应的映射文件(以类名为前缀,后缀为.hbm.xml的同一个包下的文件) .addClass(IdCard.class)// 加载指定类对应的映射文件(以类名为前缀,后缀为.hbm.xml的同一个包下的文件) .buildSessionFactory(); @Test public void saveUser() { Session session = sessionFactory.openSession(); session.beginTransaction(); // --------------------------------------- Person p = new Person(); p.setName("张三"); IdCard idcard = new IdCard(); idcard.setNumber("12345678"); // 关联起来 // 使用基于外键的一对一时:Person是无外键方,不可以维护关联关系 // 使用基于外键的一对一时:IdCard是有外键方,可以维护关联关系 // 使用基于主键的一对一时:也是只有有外键方可以保存关联关系 p.setIdCard(idcard); idcard.setPerson(p); // 保存 // session.save(p); session.save(idcard); // --------------------------------------- session.getTransaction().commit(); session.close(); } @Test public void getUser() { Session session = sessionFactory.openSession(); session.beginTransaction(); // --------------------------------------- Person person = (Person) session.get(Person.class, 1); IdCard id = (IdCard) session.get(IdCard.class, 1); System.out.println(id); System.out.println(id.getNumber()); System.out.println(id.getPerson().getName()); // --------------------------------------- session.getTransaction().commit(); session.close(); } // 移除关联关系 @Test public void testRemoveRelation() throws Exception { Session session = sessionFactory.openSession(); session.beginTransaction(); // --------------------------------------- IdCard id = (IdCard) session.get(IdCard.class, 1); id.setPerson(null); session.save(id); // --------------------------------------- session.getTransaction().commit(); session.close(); } // 删除(测试对关联对象的影响) @Test public void testDelete() throws Exception { Session session = sessionFactory.openSession(); session.beginTransaction(); // --------------------------------------- // IdCard id = (IdCard) session.get(IdCard.class, 1); // session.delete(id); Person p = (Person) session.get(Person.class, 2); session.delete(p); // --------------------------------------- session.getTransaction().commit(); session.close(); }
五、继承关系映射
1、映射一(同一表中)
public class Article { private Integer id; private String title; private String content; }
public class Reply extends Article{ private int floor; // 楼层 }
public class Topic extends Article { private int type; // 主题类型,比如精华帖、置顶帖等等 }
---Article.hbm.xml <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="pde.ams.extend_1"> <!-- 继承结构映射:整个继承结构一张表 discriminator-value属性:指定哪个值表示当前类型 --> <class name="Article" table="article" discriminator-value="Article"> <id name="id"> <generator class="native"></generator> </id> <!-- 指定一个用于鉴别是什么类型的列 --> <discriminator column="_class" type="string"></discriminator> <property name="title"></property> <property name="content" type="text" length="5000"></property> <!-- 子类:Topic --> <subclass name="Topic" discriminator-value="Topic"> <property name="type"></property> </subclass> <!-- 子类:Reply --> <subclass name="Reply" discriminator-value="Reply"> <property name="floor"></property> </subclass> </class> </hibernate-mapping>
2、映射二(三个不同表)
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="pde.ams.extend_2"> <!-- 继承结构映射:每个类一张表,抽象也对应表。 每个类的映射中都要写表名。 子类映射中要指定一个外键列<key column="id"></key> --> <class name="Article" table="article"> <id name="id"> <generator class="native"></generator> </id> <property name="title"></property> <property name="content" type="text" length="5000"></property> <!-- 子类:Topic --> <joined-subclass name="Topic" table="topic"> <key column="id"></key> <property name="type"></property> </joined-subclass> <!-- 子类:Reply --> <joined-subclass name="Reply" table="reply"> <key column="id"></key> <property name="floor"></property> </joined-subclass> </class> </hibernate-mapping>
3、映射三
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="pde.ams.extend_3"> <!-- 继承结构映射:每个具体类一张表,抽象不对应表。 如果类是抽象的,就要写上abstract="true",这样就不会创建表了,也不需要table属性了。 这时不能使用identity主键生成策略,因为继承结构映射要求在整个继承结构中,所有数据的主键值不能重复。 --> <class name="Article" table="article"> <id name="id"> <!-- increment策略,由Hibernate维护的主键增长 --> <generator class="increment"></generator> </id> <property name="title"></property> <property name="content" type="text" length="5000"></property> <!-- 子类:Topic --> <union-subclass name="Topic" table="topic"> <property name="type"></property> </union-subclass> <!-- 子类:Reply --> <union-subclass name="Reply" table="reply"> <property name="floor"></property> </union-subclass> </class> </hibernate-mapping>