hibernate学习笔记(五)
接着上一篇的说hibernate关联映射关系中的一对多单向的,一对多怎么说呢?很多很多的这样的例子,一个班级多个学生,一个发票抬头下面有多间物品等等,一对多单向的就是通过一得一端来获取多的一端的信息。
一对多和多对一大体上查不了多少,多对一是由多的一端来控制关系,那么一对多就是一得一端来控制关系。那么怎么来实现呢,其实只需要在一得一端加一个set<T>属性即可,T代表的就是多的一端的实体类,配置OneToMany即可。下面上例子(才看到有插入代码的,不用那么麻烦的上传图片了):
1 package com.demo.modal; 2 3 import java.util.HashSet; 4 import java.util.Set; 5 6 import javax.persistence.Column; 7 import javax.persistence.Entity; 8 import javax.persistence.GeneratedValue; 9 import javax.persistence.GenerationType; 10 import javax.persistence.Id; 11 import javax.persistence.JoinColumn; 12 import javax.persistence.OneToMany; 13 import javax.persistence.Table; 14 15 import org.hibernate.annotations.Cascade; 16 import org.hibernate.annotations.CascadeType; 17 18 19 @Entity 20 @Table(name="per_inf") 21 public class Person { 22 23 @Id 24 @Column(name="per_id",length=4) 25 @GeneratedValue(strategy=GenerationType.IDENTITY) 26 private Integer id; 27 private String name; 28 private int age; 29 30 @OneToMany(targetEntity=Address.class) 31 @Cascade(CascadeType.ALL) 32 @JoinColumn(name="person_id",referencedColumnName="per_id") 33 private Set<Address> address=new HashSet<Address>(); 34 35 public Integer getId() { 36 return id; 37 } 38 39 public void setId(Integer id) { 40 this.id = id; 41 } 42 43 public String getName() { 44 return name; 45 } 46 47 public void setName(String name) { 48 this.name = name; 49 } 50 51 public int getAge() { 52 return age; 53 } 54 55 public void setAge(int age) { 56 this.age = age; 57 } 58 59 public Set<Address> getAddress() { 60 return address; 61 } 62 63 public void setAddress(Set<Address> address) { 64 this.address = address; 65 } 66 67 68 69 }
这个例子要说一下啊,本人是个懒人,上一个例子的Person是多的一端,这个里面却是一得一端,一个人也可以有多个地址嘛,老家啊,现住址啊等等,主要是为了COPY代码方便,大家理解下啊。
接着说一对多,在一得一端加上private Set<Address> address=new HashSet<Address>();这行代码之后即可,具体的配置可以采用注解的方式,也可以采用配置文件的方式,都是可以的。当然级联操作的话还是离不开 @Cascade(CascadeType.ALL)的哦。
和多对一单向一样,一对多单向也是可以采用两个表直接关联或者添加第三方表的方式关联的。
对了,差点忘记说了一件事,大家看下面的一端代码:
package com.demo.junit; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.demo.modal.Address; import com.demo.modal.Person; import com.demo.util.SessionFactoryUtil; public class PersonTest { private SessionFactory sessionFactory=SessionFactoryUtil.getSessionFactory(); private Session session; private Transaction tx; @Before public void setUp() throws Exception { session=sessionFactory.openSession(); tx=session.beginTransaction(); } @After public void tearDown() throws Exception { tx.commit(); session.close(); } @Test public void test() { Person p=new Person(); Address a1=new Address("Peking chaoyang"); session.persist(a1); p.setName("John"); p.setAge(21); p.getAddress().add(a1); session.persist(p); Address a2=new Address("Peking changping"); session.persist(a2); p.getAddress().add(a2); } }
上面程序中session.persist(p);持久化了一个person对象,并且person对象关联了一个address对象,此时hibernate需要执行哪些事情呢?
首先,执行了insert into per_inf。。。。语句,向Person表中插入一条语句,然后hibernate视图执行update add_inf ....语句,将当前per_inf表记录关联的add_inf表记录的外键修改为per_inf记录的主键值,但是问题来了,如果add_inf表中将要修改的记录不存在呢(把级联的注解去掉,然后把session.persist(a1)注释掉就可以看到这种情况)?在有级联的情况下我们可以看到执行情况:
从上面可以看出,虽然只需要为person尸体增加一个关联Address实体,但是hibernate却执行了两条SQL语句,一条是插入一条外键为NULL的add_inf记录,一条是修改刚刚插入的记录,一个操作却要执行两条SQL语句,这个肯定会对系统的性能造成一定的影响,造成这个现象的根本原因就是从person到address的关联没有被当做address对象状态的一部分,因此hibernate无法执行insert into add_inf....语句时为该外键咧指定值。
解决这个问题的办法就是在程序持久化Address实体之前让Address实体能够知道它所关联的person实体,也就是通过address.setPerson(p)方法来建立关联关系,这就需要把这个关联关系添加到address的映射中---变成了一对多的双向。
对于双向的一对多父子关联,使用1的一端控制关系的性能比使用多的一端控制关系的性能要低,这是因为当使用1的一端控制关系时候,由于插入数据时无法同时插入外键咧,因此会额外的产生一条update语句,而且外键咧还无法增加非空约束,因为添加关联实体时,总会先插入一条外键咧为NULL的记录。
万一长须必须采用单向的一对多关系,也可以采用有链接表的一对多关系。
终于写完了,上面一部分内容是看李刚的书上的内容,因为本人“语死早”啊,这个总结能力有限,所以直接采用了别人的话,见谅。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。