一、单向一对多()
- 案例一(用XML文件配置): 一个班级有多个学生,班级可以查看所有学生的信息。
- ClassBean.java
package bean; import java.util.HashSet; import java.util.Set; /** * ClassBean entity. @author MyEclipse Persistence Tools */ public class ClassBean implements java.io.Serializable { // Fields private Integer classid; private String classname; private Set<StudentBean> stuSet=new HashSet<StudentBean>(); // Constructors /** default constructor */ public ClassBean() { } /** minimal constructor */ public ClassBean(Integer classid) { this.classid = classid; } /** full constructor */ public ClassBean(Integer classid, String classname) { this.classid = classid; this.classname = classname; } // Property accessors public Integer getClassid() { return this.classid; } public void setClassid(Integer classid) { this.classid = classid; } public String getClassname() { return this.classname; } public void setClassname(String classname) { this.classname = classname; } public Set<StudentBean> getStuSet() { return stuSet; } public void setStuSet(Set<StudentBean> stuSet) { this.stuSet = stuSet; } }
StudentBean.java
package bean; /** * StudentBean entity. @author MyEclipse Persistence Tools */ public class StudentBean implements java.io.Serializable { // Fields private Integer stuid; private String stuname; private Integer classId; // Constructors /** default constructor */ public StudentBean() { } /** minimal constructor */ public StudentBean(Integer stuid) { this.stuid = stuid; } /** full constructor */ public StudentBean(Integer stuid, String stuname, Integer classId) { this.stuid = stuid; this.stuname = stuname; this.classId = classId; } // Property accessors public Integer getStuid() { return this.stuid; } public void setStuid(Integer stuid) { this.stuid = stuid; } public String getStuname() { return this.stuname; } public void setStuname(String stuname) { this.stuname = stuname; } public Integer getClassId() { return this.classId; } public void setClassId(Integer classId) { this.classId = classId; } }
- 单向一对多的映射文件 :
ClassBean.hbm.xml
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <!-- Mapping file autogenerated by MyEclipse Persistence Tools --> <hibernate-mapping> <class name="bean.ClassBean" table="t_class" catalog="test"> <id name="classid" type="java.lang.Integer"> <column name="classid" /> <generator class="assigned"></generator> </id> <property name="classname" type="java.lang.String"> <column name="classname" /> </property> <!--set元素,就是定义一个集合,它的name属性值是对应的POJO中的相关属性名称--> <set name="stuSet" cascade="all"> <key column="class_id"></key> <!--指定“多”的一段的外键,与“一”端得主键相关联,这里的column=“class_id”是指数据库中的字段,而非bean中的属性,注意这里不会自动生成 class_id属性,所以在bean.StudentBean类中要有一个外键的映射属性--> <one-to-many class="bean.StudentBean"/> <!--指定了“多”端对应的类--> </set> </class> </hibernate-mapping>
- StudentBean.hbml.xml
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <!-- Mapping file autogenerated by MyEclipse Persistence Tools --> <hibernate-mapping> <class name="bean.StudentBean" table="t_student" catalog="test"> <id name="stuid" type="java.lang.Integer"> <column name="stuid" /> <generator class="assigned"></generator> </id> <property name="stuname" type="java.lang.String"> <column name="stuname" /> </property> <property name="classId" type="java.lang.Integer"> <column name="class_id" /> </property> </class> </hibernate-mapping>
- 测试类
package action; import java.util.Set; import org.hibernate.Session; import org.hibernate.Transaction; import bean.ClassBean; import bean.StudentBean; import util.HibernateUtil; /** * 本类测试一对多的操作 * @author 半颗柠檬、 * */ public class Test_ManytoOne { public static void main(String[] args) { // Test_ManytoOne.save(); // Test_ManytoOne.select(); Test_ManytoOne.delete(); } public static void save(){ Session session = null; Transaction tran = null; try { session = HibernateUtil.getSessionFactory().getCurrentSession(); tran=session.beginTransaction(); ClassBean class1=new ClassBean(); class1.setClassid(1); class1.setClassname("精英班"); StudentBean stu1=new StudentBean(); stu1.setClassId(class1.getClassid()); stu1.setStuid(1); stu1.setStuname("学生1"); StudentBean stu2=new StudentBean(); stu2.setStuid(2); stu2.setStuname("学生2"); stu2.setClassId(class1.getClassid()); session.save(class1); session.save(stu1); session.save(stu2); tran.commit(); } catch (Exception e) { e.printStackTrace(); tran.rollback(); } } /** * 测试“一”方能够读取“多”方的信息 */ private static void select() { Session session = null; Transaction tran = null; try { session = HibernateUtil.getSessionFactory().getCurrentSession(); tran=session.beginTransaction(); /** * 由“一”方得知“多”方信息 */ ClassBean cla=(ClassBean)session.get(ClassBean.class, new Integer(1)); Set<StudentBean> stuSet=cla.getStuSet(); for(StudentBean stu:stuSet){ System.out.println(stu.getStuname()); System.out.println(stu.getClassId()); System.out.println(stu.getStuid()); } tran.commit(); } catch (Exception e) { e.printStackTrace(); tran.rollback(); } } /** * 删除One一方时,默认不会级联删除Many的一方。 * * 如果要级联删除:,一般使用代码手动级联更新 * * A:使用代码来控制级联删除。也是推荐使用的方式,手动进行级联删除, * * B:配置级联关系,让Hibernate自动执行。 * * 在关联关系中配置cascade属性。 * * @OneToMany(cascade = { CascadeType.REMOVE, CascadeType.MERGE }) * */ private static void delete() { Session session = null; Transaction tx = null; try { session = HibernateUtil.getSession(); tx = session.beginTransaction(); /** * B 在关联关系中配置cascade属性之后 */ ClassBean class1 = (ClassBean) session.get(ClassBean.class, new Integer(1)); session.delete(class1); tx.commit(); } catch (Exception e) { e.printStackTrace(); tx.rollback(); } finally { HibernateUtil.closeSession(); } } }
案例二:使用注解测试单向一对多操作
- 一个班级有多个学生,班级可以查看所有学生的信息,但是学生不能查看班级的信息。
- ClassBean.java
package bean; import java.io.Serializable; import java.util.HashSet; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToMany; import javax.persistence.Table; @Entity @Table(name = "t_class") public class ClassBean implements Serializable { @Id private Integer classId; private String className; @OneToMany @JoinColumn(name = "class_id") //不会在本类中自动创建名为classes_id的属性因为只有“多”方有外键,Hibernate会自动把本类中的所有属性都映射为数据库中的字段,所以该属性要
//和表中的外键名一致,且Hibernate默认与StudentBean的主键相关联 private Set<StudentBean> stuSet=new HashSet<StudentBean>(); public ClassBean() { } public ClassBean(Integer classId, String className) { super(); this.classId = classId; this.className = className; } public Integer getClassId() { return classId; } public void setClassId(Integer classId) { this.classId = classId; } public String getClassName() { return className; } public void setClassName(String className) { this.className = className; } public Set<StudentBean> getStuSet() { return stuSet; } public void setStuSet(Set<StudentBean> stuSet) { this.stuSet = stuSet; } }
- StudentBean.java
package bean; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "t_student") public class StudentBean implements Serializable { @Id @Column(name = "stuid") private Integer studentId; @Column(name = "stuname") private String studentName; @Column(name="class_id") private Integer classid; public StudentBean() { } public StudentBean(Integer studentId, String studentName) { super(); this.studentId = studentId; this.studentName = studentName; } public Integer getStudentId() { return studentId; } public void setStudentId(Integer studentId) { this.studentId = studentId; } public String getStudentName() { return studentName; } public void setStudentName(String studentName) { this.studentName = studentName; } public Integer getClassid() { return classid; } public void setClassid(Integer classid) { this.classid = classid; } }
- 设置总配置文件的映射关系
<mapping class="bean.ClassBean" /> <mapping class="bean.StudentBean" />
- 测试一对多的操作
package action; import java.util.List; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.OneToMany; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.Transaction; import bean.ClassBean; import bean.StudentBean; import util.HibernateUtil; /** * 本类测试一对多的操作 * * @author 半颗柠檬、 * */ public class Test_ManytoOne { public static void main(String[] args) { // Test_ManytoOne.save(); // Test_ManytoOne.select(); Test_ManytoOne.delete(); } public static void save() { Session session = null; Transaction tran = null; try { session = HibernateUtil.getSessionFactory().getCurrentSession(); tran = session.beginTransaction(); ClassBean class1 = new ClassBean(); class1.setClassid(1); class1.setClassname("精英班"); StudentBean stu1 = new StudentBean(); stu1.setClassid(class1.getClassid()); stu1.setStuid(1); stu1.setStuname("学生1"); StudentBean stu2 = new StudentBean(); stu2.setStuid(2); stu2.setStuname("学生2"); stu2.setClassid(class1.getClassid()); session.save(class1); session.save(stu1); session.save(stu2); tran.commit(); } catch (Exception e) { e.printStackTrace(); tran.rollback(); } } /** * 测试“一”方能够读取“多”方的信息 */ private static void select() { Session session = null; Transaction tran = null; try { session = HibernateUtil.getSessionFactory().getCurrentSession(); tran = session.beginTransaction(); /** * 由“一”方得知“多”方信息 */ ClassBean cla = (ClassBean) session.get(ClassBean.class, new Integer(1)); Set<StudentBean> stuSet = cla.getStuSet(); for (StudentBean stu : stuSet) { System.out.println(stu.getStuname() + " " + stu.getStuid() + " " + stu.getClassid()); } // 过滤后的数据 ,这种方式会把排序注解忽略掉,即排序注解不会生效 System.out.println("过滤后的数据......."); Query query = session.createFilter(stuSet, " where stuid in (2,3)"); List<StudentBean> stuList = query.list(); for (StudentBean stu : stuList) { System.out.println(stu.getStuname() + " " + stu.getStuid() + " " + stu.getClassid()); } /** * 使用HQL语句。 */ System.out.println("使用HQL语句"); String hql = " select u from StudentBean u where stuid in(2,3) order by stuid desc "; query = session.createQuery(hql); stuList = query.list(); for (StudentBean stu : stuList) { System.out.println(stu.getStuname() + " " + stu.getStuid() + " " + stu.getClassid()); } tran.commit(); } catch (Exception e) { e.printStackTrace(); tran.rollback(); } } /** * 删除one一方的时候,一般不删除多方,Hibernate会自动把多方的外键置空 */ private static void delete() { Session session = null; Transaction tx = null; try { session = HibernateUtil.getSession(); tx = session.beginTransaction(); /** * B 在关联关系中配置cascade属性之后 */ ClassBean class1 = (ClassBean) session.get(ClassBean.class, new Integer(1)); session.delete(class1); tx.commit(); } catch (Exception e) { e.printStackTrace(); tx.rollback(); } finally { HibernateUtil.closeSession(); } } }
- 对于项目中大量使用@Entity注册在类头上,将一个类声明为一个实体bean(即一个持久化POJO类) , @Table注册在类头上,注解声明了该实体bean映射指定的表,来体现实体与表的这种映射关系。
对于属性字段和表的字段关系对应的注解属性的位置,一般我们采用以下两种方式:
第一种:
是把注解@Column(name ="xx")放在field上,一种是把注解放在get方法上一般放在field上看起来比较集中、清晰;
第二种:
是把注解@Column(name= "xx")放在get方法上,这种方式看起来比较散漫、不很清楚;
但是第一种方式这样做实际上破坏了Java面向对象的封装性,原因是一般我们写javaBean,成员变量通常定义为private,目的就是不让别人来直接访问的私有属性,而我们把注解放在私有成员的变量上,就是默认hibernate可以直接访问我们的私有的成员变量,所以我们定义属性为private,就实际没有多大意义,至于hibernate为什么能访问,hibernate采用java的反射机制完全可以访问私有成员变量!所以应该放在get方法上,第二种方式这个时候就显得更加合理。
- 注意 :注意的一点,在一个实体类中,要么将映射注解全部放在成员变量上,要么全部放在成员方法上,不能各放一部分