hibernate 数据关联一对多

一对多,多对一 (在多的一端存放一的外键)
但是在实体类中不需要创建这个外键

// 在一的一方创建Set集合
public class User {
    
    private Integer id;
    private String username;
    private String password;
    private Set<Address> addressSet;
}
//多的一方创建User的对象
public class Address {

    private Integer id;
    private String address;
    private User user;
}

在映射文件中也要配置

一对多的一:User.hbm.xml中

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.kaishengit.pojo">
    
    <class name="User" table="user">
        <id name="id">
            <generator class="native"/>
        </id>
        
        <property name="username"/>
        <property name="password"/>
        <!-- name是类中属性的名字,站在User的角度这是一对多,所以是one-to-many
             然后指定对应的多指的是哪个类.
             <key column="userid"/>指维持这种关系的多的这一端(Address)类对应的表中的外键
             inverse="true"表示放弃关系维护-->
        <set name="addressSet" cascade="delete" inverse="true">
            <key column="userid"/>
            <one-to-many class="Address"/>
        </set>
        
    </class>
</hibernate-mapping>

一对多的多:Address.hbm.xml中

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.kaishengit.pojo">
    
    <class name="Address" table="address">
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="address"/>
        <!-- 站在这个角度是多对一many-to-one
            name写对应的属性名,class是对应的类 然后指定外键-->
        <many-to-one name="user" class="User" column="userid"/>
        
    </class>
    

</hibernate-mapping>

--------------------------------------------------------------------------

--------------------------------------------------------------------------

程序的执行

1.添加

//  方式1
        User u1 = new User();
        u1.setUsername("u1");
        u1.setPassword("aaa");
        
        Address a1 = new Address();
        a1.setAddress("a1");
        a1.setUser(u1);
        
        Address a2 = new Address();
        a2.setAddress("a2");
        a2.setUser(u1);
    
        /* 如果是先save的u1,就能拿到u1的id
        然后再save a1,a2的时候加入外键中,等于执行了3条sql
        
        
        如果是先save  a1,a2 那么save的结果是没有userid这个外键的
        在save了u1之后会再去update他们(因为在address关联User的时候,user是自由态
        ,当user保存的时候就变成了持久态,User状态发生变化会同步到数据库中,所以address会更新
        ),等于执行了3条sql还有两条update*/
        session.save(u1);
        session.save(a1);
        session.save(a2);




// 所以对于一对多的这种情况,先存1,再存多



 //  方式2 

        User u1 = new User();
        u1.setUsername("u1");
        u1.setPassword("aaa");
        
        Address a1 = new Address();
        a1.setAddress("a1");
        
        
        Address a2 = new Address();
        a2.setAddress("a2");
        
        Set<Address> set = new HashSet<Address>();
        set.add(a1);
        set.add(a2);
        user.setAddressSet(set);

   // 这样即使是先存1再存多还是5条sql语句 

        session.save(u1);
        session.save(a1);
        session.save(a2);

所以在一对多的时候,关系要让多来维护,save的时候先保存一的再保存多的

可以在一的配置中inverse="true"放弃关系维护

2.查询

// 单表查询user 
        User user = (User) session.get(User.class, 25);
        System.out.println(user.getUsername());
        /* 要使用address了,单表查询address,这个是延迟查询,当使用address的时候再去查
            ,但是这个查询就必须放在session中才能有作用,给xxx.hbm.xml配置
            lazy="false" 就能取消这个延迟查询,不管你用不用address,但是只要你用user我都会查关联user
            的一切比如(address,这个时候就可以放在session外边了因为查询过后已经放入了内存中*/
        Set<Address> set = user.getAddressSet();
        for(Address a : set) {
            System.out.println(a.getAddress());
        }

    // 或者反过来用address查询,也都是两条单表查询
        Address a1 = (Address) session.get(Address.class, 17);
        System.out.println(a1.getAddress());
        System.out.println(a1.getUser().getUsername());

hibernate默认就是这样的单表查询,但是我们可以改成联接查询 -->
<!-- 添加fetch="join"表示用一条sql语句查询到所有包括关联的..所以只要不是
你能承受这么多查询,都要使用以前的延迟查询

<set name="addressSet" cascade="delete" inverse="true" fetch="join">
            <key column="userid"/>
            <one-to-many class="Address"/>
        </set>

3.级联删除

配置属性cascade="delete"属性后,默认删除一的时候把关联的多也删除掉 

<set name="addressSet" cascade="delete" inverse="true">
        <key column="userid"/>
        <one-to-many class="Address"/>
</set>

也删除了address 

User user = (User) session.get(User.class, 26);
session.delete(user);

注:

我们在user中配置了address的Set,在address中配置了user,这叫
双向配置,实际上我们都是从user找address,很少从address找user,所以address的可以不配置