hibernate中双向关联在级联情况下save对象讨论.docx_第1页
hibernate中双向关联在级联情况下save对象讨论.docx_第2页
hibernate中双向关联在级联情况下save对象讨论.docx_第3页
hibernate中双向关联在级联情况下save对象讨论.docx_第4页
hibernate中双向关联在级联情况下save对象讨论.docx_第5页
已阅读5页,还剩10页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

hibernate中双向关联在级联情况下save对象讨论一般在双向关联的情况下,都要在一方设置mappedBy(name=xxx),由对方主导映射关系。在多对一的情况下,一般在多的一方设置主导映射的关系(为了方便叙述,就这么叫它了,呵呵)。所谓主导这种映射关系,如group,user,就是由多的一方(user)里面产生一个外键参考一的一方(group)的主键,这时候user就是主导的一方,写mappedBy是被主导的一方。在多对多的情况下,随便由那方主导,在数据库表的结构上都是一样的,都会产生一个中间表,中间表有两个字段的联合主键,分别作为外键参考两个多的一方。在一对多和多对多的双向关联的情况下,并且在cascade=CascadeType.ALL情况下,save不同方面(如主导关系一方或被主导的一方)在级联的具体表现上是不同的。分别来讨论一下。先看一对多的双向关联关系,这里就拿group和user举例。Group类如下:javaview plaincopy1. packagecom.chen.hibernate.ormapping;2. 3. importjava.util.HashSet;4. importjava.util.Set;5. 6. importjavax.persistence.CascadeType;7. importjavax.persistence.Entity;8. importjavax.persistence.FetchType;9. importjavax.persistence.GeneratedValue;10. importjavax.persistence.Id;11. importjavax.persistence.OneToMany;12. importjavax.persistence.Table;13. 14. Entity15. Table(name=t_group)16. publicclassGroup17. privateintid;18. privateStringname;19. privateSetusers=newHashSet();20. 21. Id22. GeneratedValue23. publicintgetId()24. returnid;25. 26. 27. publicvoidsetId(intid)28. this.id=id;29. 30. 31. publicStringgetName()32. returnname;33. 34. 35. publicvoidsetName(Stringname)36. =name;37. 38. 39. /设置mappedBy是被主导的一方40. OneToMany(mappedBy=group,cascade=CascadeType.ALL,fetch=FetchType.LAZY)41. publicSetgetUsers()42. returnusers;43. 44. 45. publicvoidsetUsers(Setusers)46. this.users=users;47. 48. User类如下:javaview plaincopy1. packagecom.chen.hibernate.ormapping;2. 3. importjavax.persistence.CascadeType;4. importjavax.persistence.Entity;5. importjavax.persistence.FetchType;6. importjavax.persistence.GeneratedValue;7. importjavax.persistence.Id;8. importjavax.persistence.JoinColumn;9. importjavax.persistence.ManyToOne;10. importjavax.persistence.Table;11. 12. Entity13. Table(name=t_user)14. publicclassUser15. privateintid;16. privateStringname;17. privateGroupgroup;18. 19. Id20. GeneratedValue21. publicintgetId()22. returnid;23. 24. 25. publicvoidsetId(intid)26. this.id=id;27. 28. 29. publicStringgetName()30. returnname;31. 32. 33. publicvoidsetName(Stringname)34. =name;35. 36. 37. /设置fetch为lazy,多的一方默认问eager38. ManyToOne(cascade=CascadeType.ALL,fetch=FetchType.EAGER)39. JoinColumn(name=groupId)40. publicGroupgetGroup()41. returngroup;42. 43. 44. publicvoidsetGroup(Groupgroup)45. this.group=group;46. 47. junit测试类javaview plaincopy1. packagecom.chen.hibernate.ormapping;2. 3. importorg.hibernate.Session;4. importorg.hibernate.SessionFactory;5. importorg.hibernate.cfg.AnnotationConfiguration;6. importorg.hibernate.tool.hbm2ddl.SchemaExport;7. importorg.junit.AfterClass;8. importorg.junit.BeforeClass;9. importorg.junit.Test;10. 11. publicclassCRUDTest12. privatestaticSessionFactorysessionFactory=null;13. 14. BeforeClass15. publicstaticvoidbeforeClass()16. newSchemaExport(newAnnotationConfiguration().configure().create(17. false,true);18. sessionFactory=newAnnotationConfiguration().configure()19. .buildSessionFactory();20. 21. 22. Test23. publicvoidtestSaveUser()24. Useruser=newUser();25. user.setName(u1);26. Groupgroup=newGroup();27. group.setName(g1);28. 29. /这里仅仅把group加到user中,而不需要group.getUsers().add(user);把当前的对象加入到group的set里30. user.setGroup(group);31. 32. Sessionsession=sessionFactory.getCurrentSession();33. session.beginTransaction();34. session.save(user);35. session.getTransaction().commit();36. 37. 38. /再看看save被主导的一方会如何。39. Test40. publicvoidtestSaveGroup()41. /先new两个user,一个group,然后把user加到group中42. Useruser=newUser();43. user.setName(u1);44. 45. Useruser2=newUser();46. user2.setName(u2);47. Groupgroup=newGroup();48. group.setName(g1);49. group.getUsers().add(user);50. group.getUsers().add(user2);51. 52. /注意,虽然两边都是级联的方式,但這裡的user也要把group设一下,不然,save(group)的时候,user表中的53. /groupId字段仍是null54. user.setGroup(group);55. user2.setGroup(group);56. 57. Sessionsession=sessionFactory.getCurrentSession();58. session.beginTransaction();59. 60. /*61. *此时在save(group)的时候,由于级联关系会先插入里面的两个user,而此时如果不写上面的62. *user.setGroup(group);user2.setGroup(group);63. *这两句,user对应表里面的groupId字段都将为空64. */65. session.save(group);66. session.getTransaction().commit();67. 68. 69. AfterClass70. publicstaticvoidafterClass()71. sessionFactory.close();72. 73. 74. 先来个结论,什么时候t_user中的外键groupId才会参考t_group主键取得值?结论:这里的关系的主导方向是User-Group,只有当级联的方向也是从User-Group时,才会设置这个外键的值。这个结论可以参考这样的图:看下实验结果,先测试运行testSaveUser方法,运行结果对于的t_group和t_user表如下,此时数据插入都是正常的。插入的过程是应该是这样的,由于save的是user,所以先插t_user表,由于t_user表和t_group表的主键id字段都是由同一个sequence产生的,所以这里由主键id字段也可以看出先是插入了t_user,t_user中有group对象且不是null(要是null的话,即使设了级联,也不会再插t_group表了,没东西插入啊!),由于User设置了级联,所以此时又插入了t_group表,因为级联的方向为User-Group,和关系的主导方向相同,所以这里t_user表的groupId字段参考了t_group表的主键字段2。t_user表t_group表在测试下testSaveGroup,若先注掉user.setGroup(group);user2.setGroup(group);这两行,也就是说就像testSaveUser中一样,只是简单的把user加到group里的集合set里,会怎样呢?测试的结果如下:t_user表t_group表可以看到t_user表的groupId字段为空,为什么呢?同样按照上面的分析思路,由于save的是group,所以先插入t_group表,插入1,g1,而group对象中有一个user的集合,里面有两个user,由于级联,此时就会插入t_user表,此时级联的方向为Group-User,这个级联方向不会设置t_user中的groupId,因为上面注释掉了user.setGroup(group);user2.setGroup(group);这两句,也就是说这两个user中的group都为null,所以在插入t_user表的时候不会产生级联再插入t_group表了,所以t_user中两条记录的groupId字段都为空。把user.setGroup(group);user2.setGroup(group);这两句加上后,运行的结果如下,可以看到t_user表的groupId字段为1,参考了t_group的主键。这个执行的过程是这样的,先将group对象插入t_group表为1,g1,由于级联(Group-User)会将user和user2两个对象插入t_user表,当插user对象时候,user中的group字段不是一个null(是之前的group对象),所以又会发生级联,方向为(User-Group),此时又会将这个group对象插入到t_group表,将插入后的主键id的值设为t_user中插入user对象时的groupId的值,但是会发现这个group对象刚才已经插入过了,所以只是简单的将刚才插入group对象时的产生的主键id的值1给刚才的groupId值,最终将user插入到t_user中的记录为2,u1,1,上面的级联到重复插入那个group的时候就停止了,不会无穷的递归的进行下去。插入user2对象时,过程一样。可以从这个过程得到两个结论:(1)在同一个session中,同一个对象不会在数据库中插入两条不同的记录。(2)级联停止的条件为,对象里的关联字段为null或在一个表插队的对象已经被插入过。t_user表t_group表若把testSaveGroup()改为如下:javaview plaincopy1. Test2. publicvoidtestSaveGroup()3. /先new两个user,一个group,然后把user加到group中4. Useruser=newUser();5. user.setName(u1);6. 7. Useruser2=newUser();8. user2.setName(u2);9. Groupgroup=newGroup();10. group.setName(g1);11. group.getUsers().add(user);12. group.getUsers().add(user2);13. 14. /新new一个group2,把它加到user2对象里面,下面save(group)会发生什么呢?15. Groupgroup2=newGroup();16. group2.setName(g2);17. user2.setGroup(group2);18. 19. Sessionsession=sessionFactory.getCurrentSession();20. session.beginTransaction();21. session.save(group);22. session.getTransaction().commit();23. 再new一个group2,然后set到user2的group属性,这时测试会怎么样?可以设想一下,结果应该是这样的,由于save(group),所以先插入t_group表,在t_group中插入一条记录为1,g1,因为t_group中有一个集合,里面有两个user且都是非null的,所以会发生级联(方向为Group-User),会插入这两个user,这时候到底先插入哪一个user是不一定的,因为group中是个集合,假设按照add的顺序先插user,后插user2,那么在t_user表中会先插入一条记录2,u1,?,此时插入这条记录的时候由于user中的group为null,所以不会发生级联,所以这里记录的groupId为null,所以完整的是2,u1,null。接着插入user2对象,插入的记录为3,u2,?,这里的?暂时不定,user2中的group为非null(设了group2对象,注意这个group2之前没有被插入过),所以会发生级联插入t_group表,所以在t_group表中会插入4,g2,这条记录是由插入3,u2,?级联过来的(方向为User-Group),所以上面的?会参考这条记录的主键4,接着在t_group中插入4,g2的时候,因为这个group对象的集合set为null,所以不会发生级联,此时级联就收敛了。最终t_group和t_user表的情况应该是这样。t_user表2,u1,null3,u2,4t_group表1,g14,g2测试的结果如下,和预期是一样的。t_user表:t_group表:以上分析的是一对多的双向关联,采用这种分析的思路看能不能解释多对多的双向关联的结果,做如下实验,有两个类Teacher和Student类,他们时间是多对多的关系。多对多的关系会映射成三张表,一张中间表,这里产生的三张表为teacher(id,name),student(id,name),t_s(teacher_id,student_id),teacher_id和student_id作为t_s的联合主键,其中teacher_id参考了teacher表中的主键id,student_id参考了student表的主键id字段。其中关系的主导方向为Teacher-Student,此时中间表t_s可以看成teacher表中的一部分,只不过如果真的作为teacher表的一部分,teacher表中会多出很多冗余的字段,所以把它独立出来,只是我们可以参考一对多双向关联的情况下那样看它。所以只有级联的方向为teacher-student方向才会插入t_s表。Teacher类:javaview plaincopy1. packagecom.chen.hibernate.ormapping;2. 3. importjava.util.HashSet;4. importjava.util.Set;5. 6. importjavax.persistence.CascadeType;7. importjavax.persistence.Entity;8. importjavax.persistence.GeneratedValue;9. importjavax.persistence.Id;10. importjavax.persistence.JoinColumn;11. importjavax.persistence.JoinTable;12. importjavax.persistence.ManyToMany;13. 14. Entity15. publicclassTeacher16. privateintid;17. privateStringname;18. privateSetstudents=newHashSet();19. 20. Id21. GeneratedValue22. publicintgetId()23. returnid;24. 25. 26. publicvoidsetId(intid)27. this.id=id;28. 29. 30. publicStringgetName()31. returnname;32. 33. 34. publicvoidsetName(Stringname)35. =name;36. 37. 38. ManyToMany(cascade=CascadeType.ALL)39. JoinTable(name=t_s,joinColumns=JoinColumn(name=teacher_id,referencedColumnName=id),inverseJoinColumns=JoinColumn(name=student_id,referencedColumnName=id)40. publicSetgetStudents()41. returnstudents;42. 43. 44. publicvoidsetStudents(Setstudents)45. this.students=students;46. 47. Student类:javaview plaincopy1. packagecom.chen.hibernate.ormapping;2. 3. importjava.util.HashSet;4. importjava.util.Set;5. 6. importjavax.persistence.CascadeType;7. importjavax.persistence.Entity;8. importjavax.persistence.GeneratedValue;9. importjavax.persistence.Id;10. importjavax.persistence.ManyToMany;11. 12. Entity13. publicclassStudent14. privateintid;15. privateStringname;16. privateSetteachers=newHashSet();17. 18. Id19. GeneratedValue20. publicintgetId()21. returnid;22. 23. 24. publicvoidsetId(intid)25. this.id=id;26. 27. 28. publicStringgetName()29. returnname;30. 31. 32. publicvoidsetName(Stringname)33. =name;34. 35. 36. /设置Student类为被主导的类37. ManyToMany(mappedBy=students,cascade=CascadeType.ALL)38. publicSetgetTeachers()39. returnteachers;40. 41. 42. publicvoidsetTeachers(Setteachers)43. this.teachers=teachers;44. 45. junit测试类javaview plaincopy1. packagecom.chen.hibernate.ormapping;2. 3. importorg.hibernate.Session;4. importorg.hibernate.SessionFactory;5. importorg.hibernate.cfg.AnnotationConfiguration;6. importorg.hibernate.tool.hbm2ddl.SchemaExport;7. importorg.junit.AfterClass;8. importorg.junit.BeforeClass;9. importorg.junit.Test;10. 11. publicclasstestMany2ManyCRUD12. privatestaticSessionFactorysessionFactory=null;13. 14. BeforeClass15. publicstaticvoidbeforeClass()16. newSchemaExport(newAnnotationConfiguration().configure().create(17. false,true);18. sessionFactory=newAnnotationConfiguration().configure()19. .buildSessionFactory();20. 21. 22. Test23. publicvoidtestSaveStudent()24. /先new两个student和两个teacher,然后把两个student分别加到两个teacher里25. Studentstudent=newStudent();26. student.setName(s1);27. Studentstudent2=newStudent();28. student2.setName(s2);29. 30. Teacherteacher=newTeacher();31. teacher.setName(t1);32. Teacherteacher2=newTeacher();33. teacher2.setName(t2);34. student.getTeachers().add(teacher);35. student.getTeachers().add(teacher2);36. 37. student2.getTeachers().add(teacher);38. student2.getTeachers().add(teacher2);39. 40. /把这两个teacher分别加到两个student里,这是必须的,不然中间表t_s中不会有记录41. for(Teachert:student.getTeachers()42. t.getStudents().add(student);43. t.getStudents().add(student2);44. 45. 46. for(Teachert:student2.getTeachers()47. t.getStudents().add(student);48. t.getStudents().add(student2);49. 50. 51. Sessionsession=sessionFactory.getCurrentSession();52. session.beginTransaction();53. session.save(student);54. session.save(student2);55. session.getTransaction().commit();56. 57. 58. Test59. publicvoidtestSaveTeacher()60. /new两个teacher和student,在save(teacher)时,只需把两个student分别加到两个teacher中就可以了。61. /中间表t_s中也有数据62. Teacherteacher=newTeacher();63. teacher.setName(t1);64. Teacherteacher2=newTeacher();65. teacher2.setName(t2);66. 67. Studentstudent=newStudent();68. student.setName(s1);69. Studentstudent2=newStudent();70. student2.setName(s2);71. 72. teacher.getStudents().add(student);73. teacher.getStudents().add(student2);74. teacher2.getStudents().add(student);75. teacher2.getStudents().add(student2);76. 77. Sessionsession=sessionFactory.getCurrentSession();78. session.beginTransaction();79. session.save(teacher);80. session.save(teacher2);81. session.getTransaction().commit();82. 83. 84. AfterClass85. publicstaticvoidafterClass()86. sessionFactory.close();87. 88. 先运行testSaveStudent(),若先把中间的两个for循环注释掉,运行的结果如下:student表:teacher表:t_s表为空,没有数据,不贴了。为什么会出现这样的结果呢?分析一下这个执行的过程,首先save(student),所以先向student表中插入一条记录1,s1,由于student中的又一个teacher的set里有teacher和teacher2且都不为null,所以这会发生级联,方向为Student-Teacher,这个方向主导的关系方向不同,所以不会像t_s表中试图插入数据,这时候直接把teacher对象插入到teacher表中,需要注意的是,先插入哪个对象是不定的,看上面teacher表的截图可知,先插入了teacher2,因为注释掉了那两个for循环,所以两个teacher对象里的set里面没有student,所以此时就不会发生级联了。然后以同样的过程插入了student,这样teacher表就有如图所示的两条记录,至此,save(student)就执行完了。接

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论