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(); } }