Hibernate映射关系全面解析
Hibernate映射关系全面解析,到今天为止,对Hibernate映射的郁闷已经无法再抑制了,也必须该和这个烦人的家伙做个了断了,下面将对Hibernate各种映射做一一细解。
Hibernate映射关系到底有多复杂?
传说中的不就是分为3种嘛,一对多,一对一,多对多,如果你真正用过hibernate你会发现实际的开发过程中遇到的情况要比概念的3种情况更为复杂。
对映关系还会分为单项关联和双项关联,而单项和双项关系,外键在主表还是从表又分两种情况,级联保存2个表的时候,有一种情况会多一条update语句,而有一种情况则只需要2条insert语句,究竟原理和王者解决之道,今天将水落石出了。
下面开始正题,首先目标瞄准,一对多关联关系。
建表:
学生表:create table student (id int primary key auto_increment,name varchar(30));
地址表:create table address (id int primary key auto_increment,city varchar(30),student_id int);
一个学生可以有多个地址,形成一对多的关系,而关联关系的外键由地址表维护!!
首先介绍单向一对多关联关系,外键在从表中
单向学生表PO
package cn.limaoyuan.hibernate.po.single;import java.util.HashSet;import java.util.Set;import javax.persistence.CascadeType;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.JoinColumn;import javax.persistence.OneToMany;import javax.persistence.Table;@Entity@Table(name="student")public class Student {private Integer id;private String name;private Set<Address> addressSet = new HashSet<Address>(0);@Id@GeneratedValue(strategy=GenerationType.AUTO)public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}@Column(name="name")public String getName() {return name;}public void setName(String name) {this.name = name;}/** * 单向一对多,外键在地址表中维护 * */@OneToMany(cascade=CascadeType.ALL) //CascadeType.All设成级联保存,以便演示更多效果。//这里没有mappedBy映射而是用@JoinColumn来代替,因为我们用的是单向关联关系,在Address中不存在student属性,只有studentId属性,所以我们用@JoinColumn来映射2张表之间的关系关系。@JoinColumn(name="student_id")public Set<Address> getAddressSet() {return addressSet;}public void setAddressSet(Set<Address> addressSet) {this.addressSet = addressSet;}}package cn.limaoyuan.hibernate.po.single;import java.io.Serializable;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.Table;@Entity@Table(name="address")public class Address implements Serializable{private Integer id;private String city;private Integer studentId;@Id@GeneratedValue(strategy=GenerationType.AUTO)public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}@Column(name="city")public String getCity() {return city;}public void setCity(String city) {this.city = city;}@Column(name="student_id")public Integer getStudentId() {return studentId;}public void setStudentId(Integer studentId) {this.studentId = studentId;}}package cn.limaoyuan.hibernate.dao;import cn.limaoyuan.hibernate.po.single.Student;public interface IStudentDao {public void insert(Student student);}package cn.limaoyuan.hibernate.dao;import org.hibernate.Session;import cn.limaoyuan.hibernate.po.single.Student;import cn.limaoyuan.hibernate.util.HibernateSessionFactory;public class StudentDaoImpl implements IStudentDao{@Overridepublic void insert(Student student) {Session session = HibernateSessionFactory.getSession();session.beginTransaction();session.save(student);session.getTransaction().commit();session.close();}}/** * 测试插入单向一对多关联关系 * */public static void insertStudent(){IStudentDao studentDao = new StudentDaoImpl();Student student = new Student();student.setName("zhang san");Address address = new Address();address.setCity("beijing");address.setStudentId(student.getId());student.getAddressSet().add(address); //这里直接插入学生,会级联插入地址studentDao.insert(student);}2010-02-23 14:39:54,906 DEBUG [main] SQL.log(401) | insert into student (name) values (?)2010-02-23 14:39:54,968 DEBUG [main] SQL.log(401) | insert into address (city, student_id) values (?, ?)2010-02-23 14:39:55,015 DEBUG [main] SQL.log(401) | update address set student_id=? where id=?
package cn.limaoyuan.hibernate.po.both;import java.util.HashSet;import java.util.Set;import javax.persistence.CascadeType;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.OneToMany;import javax.persistence.Table;@Entity@Table(name="student")public class StudentBoth {private Integer id;private String name;private Set<AddressBoth> addressSet = new HashSet<AddressBoth>(0);@Id@GeneratedValue(strategy=GenerationType.AUTO)public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}@Column(name="name")public String getName() {return name;}public void setName(String name) {this.name = name;}/** * 单向一对多,外键在地址表中 * */ //由于用了双项关联,那么在Address中就会有了student属性,那么我们就可以简单的使用mappedBy来指向address类中的student属性来关联这组关系。@OneToMany(cascade=CascadeType.ALL,mappedBy="student")public Set<AddressBoth> getAddressSet() {return addressSet;}public void setAddressSet(Set<AddressBoth> addressSet) {this.addressSet = addressSet;}}package cn.limaoyuan.hibernate.po.both;import java.io.Serializable;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.JoinColumn;import javax.persistence.ManyToOne;import javax.persistence.Table;import javax.persistence.Transient;@Entity@Table(name="address")public class AddressBoth implements Serializable{private Integer id;private String city;private Integer studentId;private StudentBoth student;@Id@GeneratedValue(strategy=GenerationType.AUTO)public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}@Column(name="city")public String getCity() {return city;}public void setCity(String city) {this.city = city;}@Transientpublic Integer getStudentId() {return studentId;}public void setStudentId(Integer studentId) {this.studentId = studentId;} /*这里由于使用了双向关联关系,那么就直接把数据库中的student_id字段直接映射成student属性,而不用单独映射成一个studentId属性,然后用@JoinColumn()注解的name属性去指定以本类中的哪个属性去关联对方,默认的是去关联对方的主键值,我们也可以用referencedColumnName属性去指定关联主表中的某个值来确认关系。@JoinColumn(name="student_id")的含义就是用address中的student_id字段去关联student表中的id字段,这里我们在@JoinColumn中省略了referencedColumnName="id",加上了也会得到同样的效果。*/@ManyToOne@JoinColumn(name="student_id")public StudentBoth getStudent() {return student;}public void setStudent(StudentBoth student) {this.student = student;}}//双向关联保存,外建在对方public static void insertStudentBoth(){IStudentDao studentDao = new StudentDaoImpl();StudentBoth student = new StudentBoth();student.setName("zhang san");AddressBoth address = new AddressBoth();address.setCity("beijing");//address.setStudentId(student.getId());address.setStudent(student); //地址表关联学生student.getAddressSet().add(address); //学生添加地址studentDao.insert(student); //保存学生}2010-02-23 14:57:28,000 DEBUG [main] SQL.log(401) | insert into student (name) values (?)2010-02-23 14:57:28,015 DEBUG [main] SQL.log(401) | insert into address (city, student_id) values (?, ?)
package cn.limaoyuan.hibernate.po.single2;import java.util.HashSet;import java.util.Set;import javax.persistence.CascadeType;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.JoinColumn;import javax.persistence.ManyToOne;import javax.persistence.OneToMany;import javax.persistence.OneToOne;import javax.persistence.Table;@Entity@Table(name="student")public class StudentSingle2 {private Integer id;private String name;private AddressSingle2 address;@Id@GeneratedValue(strategy=GenerationType.AUTO)public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}@Column(name="name")public String getName() {return name;}public void setName(String name) {this.name = name;}/** * 双向一对一,外键在对方,一对一可以用OneToOne来映射,由于外键在对方,那么OneToOne方式只能用mappedBy去引用。 **/@OneToOne(mappedBy="student",cascade=CascadeType.ALL)public AddressSingle2 getAddress() {return address;}public void setAddress(AddressSingle2 address) {this.address = address;}}package cn.limaoyuan.hibernate.po.single2;import java.io.Serializable;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.JoinColumn;import javax.persistence.OneToOne;import javax.persistence.Table;@Entity@Table(name="address")public class AddressSingle2 implements Serializable{private Integer id;private String city;private StudentSingle2 student;@Id@GeneratedValue(strategy=GenerationType.AUTO)public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}@Column(name="city")public String getCity() {return city;}public void setCity(String city) {this.city = city;}@OneToOne@JoinColumn(name="student_id") //自己的student_id字段去关联studnet表中的id属性,如果不是关联student主键,那么可以用referencedColumnName指定。public StudentSingle2 getStudent() {return student;}public void setStudent(StudentSingle2 student) {this.student = student;}}/** * 测试插入单向一对多关联关系 ,外建在本方 * */public static void insertStudentSingle2(){IStudentDao studentDao = new StudentDaoImpl();StudentSingle2 student = new StudentSingle2();student.setName("zhang san");AddressSingle2 address = new AddressSingle2();address.setCity("beijing");address.setStudent(student); //地址绑定学生student.setAddress(address); //学生绑定地址studentDao.insert(student); //插入学生}2010-02-23 15:24:21,546 DEBUG [main] SQL.log(401) | insert into student (name) values (?)2010-02-23 15:24:21,562 DEBUG [main] SQL.log(401) | insert into address (city, student_id) values (?, ?)
package cn.limaoyuan.hibernate.po.single3;/** * 一对一单项关联,外键在本方 * */import javax.persistence.*;@Entity@Table(name="student2")public class StudentSingle3 {private Integer id;private String name;private AddressSingle3 address;@Id@GeneratedValue(strategy=GenerationType.AUTO)public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}@Column(name="name")public String getName() {return name;}public void setName(String name) {this.name = name;}/** * 单向一对多,外键在本方,一对一可以用OneToOne来映射 * */@OneToOne(cascade=CascadeType.ALL)@JoinColumn(name="address_id")public AddressSingle3 getAddress() {return address;}public void setAddress(AddressSingle3 address) {this.address = address;}}package cn.limaoyuan.hibernate.po.single3;import java.io.Serializable;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.Table;@Entity@Table(name="address2")public class AddressSingle3 implements Serializable{private Integer id;private String city;@Id@GeneratedValue(strategy=GenerationType.AUTO)public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}@Column(name="city")public String getCity() {return city;}public void setCity(String city) {this.city = city;}}/** * 测试插入单向一对一关联关系 ,外建在本方 * */public static void insertStudentSingle3(){IStudentDao studentDao = new StudentDaoImpl();StudentSingle3 student = new StudentSingle3();student.setName("zhang san");AddressSingle3 address = new AddressSingle3();address.setCity("beijing");student.setAddress(address);studentDao.insert(student);}2010-02-23 15:53:29,453 DEBUG [main] SQL.log(401) | insert into address2 (city) values (?)2010-02-23 15:53:29,468 DEBUG [main] SQL.log(401) | insert into student2 (address_id, name) values (?, ?)