Hibernate学习_014_级联关系中的CRUD操作

来源:互联网 发布:mac口红专柜多少钱一支 编辑:程序博客网 时间:2024/05/01 12:44

前面几篇文章说过,关联关系反映的只是编程模型的变化,在数据库表层面是没有变化的,下面我们以Group和User的一对多双向关联来说明关联关系中CRUD操作要注意的几点事项:

首先给出Group和User的定义。

Group.java:

@Entity@Table(name="t_group")public class Group {private int id;private String name;private Set<User> users = new HashSet<User>();@Id@GeneratedValuepublic int getId() {return id;}public void setId(int id) {this.id = id;}@OneToMany(mappedBy="group",cascade=CascadeType.ALL,fetch=FetchType.EAGER)public Set<User> getUsers() {return users;}public void setUsers(Set<User> users) {this.users = users;}public String getName() {return name;}public void setName(String name) {this.name = name;}}

User.java:

@Entity@Table(name="t_user")public class User {private int id;private String name;private Group group;@Id@GeneratedValuepublic int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@ManyToOne(cascade=CascadeType.ALL)@JoinColumn(name="group_id")public Group getGroup() {return group;}public void setGroup(Group group) {this.group = group;}}

下面就上面POJO为例说明CRUD中要注意的几点事项:

第一:POJO中不论是@ManyToOne还是@OneToMany,其中的cascade属性都不是必须的,只是说有了它,我们编程会比较方便。不用手动去对关联对象去做CRUD操作。

第二:双向关联中,默认是不会保存关联对象的,除非在关联对象中设置cascade属性来进行级联,比如说,我们设置了创建了一个新的Gruop对象,并且对其关联属性值进行了设置,但是Group中的@OneToMany并没有设置cascade属性,这个时候,我们保存创建的Gruop对象的时候,是不会保存关联的User对象的。解决方式就是在Group的@OneToMany设置cascade为ALL或者是PERSIST即可。

第三:由于一对多双向关联,数据库表级别上看,会在多的一端加上一个外键,在上面第二点的基础上,我们会发现,即使我们的Group的@OneToMany设置cascade为ALL或者是PERSIST,在保存Gruop对象时,确实可以保存关联着的User对象了,但是,User表中的Group_id却为NULL,这是因为凡是双向关联,程序中必须在两个方向上都把关联关系设置好,这样才可以在数据库级别保存对象之间的关联关系【只要是双向关联,必须这样做,这是一条最佳实践!】。比如保存的时候,不仅仅要设置Group.setUser(XXX),还要设置User.setGroup(XXX)才可以保证在数据库也是正常的。

第四:在@ManyToOne或者是@OneToMany中,常常会设置两个属性,一个是cascade,一个是fetch。尤其注意,对于CRUD来说,cascade属性主要负责的是CUD的关联,而fetch负责的是R操作的关联。比如,要控制不使用懒加载,即使设置为CascadeType.ALL也不可以,一定要设置FetchType.LAZY才行,在XML方式中,如果要在Group中设置懒加载,方法是在Group所对应的XML文件中,通过inverse="true"来设置的。

第五:注意在一对多双向关联中,默认的,在加载多的一端,默认模式fetch=FetchType.EAGER,而在加载一的一端的时候,模式默认为fetch=FetchType.LAZY。其他关联关系依次类推。

第六:任何时候,凡是要去数据库取数据的话,就一定要和特定的session关联,否则报错,比如我们在Group设置懒加载,取出Group后,关闭session,这个时候,如果用到了Group中的User对象的话,就会到数据库中取数据,这个时候,由于Session已经关闭,所以报错。

第七:在更新和删除一个对象的时候,除非是确切的知道要删除数据的ID是什么,否则都应该先加载,看对象是否存在,然后在删除。

第八:对于一个很有意思的现象的剖析:现象描述:在User和Group中我们设置cascade=CascadeType.ALL。我们假设有group1,user1,user2三个对象,同时user1,user2属于group1,这个时候,我们删除user1,我们发现一个很有趣的现象就是group1,user2也同时删除了。剖析:原因是,因为我们在删除user1的时候,由于级联关系式ALL,所以此时会出删除user1关联着的group1,但是这个时候,group1同时又关联着user2,所以user2 也被删除。解决方式:方法A:将User的级联关系不要设置为ALL。方法B:打破这种级联关系,经过测试,双向关联中要从双向去打破这种关联关系,仅仅从User打破于Gruop的关系式不可以的。方法C:使用HQL,可以成功删除特定的user1,而且可以保证不会删除关联着的group1对象,但是经过测试表明,使用HQL来删除Group对象的时候,由于有关联对象的存在,是不可以删除的。

第九:总结:其实O/R Mapping编程模型 ,细分两大分支,一支是映射模型(4大类:JPA Annotation、Hibernate extended Annotation、Hibernate XML、JPA XML),一支是编程接口(两大类:JPA、Hibernate),hibernate中常用的是Hibernate的编程接口组合JPA Annotation的映射模型。比如说在Hibernate接口中的Sesison接口在JPA中与之对应的是EntityManager接口, 这个接口中有很多的方法,比如persist、merge、remove,在Hibernate中与之对应的是save和delete方法。不过hibernate标准正在和JPA标准趋于统一,严格来说,JPA标准是Hibernate标准的子集。所以这样理解EJBQL(JPQL)是HQL的子集也是可以的。

0 0
原创粉丝点击