hibernate 字段长度多对多 表里要加字段吗

下载作业帮安装包
扫二维码下载作业帮
1.75亿学生的选择
hibernate 配置中,把一个表字段同时配成id和property,会不会有什么影响?背景:遗留数据库中,需通过两个字段连添加一对多关联。但是properties里不能嵌套id定义,所以额外配置了一个和id同名的property。
你懂得8b欹
应该不会有什么问题撒!
为您推荐:
扫描下载二维码hibernate 多对多 中间表有其他的字段怎么办 - ITeye问答
如:student& course&& sc
sc表中有sid(student的主键)cid(course的主键) 还有成绩score
哪位大侠帮助一下哈,我查了很多的网上资料说的都比较模糊 ,有没有哪位大侠给个完整的例子啊 ,顺便讲解一下!着急啊!
为什么你会去看我的one-to-many的介绍,你应该看的是many-to-many中间实体的关联关系处理啊& 引用/admin/blogs/1202133
将这个多对多的关联关系用两个一对多的关联关系表示,这样就会将中间表提取成一个中间实体,详情请参见这篇博文&&
延迟加载啊,你设置关联配置里面的lazy=true
已解决问题
未解决问题Hibernate中多对多的annotation的写法(中间表可以有多个字段)
我的图书馆
Hibernate中多对多的annotation的写法(中间表可以有多个字段)
一般情况下,多对多的关联关系是需要中间表的;
情况一:如果中间表仅仅是做关联用的,它里面仅有2个外键做联合主键,则使用ManyToMany(不用写中间表的Model,只需要写出两张主表的model即可)
@Table(name = "T_STUDENT")
@SequenceGenerator(name = "SEQ_STUDENT", sequenceName = "SEQ_STUDENT")
public class Student implements Serializable {
private static final long serialVersionUID = 9848644L;
private Set&Teacher& teacherL
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_STUDENT")
@Column(name = "ID", nullable = false, precision = 22, scale = 0)
public Long getId() {
public void setId(Long id) {
@Column(name = "NAME")
public String getName() {
public void setName(String name) {
this.name =
@Temporal(TemporalType.DATE)
@Column(name = "BIRTHDAY")
public Date getBirthday() {
public void setBirthday(Date birthday) {
this.birthday =
@Column(name = "sex")
public int getSex() {
public void setSex(int sex) {
this.sex =
@Column(name = "address")
public String getAddress() {
public void setAddress(String address) {
this.address =
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "T_TEACHER_STUDENT",
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "teacher_id"))
public Set&Teacher& getTeacherList() {
return teacherL
public void setTeacherList(Set&Teacher& teacherList) {
this.teacherList = teacherL
@Table(name = "T_TEACHER")
@SequenceGenerator(name = "SEQ_TEACHER", sequenceName = "SEQ_TEACHER")
public class Teacher implements Serializable {
private static final long serialVersionUID = 5111793L;
private Set&Student& studentL
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_TEACHER")
@Column(name = "ID", nullable = false, precision = 22, scale = 0)
public Long getId() {
public void setId(Long id) {
@Column(name = "name")
public String getName() {
public void setName(String name) {
this.name =
@Column(name = "sex")
public int getSex() {
public void setSex(int sex) {
this.sex =
@ManyToMany(mappedBy = "teacherList", cascade = CascadeType.ALL)
public Set&Student& getStudentList() {
return studentL
public void setStudentList(Set&Student& studentList) {
this.studentList = studentL
hibernate.cfg.xml配置2个class类
&mapping class="com.dvn.li.model.Student"/&
&mapping class="com.dvn.li.model.Teacher"/&
SessionFactory sessionFactory =
Session session =
sessionFactory = HibernateUtil.getSessionFactory();
session = sessionFactory.getCurrentSession();
session.beginTransaction();
Student s = new Student();
s.setName("小猪");
Teacher t = new Teacher();
t.setName("小李");
Set&Teacher& t_set = new HashSet&Teacher&();
t_set.add(t);
s.setTeacherList(t_set);
session.save(s);
} catch (Exception e) {
if (session != null) {
session.getTransaction().rollback();
测试通过!!!
很简单吧!注意HibernateUtil.getSessionFactory()的实现如下:
public class HibernateUtil {
private static final SessionFactory sessionF
// Create the SessionFactory from hibernate.cfg.xml
sessionFactory = new AnnotationConfiguration().configure()
.buildSessionFactory();
} catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
public static SessionFactory getSessionFactory() {
return sessionF
如果自己做测试,可以通过SchemaExport导入表结构
SchemaExport export = new SchemaExport(new AnnotationConfiguration()
.configure());
export.create(true, true);
情况二:如果中间表不仅仅是做关联用的,它里面包含了其他字段信息,仅仅靠多对多的关系是搞不定的。
解决方案:多对多的关系拆分为两个一对多!这时候三张表的Model都需要写。
我们知道,一对多的关系,一般都是在多的一方做配置。具体代码如下:
@Table(name = "T_STUDENT")
@SequenceGenerator(name = "SEQ_STUDENT", sequenceName = "SEQ_STUDENT")
public class Student2 implements Serializable {
private static final long serialVersionUID = 9848644L;
private Set&TeacherStudent& teacherStudentL
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_STUDENT")
@Column(name = "ID", nullable = false, precision = 22, scale = 0)
public Long getId() {
public void setId(Long id) {
@Column(name = "NAME")
public String getName() {
public void setName(String name) {
this.name =
@Temporal(TemporalType.DATE)
@Column(name = "BIRTHDAY")
public Date getBirthday() {
public void setBirthday(Date birthday) {
this.birthday =
@Column(name = "sex")
public int getSex() {
public void setSex(int sex) {
this.sex =
@Column(name = "address")
public String getAddress() {
public void setAddress(String address) {
this.address =
@OneToMany(mappedBy="student",cascade=CascadeType.ALL)
public Set&TeacherStudent& getTeacherStudentList() {
return teacherStudentL
public void setTeacherStudentList(Set&TeacherStudent& teacherStudentList) {
this.teacherStudentList = teacherStudentL
@Table(name = "T_TEACHER")
@SequenceGenerator(name = "SEQ_TEACHER", sequenceName = "SEQ_TEACHER")
public class Teacher2 implements Serializable {
private static final long serialVersionUID = 5111793L;
private Set&TeacherStudent& teacherStudentL
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_TEACHER")
@Column(name = "ID", nullable = false, precision = 22, scale = 0)
public Long getId() {
public void setId(Long id) {
@Column(name = "name")
public String getName() {
public void setName(String name) {
this.name =
@Column(name = "sex")
public int getSex() {
public void setSex(int sex) {
this.sex =
@OneToMany(mappedBy = "teacher",cascade=CascadeType.ALL)
public Set&TeacherStudent& getTeacherStudentList() {
return teacherStudentL
public void setTeacherStudentList(Set&TeacherStudent& teacherStudentList) {
this.teacherStudentList = teacherStudentL
@Table(name = "T_TEACHERSTUDENT")
@SequenceGenerator(name = "SEQ_TEACHERSTUDENT", sequenceName = "SEQ_TEACHERSTUDENT")
public class TeacherStudent implements Serializable {
private Student2
private Teacher2
private String note1;
private String note2;
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_TEACHERSTUDENT")
@Column(name = "ID", nullable = false, precision = 22, scale = 0)
public Long getId() {
public void setId(Long id) {
@Column(name = "note1")
public String getNote1() {
return note1;
public void setNote1(String note1) {
this.note1 = note1;
@Column(name = "note2")
public String getNote2() {
return note2;
public void setNote2(String note2) {
this.note2 = note2;
@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name = "student_id", unique = true)
public Student2 getStudent() {
public void setStudent(Student2 student) {
this.student =
@ManyToOne
@JoinColumn(name = "teacher_id", unique = true)
public Teacher2 getTeacher() {
public void setTeacher(Teacher2 teacher) {
this.teacher =
hibernate.cfg.xml 引入对象
&mapping class="com.dvn.li.model.Student2"/&
&mapping class="com.dvn.li.model.Teacher2"/&
&mapping class="com.dvn.li.model.TeacherStudent"/&
SessionFactory sessionFactory =
Session session =
sessionFactory = HibernateUtil.getSessionFactory();
session = sessionFactory.getCurrentSession();
session.beginTransaction();
Student2 s = new Student2();
s.setName("小猪");
Teacher2 t = new Teacher2();
t.setName("小李");
TeacherStudent ts=new TeacherStudent();
ts.setStudent(s);
ts.setTeacher(t);
ts.setNote1("以呀呀!!!");
session.save(s);
session.save(t);
session.save(ts);
session.getTransaction().commit();
} catch (Exception e) {
if (session != null) {
session.getTransaction().rollback();
测试通过!
发表评论:
TA的最新馆藏[转]&Hibernate(6)—— 一对多 和 多对多关联关系映射(xml和注解)总结
分类:程序语言|标签:JAVA|日期:
俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及的知识点总结如下:
One to Many 映射关系
多对一单向外键关联(XML/Annotation)
一对多单向外键关联(XML/Annotation)
懒加载和积极加载
一对多双向外键关联(XML/Annotation)
Many to Many 映射关系
多对多单向外键关联(XML/Annotation)
多对多双向外键关联(XML/Annotation)
set的inverse元素详解
关联关系的优缺点
  多对一单向外键关联关系
  注意多对一关联是多方持有一方的引用。看一个例子,去淘宝购物,那么一个淘宝用户可以对应多个购物订单,如图所示:
  多的一方是Orders,持有一方的引用,也就是Users,而在Users中无需作任何定义,从订单到用户的关系是单向多对一关联。对应数据库就是:
  还有比如说学生和班级的关系,多个学生可以属于同一个班级,这就是从学生到班级也是典型的单向多对一关系,看代码实现:
  基于注解的多对一单向外键关联:
  单向多对一关联中,多方需要持有一方的引用,那么多方(学生类)需要额外配置,需要对持有的一方引用使用注解@ManyToOne (cascade={CascadeType.ALL}, fetch=FetchType.EAGER),设置为级联操作和饥渴的抓取策略,@JoinColumn(name=&cid&),而一方(教室类)无需做任何多方的定义。
  注意;多方必须保留一个不带参数的构造器!
import javax.persistence.E
import javax.persistence.GeneratedV
import javax.persistence.Id;
//班级类,在多对一关系中属于一的方,不持有其他多余的配置,反而是被多方持有
public class ClassRoom {
//班级编号
private S//班级名称
自动增长的主键
@GeneratedValue
public int getCid() {
public void setCid(int cid) {
this.cid =
public String getCname() {
public void setCname(String cname) {
一方——班级类无需做多余的定义,下面是多方——学生实体和配置:
import javax.persistence.CascadeT
import javax.persistence.E
import javax.persistence.FetchT
import javax.persistence.GeneratedV
import javax.persistence.Id;
import javax.persistence.JoinC
import javax.persistence.ManyToO
//学生实体类,属于多对一的多方,持有班级(一方)的引用
public class Students {
private S //姓名
private ClassR//学生班级
//注意:多方一定要显式的定义不带参数的构造方法
public Students() {
public Students(String sname)
this.sname =
多方使用注解:@ManyToOne
fetch=FetchType.EAGER,急加载,加载一个实体时,定义急加载的属性会立即从数据库中加载。
全部级联操作,referencedColumnName显式设置数据库字段名cid,不写默认就是和name一样的。
@ManyToOne (cascade={CascadeType.ALL}, fetch=FetchType.EAGER)
@JoinColumn(name=&cid&,referencedColumnName=&cid&)
public ClassRoom getClassroom() {
public void setClassroom(ClassRoom classroom) {
this.classroom =
自动增长主键
@GeneratedValue
public int getSid() {
public void setSid(int sid) {
this.sid =
public String getSname() {
public void setSname(String sname) {
this.sname =
下面测试:先生成数据库脚本,再进行学生对象的插入
public class TestStudentsByAnno {
private static SessionFactory sessionF
public void setUp() throws Exception {
System.out.println(&setUp()...&);
sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
public void tearDown() throws Exception {
System.out.println(&tearDown()...&);
sessionFactory.close();
public void testSave() {
Session session = sessionFactory.getCurrentSession();
Transaction tx = session.beginTransaction();
ClassRoom c = new ClassRoom();
c.setCname(&computer001&);
Students s = new Students(&zhangsan&);
s.setClassroom(c);
session.save(s);
tx.commit();
} catch(Exception ex) {
ex.printStackTrace();
tx.rollback();
public void testSchemaExport() {
SchemaExport se = new SchemaExport(new AnnotationConfiguration().configure());
se.create(true, true);
反向创建表的数据库脚本如下:
create table ClassRoom (cid integer not null auto_increment, cname varchar(255), primary key (cid))create table Students (sid integer not null auto_increment, sname varchar(255), cid integer, primary key (sid))
插入一个学生对象,会自动生成如下语句:
ClassRoom c = new ClassRoom();
c.setCname(&computer001&);
Students s = new Students(&zhangsan&);
s.setClassroom(c);
session.save(s);
tx.commit();
Hibernate: insert into ClassRoom (cname) values (?)
Hibernate: insert into Students (cid, sname) values (?, ?)
插入成功:
  基于xml配置实现多对一单向外键关联
&hibernate-mapping&
&class name=&net.nw.vo.fk.mto.ClassRoom& table=&classroom&&
&id name=&cid& column=&cid& type=&int&&
&generator class=&native&/&
&property name=&cname& column=&cname& type=&string&/&
&/hibernate-mapping&
  一方(教室类)无需做任何多方的定义。只需要维护好自己的属性配置即可。而多方只需要加上&many-to-one name=&& column=“&/&就ok。
&hibernate-mapping&
&class name=&net.nw.vo.fk.mto.Students& table=&students&&
&id name=&sid& column=&sid& type=&int&&
&generator class=&native&/&
&property name=&sname& column=&sname& type=&string&/&
&many-to-one name=&classroom& column=&cid&/&
&/hibernate-mapping&
  hibernate.cfg.xml里加上
&mapping resource=&net/nw/vo/fk/mto/ClassRoom.hbm.xml& /&
&mapping resource=&net/nw/vo/fk/mto/Students.hbm.xml& /&
注意:如果没有设置级联ALL,那么需要在保存的时候先保存班级,在保存学生,否则出错:&object references an unsaved transient instance - save the transient instance before flushing:&
ClassRoom classRoom = new ClassRoom();
classRoom.setCname(&CS&);
Students students = new Students(&111&);
students.setClassroom(classRoom);
session.save(classRoom);
session.save(students);
tx.commit();
  小结:使用&many-to-one&元素进行多对一关联关系配置,name属性& 指定类的属性名,column属性 指定库表字段名,class属性& 指定类属性类型(加上姓,即包名),not-null属性 指定属性是否允许为空,cascade属性 指定是否级联保存和更新:save-update、delete、all、none。
  一对多单向外键关联
  当类与类建立了关联,程序能很方便的从一个对象导航到另一个或一组与之关联的对象,有了student对象,就可以通过student对象得到这个学生所属的班级的信息——students.getClassroom();,对于班级对象,如果想要得到某个学生的信息,怎么办呢?这时候可以反过来控制,一方控制多方,下面进行一对多单向外键关联。
  简单说就是和之前多对一相反,之前是多方持有一方的引用,而一对多关联关系是一方持有多方的集合的引用,注意区别:这里是持有多方的集合。
  基于注解的配置:
&  @OneToMany(cascade={CascadeType.ALL},fetch=FetchType.LAZY),@JoinColumn(name=&&),除了级联之外,还要设置一方为懒加载模式。且外键还是加在了多方学生表里,只不过控制权变了,之前多对一关联是多方学生持有班级外键,控制班级,现在一对多关联,表里还是多方学生持有班级一方的外键,只不过控制权交给了班级,让班级控制学生。不要混淆。
import javax.persistence.*;
import java.util.S
//班级类是一方,一方持有多方的引用
public class ClassRoom {
//班级编号
private S//班级名称
private Set&Students&//班级的学生集合是多方
现在是一方维护多方了,主控权交给了一方,设置级联,一方要设置懒加载,推荐!
@OneToMany(cascade={CascadeType.ALL},fetch=FetchType.LAZY)
@JoinColumn(name=&cid&) // 设置一方的外键,这里是cid,因为实际上这个外键还是加在多方,只不过控制权变了。
public Set&Students& getStus() {
public void setStus(Set&Students& stus) {
this.stus =
@GeneratedValue
public int getCid() {
public void setCid(int cid) {
this.cid =
public String getCname() {
public void setCname(String cname) {
  注意,不论多对一还是一对多,多方都要显式保留无参构造器。
import javax.persistence.E
import javax.persistence.GeneratedV
import javax.persistence.Id;
//学生实体类
public class Students {
private S //姓名
//注意:一定要保留这个默认不带参数的构造方法
public Students(){
public Students(String sname)
this.sname =
@GeneratedValue
public int getSid() {
public void setSid(int sid) {
this.sid =
public String getSname() {
public void setSname(String sname) {
this.sname =
  执行数据库脚本,发现一方(主控方)还是和之前多对一的表结构一样,多方也是如此。
create table ClassRoom (cid integer not null auto_increment, cname varchar(255), primary key (cid))create table Students (sid integer not null auto_increment, sname varchar(255), cid integer, primary key (sid))
  执行测试,保存学生,因为现在关系是一方维护,控制多方。肯定保存主控方——班级(和之前相反,之前多对一保存的是多方学生对象),但是本质上还是先保存的学生班级,再自动保存学生,这点和多对一本质一样。
Set&Students& stus = new HashSet&&();
stus.add(new Students(&zhangsan&));
stus.add(new Students(&lisi&));
stus.add(new Students(&wangwu&));
stus.add(new Students(&zhaoliu&));
stus.add(new Students(&sunqi&));
ClassRoom c = new ClassRoom();
c.setCname(&cs001&);
c.setStus(stus);
session.save(c);
tx.commit();
  生成的脚本如下:先插入外键的班级对象,在执行五个学生的插入操作,最后执行五个更新,为sid=1。。。5的学生,更新cid为2
Hibernate: insert into ClassRoom (cname) values (?)
Hibernate: insert into Students (sname) values (?)
Hibernate: insert into Students (sname) values (?)
Hibernate: insert into Students (sname) values (?)
Hibernate: insert into Students (sname) values (?)
Hibernate: insert into Students (sname) values (?)
Hibernate: update Students set cid=? where sid=?
Hibernate: update Students set cid=? where sid=?
Hibernate: update Students set cid=? where sid=?
Hibernate: update Students set cid=? where sid=?
Hibernate: update Students set cid=? where sid=?
  总结:多对一时候,多方设置EAGER,一方设置LAZY,也就是说,如果是多对一,多方控制一方,那么多方设置积极加载,一方无需多余配置,反过来,如果是一对多关系,一方控制多方,那么一方设置懒加载,多方无需多余配置,但是不论哪种,多方都显式加上一个不带参数的构造器。
  一对多里的懒加载
  记得之前总结,get和load的查询方式源码的时候,就总结了一下懒加载load里的应用,之前说Hibernate中,当访问的数据量过大时,用缓存也不太合适,&因为内存容量有限 ,为了减少并发量,减少系统资源的消耗,Hibernate用懒加载机制来弥补这种缺陷,但是这只是弥补而不是用了懒加载总体性能就提高了。懒加载也被称为延迟加载,它在查询的时候不会立刻访问数据库,而是返回代理对象,比如之前总结的load方式查询,当真正去使用对象的时候才会访问数据库。除了load查询默认使用懒加载,现在我们的一对多关联映射也使用了lazy加载,下面进行实际验证测试:
public void testQuery()
Session session = sessionFactory.getCurrentSession();
Transaction tx = session.beginTransaction();
// 首先查询班级,cid=1的班级
ClassRoom c =(ClassRoom) session.get(ClassRoom.class, 1);
// 通过班级导航到学生,遍历学生得到名字
for(Students s : c.getStus()) {
System.out.println(&姓名 :& + s.getSname());
tx.commit();
} catch(Exception ex) {
ex.printStackTrace();
tx.rollback();
  执行之后,debug发现:在没有使用班级对象的时候,只有这样一条SQL语句:从classroom表查询,cid=1的班级,使用使用AS赋给列一个别名。
Hibernate: select classroom0_.cid as cid0_0_, classroom0_.cname as cname0_0_ from ClassRoom classroom0_ where classroom0_.cid=?
  等执行到for了,才打印这一语句:
Hibernate: select stus0_.cid as cid0_1_, stus0_.sid as sid1_, stus0_.sid as sid1_0_, stus0_.sname as sname1_0_ from Students stus0_ where stus0_.cid=?
  充分说明这是执行的懒加载模式。一方控制多方,一方设置懒加载,如果什么都不设置,会是什么情况?经过验证,发现和显式设置懒加载效果一样,也就是说,one-to-many(元素)的懒加载是默认的,这是必须的,是常用的策略。一对多的时候,查询主对象时默认是懒加载。即:查询主对象的时候不会把从对象查询出来,使用从对象的时候才加载从对象。
  如果人为设置为积极加载,则直接全部查询,@OneToMany(cascade={CascadeType.ALL},fetch=FetchType.EAGER),SQL语句为如下,进行了外连接的查询。一次性查了主对象和从对象出来。
Hibernate: select classroom0_.cid as cid0_1_, classroom0_.cname as cname0_1_, stus1_.cid as cid0_3_, stus1_.sid as sid3_, stus1_.sid as sid1_0_, stus1_.sname as sname1_0_ from ClassRoom classroom0_ left outer join Students stus1_ on classroom0_.cid=stus1_.cid where classroom0_.cid=?
  基于xml文件配置:
  一方作为主控方:
&set name=&& &
&key column=&&/&
&one-to-many class= && /&
  一方是班级,持有多方的集合,如下配置:
&hibernate-mapping&
&class name=&net.nw.vo.fk.otm.ClassRoom& table=&classroom&&
&id name=&cid& column=&cid& type=&int&&
&generator class=&native&/&
&property name=&cname& column=&cname& type=&string&/&
&set name=&stus& &
&!-- 外键还是班级cid --&
&key column=&cid&/&
&one-to-many class=&net.nw.vo.fk.otm.Students& /&
&/hibernate-mapping&
  多方是学生,作为从对象,别忘了,保留无参构造器,如下配置:
&hibernate-mapping&
&class name=&net.nw.vo.fk.otm.Students& table=&students&&
&id name=&sid& column=&sid& type=&int&&
&generator class=&native&/&
&property name=&sname& column=&sname& type=&string&/&
&/hibernate-mapping&
  一对多双向外键关联
  其实类似之前的一对一双向外键关联,也是互相持有对方的引用,故也叫双向一对多自身关联。多方持有一方的引用,@ManyToOne(cascade={CascadeType.ALL}),@JoinColumn(name=&&)。反过来,一方也持有多方的集合,@OneToMany(cascade={CascadeType.ALL}),@JoinColumn(name=&&)。代码如下:
  基于注解的配置:
import javax.persistence.CascadeT
import javax.persistence.E
import javax.persistence.FetchT
import javax.persistence.GeneratedV
import javax.persistence.Id;
import javax.persistence.JoinC
import javax.persistence.ManyToO
//学生实体类,属于多方,持有一方的引用
public class Students {
private S //姓名
private ClassR//学生班级属于一方
//注意:一定要在多方保留这个默认不带参数的构造方法
public Students() {
public Students(String sname) {
this.sname =
多方是设置积极加载,全部级联
@ManyToOne (cascade={CascadeType.ALL}, fetch=FetchType.EAGER)
@JoinColumn(name=&cid&,referencedColumnName=&cid&) // 外键设置为班级id,cid
public ClassRoom getClassroom() {
public void setClassroom(ClassRoom classroom) {
this.classroom =
@GeneratedValue
public int getSid() {
public void setSid(int sid) {
this.sid =
public String getSname() {
public void setSname(String sname) {
this.sname =
  关键是一方,也必须持有多方的集合,形成你中有我,我中有你的局面,互相控制。但是还是注意,本质上,数据库表里外键cid还是加在了学生表——多方的表里。
import javax.persistence.*;
import java.util.S
public class ClassRoom {
//班级编号
private S//班级名称
private Set&Students& // 一方也持有了多方:学生的集合引用
一方也要控制多方,一方设置懒加载,外键还是cid,也就是外键还是加在多方——学生表。
@OneToMany(cascade={CascadeType.ALL},fetch=FetchType.LAZY)
@JoinColumn(name=&cid&)
public Set&Students& getStus() {
public void setStus(Set&Students& stus) {
this.stus =
@GeneratedValue
public int getCid() {
public void setCid(int cid) {
this.cid =
public String getCname() {
public void setCname(String cname) {
  测试脚本生成。和之前表一样,只不过控制权双方都有了:
alter table Students drop foreign key FK73AC29B
drop table if exists ClassRoom
drop table if exists Students
create table ClassRoom (cid integer not null auto_increment, cname varchar(255), primary key (cid))
create table Students (sid integer not null auto_increment, sname varchar(255), cid integer, primary key (sid))
alter table Students add index FK73AC29B (cid), add constraint FK73AC29B foreign key (cid) references ClassRoom (cid)
&  此时先保存谁都可以!控制权是双方都有。
  基于xml配置:
  多方:&many-to-one name=&group& column=&gid&&&/many-to-one&,一方:记住,一方是持有集合
&set name=&& &
&key column=&&&&/key&
&one-to-many class=&&/&
  本例代码如下:
&hibernate-mapping&
&class name=&net.nw.vo.bfk.mto.Students& table=&students&&
&id name=&sid& column=&sid& type=&int&&
&generator class=&native&/&
&property name=&sname& column=&sname& type=&string&/&
&many-to-one name=&classroom& column=&cid&/&
&/hibernate-mapping&
----------------------------------------------------------------------------------
&hibernate-mapping&
&class name=&net.nw.vo.bfk.mto.ClassRoom& table=&classroom&&
&id name=&cid& column=&cid& type=&int&&
&generator class=&native&/&
&property name=&cname& column=&cname& type=&string&/&
&set name=&stus& &
&key column=&cid&/&
&one-to-many class=&net.nw.vo.bfk.mto.Students& /&
&/hibernate-mapping&
  小结:在关系模型中,只存在外键参照关系,而且是many方参照one方。
  多对多的关联关系映射
  现在有一个角色类,和一个特权类,前者保存了都有哪些人(角色)拥有哪些特权,后者保存的是一些特权,比如可以做什么,不可以做什么等让哪些人拥有。如图类关系:
  这就是一个多对多的例子,他们之间在数据库如何实现的关联呢?显然不能互相持有对方主键做外键,那么就需要用到一个新的表——映射表作为中间表:
  再举一个最熟悉的学生的例子,现实中,学生和教师就构成了多对多的关联关系。一个教师可以教很多学生,同时一个学生可以师从很多老师,拿这个例子说明。
  多对多单向外键关联
  其中一个多方持有另一个多方的集合对象,而且前面也分析了,还需要创建一个中间表,先看两个实体对象配置
基于注解的多对多单向外键关系配置:
  一个多方持有另一个多方的集合对象,我让学生持有老师的集合对象引用,同样的另一个多方——老师不做多余配置,且多方要显式设置一个无参构造器,那么学生需要使用注解@ManyToMany和@JoinTable,设置级联全部 cascade=CascadeType.ALL,代码如下:
import javax.persistence.*;
import java.util.S
//学生实体类
public class Students {
private S //姓名
private Set&Teachers&
// 我设置学生这个多方去持有老师这个多方的集合,去控制老师
//注意:一定要保留这个默认不带参数的构造方法
public Students() {
public Students(String sname)
this.sname =
先设置多对多的关联,之后必须生成一个中间表,使用JoinTable注解
@ManyToMany(cascade=CascadeType.ALL)
@JoinTable(
设置中间表名
name=&teachers_students&,
指定当前对象的外键,本表在中间表的外键名称
joinColumns={@JoinColumn(name=&sid&)},
指定关联对象的外键,另一个表在中间表的外键名称。
inverseJoinColumns={@JoinColumn(name=&tid&)}
public Set&Teachers& getTeachers() {
public void setTeachers(Set&Teachers& teachers) {
this.teachers =
@GeneratedValue
public int getSid() {
public void setSid(int sid) {
this.sid =
public String getSname() {
public void setSname(String sname) {
this.sname =
  另一个多方,老师不做多余配置:
import javax.persistence.E
import javax.persistence.GeneratedV
import javax.persistence.Id;
public class Teachers {
//教师的编号
private S//教师姓名
public Teachers() {
public Teachers(String tname)
this.tname =
@GeneratedValue
public int getTid() {
public void setTid(int tid) {
this.tid =
public String getTname() {
public void setTname(String tname) {
this.tname =
  生成的数据库脚本如下:
create table Students (sid integer not null auto_increment, sname varchar(255), primary key (sid))create table Teachers (tid integer not null auto_increment, tname varchar(255), primary key (tid))create table teachers_students (sid integer not null, tid integer not null, primary key (sid, tid))
  主要关注中间表,sid和tid都是作为了中间表的联合主键,他们同时也是外键:
  下面进行插入数据的测试,因为学生持有老师集合引用,且设置了级联,故直接保存学生就ok:
// 因为学生持有教师的集合,先设置教师
Set&Teachers& teachers = new HashSet&&();
teachers.add(new Teachers(&Wang&));
teachers.add(new Teachers(&Li&));
teachers.add(new Teachers(&Song&));
teachers.add(new Teachers(&Zhang&));
Students s = new Students();
s.setSname(&zhangsan&);
s.setTeachers(teachers);
session.save(s);
tx.commit();
  基于xml的多对多单向外键关系配置:
  学生这个多方持有老师的集合,那么持有对方集合的学生映射文件配置如下:&
&hibernate-mapping&
&class name=&net.nw.vo.fk.mtm.Students& table=&students&&
&id name=&sid& column=&sid& type=&int&&
&generator class=&native&/&
&property name=&sname& column=&sname& type=&string&/&
&!-- 学生表持有老师的集合,如下进行配置 --&
&set name=&teachers& table=&students_teachers& cascade=&all&&
&!-- table设置中间表,级联是all --&
&!-- key设置本对象在中间表的外键sid --&
&key column=&sid&/&
&!-- many-to-many 标签设置对方的表(老师)在中间表的外键tid --&
&many-to-many class= &net.nw.vo.fk.mtm.Teachers& column=&tid&/&
&/hibernate-mapping&
  老师表配置就简单了:
&hibernate-mapping&
&class name=&net.nw.vo.fk.mtm.Teachers& table=&teachers&&
&id name=&tid& column=&tid& type=&int&&
&generator class=&native&/&
&property name=&tname& column=&tname& type=&string&/&
&/hibernate-mapping&
  进行测试(删除之前的表,先删除中间表,在删除老师表,最后删除学生表):
Set&Teachers& teachers = new HashSet&&();
teachers.add(new Teachers(&Teacher Wang&));
teachers.add(new Teachers(&Teacher Li&));
teachers.add(new Teachers(&Teacher Song&));
teachers.add(new Teachers(&Teacher Zhang&));
Students s = new Students();
s.setSname(&zhangsan&);
s.setTeachers(teachers);
session.save(s);
tx.commit();
  多对多双向外键关联
  和之前的类似,是互相持有对方的集合,双方持有对方的集合对象,其中一方设置@ManyToMany(mappedBy=&&),另一方:
@ManyToMany
@JoinTable(
joinColumns={@JoinColumn(name=&&)},
inverseJoinColumns={@JoinColumn(name=&&)}
  基于注解的配置,看具体代码:
import javax.persistence.*;
import java.util.S
//学生实体类
public class Students {
private S //姓名
private Set&Teachers&
//注意:一定要保留这个默认不带参数的构造方法
public Students() {
public Students(String sname)
this.sname =
@ManyToMany(cascade=CascadeType.ALL)
@JoinTable(
name=&teachers_students&,
joinColumns={@JoinColumn(name=&sid&)},
inverseJoinColumns={@JoinColumn(name=&tid&)}
public Set&Teachers& getTeachers() {
public void setTeachers(Set&Teachers& teachers) {
this.teachers =
@GeneratedValue
public int getSid() {
public void setSid(int sid) {
this.sid =
public String getSname() {
public void setSname(String sname) {
this.sname =
  关键是另一方的配置,前面总结了,双向关联不会真的是互相维持,只能交给一方去维护:
import javax.persistence.E
import javax.persistence.GeneratedV
import javax.persistence.Id;
import javax.persistence.ManyToM
import java.util.S
public class Teachers {
//教师的编号
private S//教师姓名
private Set&Students&
public Teachers() {
public Teachers(String tname)
this.tname =
把控制权交给student类——teachers集合引用
@ManyToMany(mappedBy=&teachers&)
public Set&Students& getStus() {
public void setStus(Set&Students& stus) {
this.stus =
@GeneratedValue
public int getTid() {
public void setTid(int tid) {
this.tid =
public String getTname() {
public void setTname(String tname) {
this.tname =
  生成数据库脚本:(和之前的单向多对多一样的表结构,关键看实体中控制权的变化)
create table Students (sid integer not null auto_increment, sname varchar(255), primary key (sid))create table Teachers (tid integer not null auto_increment, tname varchar(255), primary key (tid))create table teachers_students (sid integer not null, tid integer not null, primary key (sid, tid))
  基于xml的配置:
  其中一方:
&set name=&teachers& table=&students_teachers&&
&key column=&sid&&&/key&
&many-to-many class=&net.nw.vo.Teachers& column=&tid&/&
  另一方:
&set name=&students& table=&students_teachers&&
&key column=&tid&&&/key&
&many-to-many class=&net.nw.vo.Students& column=&sid&/&
  具体代码:
&hibernate-mapping&
&class name=&net.nw.vo.bfk.mtm.Students& table=&students&&
&id name=&sid& column=&sid& type=&int&&
&generator class=&native&/&
&property name=&sname& column=&sname& type=&string&/&
&set name=&teachers& table=&students_teachers& cascade=&all&&
&key column=&sid&/&
&many-to-many class= &net.nw.vo.bfk.mtm.Teachers& column=&tid&/&
&/hibernate-mapping&
---------------------------------------------------------------------
&hibernate-mapping&
&class name=&net.nw.vo.bfk.mtm.Teachers& table=&teachers&&
&id name=&tid& column=&tid& type=&int&&
&generator class=&native&/&
&property name=&tname& column=&tname& type=&string&/&
&set name=&stus& table=&students_teachers& cascade=&all&&
&key column=&tid&/&
&many-to-many class= &net.nw.vo.bfk.mtm.Students& column=&sid&/&
&/hibernate-mapping&
  注意:set元素配置;
  属性name& 指定类的属性名,table指定多对多关联关系中间表,cascade 级联操作属性:save-update、delete、all、none,一般all就ok,lazy属性可以指定是否是懒加载。set的子元素key元素——设定本表在中间表的外键名称。
  & inverse属性设置:
  inverse是Hibernate中双向关联关系中的基本概念,在xml配置里,用来设置关系由哪一方来维护,inverse=true 表示被控方,false表示主控方,在多对一,一对一关联关系中,Hibernate默认设置多方的inverse=true,即多方为被控方,一方的inverse=false,即一方为主控方。在多对多关系中需要我们自己设置哪一方为被控方即设置inverse=true。上述例子没有设置,其实需要手动设置的,对应注解里的mappedBy属性。
  关联关系的优缺点
  使用关联关系,就可以直接操作内存中的对象,不用每次都查询数据库,会提高效率;而且域模型真实反映了客观世界的关系,但是缺点就是 建立复杂的关联关系会给程序开发带来麻烦,当修改一个对象时,会牵连其它的对象,这也是为什么很多人说什么hibernate不好用……其实就是没学好,一般人掌握的不扎实,总出错,后来MyBatis横空出现,大家就去用它了,比起hibernate来,上手非常简单,使用原生SQL……本质不是一个真正的ORM架构模式的实现框架。当然Mybatis也有它的优点和缺点,以后再总结它。
具体要建立对象之间的什么关联关系要根据具体的需求。具体使用什么框架,要听领导的,哈哈。、
  问题小结
注意在多对一/一对多关系里:多方必须保留一个不带参数的构造器!
如果没有设置级联ALL,那么需要在保存的时候先保存班级,在保存学生,否则出错:&object references an unsaved transient instance - save the transient instance before flushing:&
多对一时候,多方设置EAGER加载,一对多的时候,一方设置LAZY加载
多对多关联,多方需要保留一个无参构造器。
文章署名:
文章地址:
优质IT资料分享网,由广大资源爱好者通过共享互助而共享各种学习资料,但本站无法保证所共享,资料的完整性和合理性
如果有资料对您的合法权益造成侵害,请立即联系我们处理

我要回帖

更多关于 hibernate 字段映射 的文章

 

随机推荐