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

 

 欢迎关注个人公众号一起交流学习: