双边关系是最常见的配置。在多方有一方的引用,一方也有多方的引用。双边关系能够很方便地查询数据。看一个班级与学生的双边关系。
班级(Clazz类)与学生(Student类):一对多关系。班级中有学生属性,学生中有班级属性,二者是双边关系。(Class是关键字,不能用)
分析:Clazz为一方,Student为多方。Clazz中有Student集合属性,Student中也有Clazz类型属性。
环境:MyEclipse10,新建Web Project名为hibernate
1、Clazz.java
Clazz类中有一个id主键、一个name属性、一个List<Student>集合代表该班级内的学生。班级与学生关系是一对多,这里使用@OneToMany配置,并用mappedBy属性配置与该List<Student>属性对应的是Student类中的clazz属性。具体的关联配置都在Student的clazz属性上。
双边关系中,控制权一般交给多方,因此这里的@OneToMany没有设置数据库的外键列,而只配置了一个mappedBy属性,值为clazz,告诉hibernate,配置信息要到Student类的clazz属性中找。
package com.hibernate.bean; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.MapKey; import javax.persistence.OneToMany; import javax.persistence.Table; import org.hibernate.annotations.Cascade; import org.hibernate.annotations.CascadeType; @Entity @Table(name = "tb_class") public class Clazz { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; private String name; @OneToMany(mappedBy = "clazz") @Cascade(value = CascadeType.DELETE_ORPHAN) private List<Student> students = new ArrayList<Student>(); // @OneToMany(mappedBy = "clazz") // @MapKey(name="name") // private Map<String, Student> students = new HashSet<String, Student>(); public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<Student> getStudents() { return students; } public void setStudents(List<Student> students) { this.students = students; } }
2、Student.java
Student类中有一个id主键以及name姓名、sex性别两个普通属性,还有一个Clazz类型的属性clazz,代表所在的班级。该属性与Clazz中的List<Student>集合属性是对应的。从逻辑上来讲,某student的clazz属性为某clazz,该clazz的List<Student>中必定还有改student。配置了mappedBy后,hibernate能自动维护这种关系。
Student与Clazz是多对一的关系,多对一使用@ManyToOne配置,另外用@JoinColumn配置关联的列名。这里用tb_student表的class_id列与tb_class的id主键列连接。这里同时配置了级联保存类型为PERSIST,创建student时,会自动将clazz也写进数据库。
package com.hibernate.bean; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; @Entity @Table(name = "tb_student") public class Student { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; @ManyToOne(fetch = FetchType.EAGER, cascade = { CascadeType.PERSIST }) @JoinColumn(name = "class_id") //外键为class_id private Clazz clazz; private String name; private String sex; public Clazz getClazz() { return clazz; } public void setClazz(Clazz clazz) { this.clazz = clazz; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } }
3、hibernate.cfg.xml(src目录下)
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="show_sql">true</property> <property name="format_sql">true</property> <property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property> <property name="connection.url">jdbc:oracle:thin:@192.168.1.2:1521:orcl</property> <property name="connection.username">daym2</property> <property name="connection.password">daym2</property> <property name="connection.isolation">2</property> <property name="hbm2ddl.auto">create</property> <property name="javax.persistence.validation.mode">none</property> <!-- SQL方言,这边设定的是Oracle --> <property name="dialect">org.hibernate.dialect.Oracle10gDialect</property> <property name="current_session_context">thread</property> <mapping class="com.hibernate.bean.Cat" /> <mapping class="com.hibernate.bean.Person" /> <mapping class="com.hibernate.bean.Email" /> <mapping class="com.hibernate.bean.Clazz" /> <mapping class="com.hibernate.bean.Student" /> </session-factory> </hibernate-configuration>
4、TestClazzStudent.java
package com.hibernate.bean; import java.util.List; import org.hibernate.Session; import com.hibernate.bean.Clazz; import com.hibernate.bean.Student; import com.hibernate.bean.HibernateSessionFactory; public class TestClazzStudent { @SuppressWarnings("all") public static void main(String[] args) throws Exception { Clazz clazz = new Clazz(); clazz.setName("三年二班"); Student student1 = new Student(); student1.setName("周周"); student1.setSex("男"); Student student2 = new Student(); student2.setName("李四"); student2.setSex("女"); Session session = HibernateSessionFactory.getSession(); session.beginTransaction(); // 保存进数据库 session.persist(clazz); session.persist(student1); session.persist(student2); // 设置班级 student1.setClazz(clazz); student2.setClazz(clazz); // clazz.getStudents().add(student1); // clazz.getStudents().add(student2); session.getTransaction().commit(); session.close(); session = HibernateSessionFactory.getSession(); session.beginTransaction(); // 查询名为“三年二班”的班级 然后输出学生 Clazz c = (Clazz) session.createQuery( " select c from Clazz c where c.name = :name ").setParameter( "name", "三年二班").uniqueResult(); System.out.println("三年二班 的所有学生:"); for (Student s : c.getStudents()) { System.out.println(" 姓名:" + s.getName() + ", 性别:" + s.getSex()); } // 直接查询班级为“三年二班”的学生 List<Student> students = session.createQuery( " select s from Student s where s.clazz.name = :name ") .setParameter("name", "三年二班").list(); System.out.println("三年二班 的所有学生:"); for (Student s : students) { System.out.println(" 姓名:" + s.getName() + ", 性别:" + s.getSex()); } session.getTransaction().commit(); session.close(); } }
5、log4j.properties (src目录下)
log4j.rootLogger=INFO,stdout log4j.category.org.hibernate.tool.hbn2ddl=DEBUG log4j.category.org.hibernate.SQL=DEBUG log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%c]-[%p] %m%n