hibernate关联关系的CRUD操作,解释都在注释里了,讲了fetchType、cascade。
User类:
package com.oracle.hibernate; import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne; @Entity
public class User { private int id;
private String name;
private Group group; //多对一
@ManyToOne(cascade={CascadeType.ALL}//, //设置级联
//fetch = FetchType.LAZY
)
@JoinColumn(name="groupId")//指定外键名称
public Group getGroup() {
return group;
}
public void setGroup(Group group) {
this.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;
} }
Group类:
package com.oracle.hibernate; import java.util.HashSet;
import java.util.Set; import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table; @Entity
@Table(name="t_group")//group是mysql的关键字,换个名
public class Group { private int id;
private String name;
private Set<User> users = new HashSet<User>(); //设置mappedBy和级联
@OneToMany(mappedBy="group",
cascade={CascadeType.ALL}//,//级联管增删改, //fetch=FetchType.EAGER //一的一方默认为LAZY
)
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
@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;
} }
测试类:
package com.oracle.hibernate; import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.junit.AfterClass;
import org.junit.BeforeClass; public class Test { private static SessionFactory sf = null;
@BeforeClass
public static void beforeClass(){ try {
//生成表
new SchemaExport(new AnnotationConfiguration().configure()).create(false, true);
sf = new AnnotationConfiguration().configure().buildSessionFactory();
} catch (HibernateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} @org.junit.Test
public void testSchemaExport(){
new SchemaExport(new AnnotationConfiguration().configure()).create(false, true); }
@AfterClass
public static void afterClass(){
sf.close();
} @org.junit.Test
public void testSaveUser(){ Session s = sf.getCurrentSession();
s.beginTransaction();
User user = new User();
user.setName("u1");
Group g = new Group();
g.setName("g1");
user.setGroup(g);
//s.save(g);默认不会自动保存关联变量,
//设置cascade后,直接保存user就能把user的group也保存
s.save(user);
s.getTransaction().commit();
} @org.junit.Test
public void testSaveGroup(){ Group g = new Group();
g.setName("g1");
User u1 = new User();
u1.setName("u1");
//必须设定User所属的group,否则在保存user时不会保存g的信息(hibernate不知道属于哪个group啊)
u1.setGroup(g);
User u2 = new User();
u2.setName("u2");
u2.setGroup(g);
g.getUsers().add(u1);
g.getUsers().add(u2); Session s = sf.getCurrentSession();
s.beginTransaction(); s.save(g);
s.getTransaction().commit();
} @org.junit.Test
public void testGetUser(){
testSaveGroup();//生成数据 Session s = sf.getCurrentSession();
s.beginTransaction();
/**
* 默认情况,多的一方的fetchType=Eager,这符合正常思维,比如我们取学生时也会把他的老师取出来。
* 设置多的一方User里设fetchType=Lazy时(很少这么干),执行下边的代码发出的sql语句是:
* Hibernate:
select
user0_.id as id2_0_,
user0_.groupId as groupId2_0_,
user0_.name as name2_0_
from
User user0_
where
user0_.id=?
不会把一的一方Group给取出来,只有当用到group的时候(如下边的取u.getGroup.getName)才发sql语句把User和group连接查询
*
*/
User u = (User) s.get(User.class,1);
//取User,默认情况下,不设cascade,也能取出group,这符合平常逻辑。
System.out.println(u.getName()+u.getGroup().getName());
s.getTransaction().commit(); //System.out.println(u.getName()+u.getGroup().getName());
//会报错,因为fetchType为Lazy,用group的时候才发sql语句,而session却关了,所以报错(懒加载错误)
} @org.junit.Test
public void testGetGroup(){
testSaveGroup();//生成数据 Session s = sf.getCurrentSession();
s.beginTransaction();
//取group一方,fetchType默认为Lazy,执行下边的一句话:
//不发取user的sql语句,只发取group的信息的sql。不取多的一方,只有用到user信息时才发sql'语句,下边的g.getUsers()XXX
Group g = (Group) s.get(Group.class,1);
s.getTransaction().commit();
//设置fetchType为EAGER,发的sql语句把user也取出来了,所以即使session关了,也能取出User(从内存)而不报错
System.out.println(g.getName()+g.getUsers());
} @org.junit.Test
public void testLoadUser(){
testSaveGroup();//生成数据 Session s = sf.getCurrentSession();
s.beginTransaction();
//get拿的是User对象,load,拿的是user的代理对象,
//执行下边的代码不会发sql语句,当getGroup时才发sql语句
User u = (User) s.load(User.class,1); //执行此句时先发出sql语句取user,再发sql语句取user和group,发了2条select
System.out.println(u.getName()+u.getGroup().getName());
s.getTransaction().commit(); } @org.junit.Test
public void testUpdateUser1(){
testSaveGroup();//生成数据 Session s = sf.getCurrentSession();
s.beginTransaction();
/**
* 发的sql语句:
* 因为 u.getName()+u.getGroup().getName()既取了u。name,又取了u.的group的name,所以
* 发的select语句取了user和group,
* Hibernate:
select
user0_.id as id2_1_,
user0_.groupId as groupId2_1_,
user0_.name as name2_1_,
group1_.id as id3_0_,
group1_.name as name3_0_
from
User user0_
left outer join
t_group group1_
on user0_.groupId=group1_.id
where
user0_.id=?
//但是为什么还会发出下边的select 语句呢?因为group的fetchType设的EAGER,
* 在u.getGroup().getName()的同时,也会发sql语句去取user的信息。所以不能同时两边设EAGER
* 一般正常人思维去思考:一般:一对多设lazy,多对一设eager。
* 但是假设一个人有多个权限,可以设一对多为eager。公司机构、部门可以用。
Hibernate:
select
users0_.groupId as groupId1_,
users0_.id as id1_,
users0_.id as id2_0_,
users0_.groupId as groupId2_0_,
users0_.name as name2_0_
from
User users0_
where
users0_.groupId=?
* 可以看到先发的select语句取user和group,又取的user()
*/
User u = (User) s.load(User.class,1);
u.setName("user");
u.getGroup().setName("group");
System.out.println(u.getName()+u.getGroup().getName());
s.getTransaction().commit(); } @org.junit.Test
public void testUpdateUser2(){
testSaveGroup();//生成数据 Session s = sf.getCurrentSession();
s.beginTransaction(); User u = (User) s.get(User.class,1);
s.getTransaction().commit();//关闭session,而u已经在内存中。 u.setName("user");//修改user姓名
u.getGroup().setName("group");//修改group Session s2 = sf.getCurrentSession();
s2.beginTransaction();
s2.update(u); //group和user同时更新,user里cascade起的作用
s2.getTransaction().commit(); }
@org.junit.Test
public void testDeleteUser(){
testSaveGroup();//生成表user:u1 u1.group: g u2.group:g group:g Session s = sf.getCurrentSession();
s.beginTransaction();
User u = (User) s.load(User.class, 1);
// 级联:会把u1删掉,再把u1指向的group:g删了,g删了,他所关联的u2也没了。
//s.delete(u);
//解决办法:先解除关联关系,把u的group设成null,再删除
u.setGroup(null);
s.delete(u);
//用hql:
//s.createQuery(" from User u where u.id = 1");
s.getTransaction().commit();
} @org.junit.Test
public void testDeleteGroup(){
testSaveGroup();//生成表user:u1 u1.group: g u2.group:g group:g Session s = sf.getCurrentSession();
s.beginTransaction(); Group g = (Group) s.load(Group.class,1);
//外键指向g的 user 都会被删掉。如果不想删,可以把User的group都设成null,不过这些数据也就成了垃圾数据。
s.delete(g);
s.getTransaction().commit();
}
}