首页 > 代码库 > Hibernate中关联关系的CRUD(增删改查)
Hibernate中关联关系的CRUD(增删改查)
关联关系的CRUD(增删改查)
一、增加数据
1、User和Group的关联关系:User对Group是Many-To-One,Group对User是One-To-Many
2、默认情况下,不会自动保存尚未保存关联的对象。因为对象没有保存的情况下,对象是Transient状态,此时数据库中并没有存储,所以获取不到该对象。
3、使用级联cascade方式可以自动将关联的对象进行存储。其取值有ALL,PERSIST,REFRESH,REMOVE,DETACH,MERGE这几种取值。其中,ALL表示在任何情况下进行级联操作。PERSIST表示持久化的时候进行级联。
3、实验1(只保存User对象的情况下,自动保存Group)
Group.java
package com.zgy.hibernate.model;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name="t_group")
public class Group {
private int id;
private String name;
private Set<User> users = new HashSet<User>();
@Id
@GeneratedValue
public 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;
}
@OneToMany(mappedBy="group")
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
}
4、User.java
package com.zgy.hibernate.model;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity
@Table(name="t_user")
public class User {
private int id;
private String name;
private Group group;
@Id
@GeneratedValue
public 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})
public Group getGroup() {
return group;
}
public void setGroup(Group group) {
this.group = group;
}
}
5、JUnit测试
package com.zgy.hibernate.model;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
public class ORMapppingTest {
public static SessionFactory sf = null;
@BeforeClass
public static void beforeClass(){
Configuration configure =new Configuration().configure();
new SchemaExport(configure).create(true, true);
sf = configure.buildSessionFactory();
}
@Test
public void testSaveUser() {
User user = new User();
user.setName("user1");
Group group = new Group();
group.setName("group");
user.setGroup(group);
Session s = sf.openSession();
s.beginTransaction();
//s.save(group);
s.save(user);
s.getTransaction().commit();
}
@AfterClass
public static void afterClass(){
sf.close();
}
}
6、结果:
(1)不保存group的情况下,运行JUnit会报错
(2)在User.java中加入@ManyToOne(cascade={CascadeType.ALL}),那么再次运行JUnit时将不会再报错。
(3)查看生成的sql语句:
Hibernate: create table t_group (id integer not null auto_increment, name varchar(255), primary key (id))
Hibernate: create table t_user (id integer not null auto_increment, name varchar(255), group_id integer, primary key (id))
Hibernate: alter table t_user add constraint FK_e5f24mh6aryt9hsy99oydps6g foreign key (group_id) references t_group (id)
Hibernate: insert into t_group (name) values (?)
Hibernate: insert into t_user (group_id, name) values (?, ?)
7、实验2(仅保存Group对象的情况下,自动保存User)
(1)修改Group.java
package com.zgy.hibernate.model;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.CascadeType;
@Entity
@Table(name="t_group")
public class Group {
private int id;
private String name;
private Set<User> users = new HashSet<User>();
@Id
@GeneratedValue
public 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;
}
@OneToMany(mappedBy="group",
cascade={CascadeType.ALL}
)
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
}
(2)去除User.java中加入的cascade={CascadeType.ALL}这段Annotation
package com.zgy.hibernate.model;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity
@Table(name="t_user")
public class User {
private int id;
private String name;
private Group group;
@Id
@GeneratedValue
public 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
public Group getGroup() {
return group;
}
public void setGroup(Group group) {
this.group = group;
}
}
(3)测试
要建立User和Group两者的双向关系,并且只保存Group对象
package com.zgy.hibernate.model;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
public class ORMapppingTest {
public static SessionFactory sf = null;
@BeforeClass
public static void beforeClass(){
Configuration configure =new Configuration().configure();
new SchemaExport(configure).create(true, true);
sf = configure.buildSessionFactory();
}
@Test
public void testSaveUser() {
User user1 = new User();
user1.setName("user1");
User user2 = new User();
user2.setName("user2");
Group group = new Group();
group.setName("group1");
group.getUsers().add(user1);
group.getUsers().add(user2);
user1.setGroup(group);
user2.setGroup(group);
Session s = sf.openSession();
s.beginTransaction();
s.save(group);
//s.save(user);
s.getTransaction().commit();
}
@AfterClass
public static void afterClass(){
sf.close();
}
}
(4)观察结果
生成的SQL语句:
create table t_group (
id integer not null auto_increment,
name varchar(255),
primary key (id)
)
create table t_user (
id integer not null auto_increment,
name varchar(255),
group_id integer,
primary key (id)
)
alter table t_user
add constraint FK_e5f24mh6aryt9hsy99oydps6g
foreign key (group_id)
references t_group (id)
查看数据库中的信息:
select * from t_group;
select * from t_user;
数据保存成功。
8.双向关系在程序中要设置双向关联
9.双向关系要使用mappedBy
二、读取数据
还是一上面的例子做说明
1、读取User数据,是否能读取Group中的数据?
2、ManyToOne默认的情况下是可以取出One里的数据的,也就是说,获取User对象的数据的时候,是可以获取Group对象中的数据的。
3、读取Group数据的时候,是否能读取User中的数据?
4、cascade并不会影响读取,fetch管理读取
5、fetch的属性是Enum类型,分别为LAZY,EAGER。取值为LAZY时,不会获取User中的数据;取值为EAGER时,可以获取User的数据
6、JPA接口默认为一对多为Lazy,多对一为Eager,但是Hibernate反向工程生成Entity时,多对一为Lazy,需要手动改为Eager。
7、实验:
8、Group.java
package com.zgy.hibernate.model;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.CascadeType;
@Entity
@Table(name="t_group")
public class Group {
private int id;
private String name;
private Set<User> users = new HashSet<User>();
@Id
@GeneratedValue
public 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;
}
@OneToMany(mappedBy="group",
cascade={CascadeType.ALL},
fetch=FetchType.EAGER
)
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
}
9、User.java
package com.zgy.hibernate.model;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity
@Table(name="t_user")
public class User {
private int id;
private String name;
private Group group;
@Id
@GeneratedValue
public 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},
fetch=FetchType.LAZY
)
public Group getGroup() {
return group;
}
public void setGroup(Group group) {
this.group = group;
}
}
10、JUnit测试
@Test
public void testGetUser() {
testSaveGroup();
Session s = sf.openSession();
s.beginTransaction();
User u = (User)s.get(User.class, 1);
s.getTransaction().commit();
}
@Test
public void testGetGroup() {
testSaveGroup();
Session s = sf.openSession();
s.beginTransaction();
Group g = (Group)s.get(Group.class, 1);
s.getTransaction().commit();
for(User u : g.getUsers()){
System.out.println(u.getName());
}
}
11、结论
(1)将User设置为@ManyToOne(cascade={CascadeType.ALL},fetch=FetchType.LAZY的时候,将不再取得Group的属性。在session关闭前,如果使用到Group属性还是可以手动取得。Session关闭后将去得到Group的属性。
(2)@ManyToOne(cascade={CascadeType.ALL},fetch=FetchType.LAZY的时候,先取出的是User,再取出的是两者之间的关系。
Hibernate: select user0_.id as id1_1_0_, user0_.group_id as group_id3_1_0_, user0_.name as name2_1_0_ from t_user user0_ where user0_.id=?
Hibernate: select group0_.id as id1_0_0_, group0_.name as name2_0_0_, users1_.group_id as group_id3_0_1_, users1_.id as id1_1_1_, users1_.id as id1_1_2_, users1_.group_id as group_id3_1_2_, users1_.name as name2_1_2_ from t_group group0_ left outer join t_user users1_ on group0_.id=users1_.group_id where group0_.id=?
(3)@ManyToOne(cascade={CascadeType.ALL},fetch=FetchType.EAGER的时候,先取出的是关系,然后取出的是User
Hibernate: select user0_.id as id1_1_0_, user0_.group_id as group_id3_1_0_, user0_.name as name2_1_0_, group1_.id as id1_0_1_, group1_.name as name2_0_1_ from t_user user0_ left outer join t_group group1_ on user0_.group_id=group1_.id where user0_.id=?
Hibernate: select users0_.group_id as group_id3_0_0_, users0_.id as id1_1_0_, users0_.id as id1_1_1_, users0_.group_id as group_id3_1_1_, users0_.name as name2_1_1_ from t_user users0_ where users0_.group_id=?
(4)两边都设置EAGER的时候,会发出两次select语句。所以,一般是在一遍设置EAGER就可以了。
三、更新数据
1.cascade={CascadeType.ALL}的时候,默认会级联。因此在修改User属性的时候,会修改Group的属性。例如:
@Test
public void testUpdateUser() {
testSaveGroup();
Session s = sf.openSession();
s.beginTransaction();
User u = (User)s.load(User.class, 1);
u.setName("user");
u.getGroup().setName("ggg");
s.getTransaction().commit();
}
此处修改了Group的name属性,因此,在更新User对象的时候,会更新Group对象的属性。
如下SQL语句说明了以上观点:
Hibernate: update t_user set group_id=?, name=? where id=?
Hibernate: update t_group set name=? where id=?
2.在User.java中,配置cascade={CascadeType.MERGE},此时在JUnit中,使用merge()方法后,将会产生级联,即只保存User对象的情况下,会自动保存Group对象。使用merge()来合并两个session中的同一对象。
以下是JUnit中的测试方法
@Test
public void testUpdateUser() {
testSaveGroup();
Session s = sf.getCurrentSession();
s.beginTransaction();
User u = (User)s.get(User.class, 1);
s.getTransaction().commit();
u.setName("u");
u.getGroup().setName("g");
Session s2 = sf.getCurrentSession();
s2.beginTransaction();
s2.merge(u);
s2.getTransaction().commit();
}
同理,设置cascade的值的时候,在session中使用对应的方法将可以实现级联操作。
四、删除数据
1、ORMapping编程模型:
|映射模型
|以Hibernate为例
|jpa annotation
|Hibernate annotation extension
|Hibernate xml
|jpa xml
|接口编程
|jpa编程接口
|Hibernate
2、@Test
public void testDeleteUser() {
testSaveGroup();
Session s = sf.openSession();
s.beginTransaction();
User u = (User)s.load(User.class, 1);
s.delete(u);
s.getTransaction().commit();
}
如下的测试方法会删除User和Group中的所有数据。原因是因为两者是级联关系。User.java中设置的@ManyToOne(cascade={CascadeType.ALL},Group.java中设置的是@OneToMany(mappedBy="group",
cascade={CascadeType.ALL},所以删除User的时候会关联到该User对象的Group属性,从而删除该Group属性,而Group属性又关联了User属性,所以又会删除User的内容,从而导致了删除了两张表中的全部内容。
3.解决如上的问题的方法是消除关联关系,再进行删除。
@Test
public void testDeleteUser() {
testSaveGroup();
Session s = sf.openSession();
s.beginTransaction();
User u = (User)s.load(User.class, 1);
u.setGroup(null);
s.delete(u);
s.getTransaction().commit();
}
查看生成的SQL语句:
Hibernate: delete from t_user where id=?
还有一种方式就是使用HQL语句:
s.createQuery("delete from User where u.id = 1").executeUpdate();
也可以达到效果。
4.想要消除关联关系,先设定关系为null,在删除对应的记录。如果不删除记录,那么该记录就会变为垃圾数据。
Hibernate中关联关系的CRUD(增删改查)