hibernate筆記-關聯關系

hibernate 關聯關系主要有一對一,一對多,多對多

一對一關聯

一對一關聯包括:

  1. 主鍵關聯
  2. 唯一外鍵關聯

主鍵關聯

兩張表通過主鍵一對一映射
比如員工和工牌之間,一個員工對應一個工牌,一個工牌也對應一個員工
對應員工實體類

public class Employee implements Serializable {
    private int id;
    private String firstName;
    private String lastName;
    private int salary;
    private CardEntity cardEntity;
}

hbm

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping default-lazy="true">
    <class name="bean.Employee" table="employee">
        <meta attribute="class-description">
            This class contains the employee detail.
        </meta>
        <id name="id" type="int" column="id">
            <generator class="native"/>
        </id>
        <property name="firstName" column="first_name" type="string"/>
        <property name="lastName" column="last_name" type="string"/>
        <property name="salary" column="salary" type="int"/>
        <!--聲明一對一關系-->
        <one-to-one name="cardEntity" cascade="all" class="bean.CardEntity" outer-join="true"></one-to-one>
    </class>
</hibernate-mapping>

cascade用來設置級聯關系

  1. none:在保存,刪除或修改當前對象時,不對其附屬對象(關聯對象)進行級聯操作。它是默認值。
  2. save-update:在保存,更新當前對象時,級聯保存,更新附屬對象(臨時對象,游離對象)。
  3. delete:在刪除當前對象時,級聯刪除附屬對象。
  4. all:所有情況下均進行級聯操作,即包含save-update和delete等等操作。
  5. delete-orphan:刪除此對象的同時刪除與當前對象解除關系的孤兒對象(僅僅使用于一對多關聯關系中)。

工牌對應實體類

public class CardEntity {
    private int id;
    private String cardNo;
    }

hbm

<?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>

    <class name="bean.CardEntity" table="t_card" schema="jpa">
        <id name="id" column="id"/>
        <property name="cardNo" column="card_no"/>
    </class>
</hibernate-mapping>

插入數據

Session session = sessionFactory.openSession();
        //獲取事務
        Transaction ts = session.beginTransaction();
        Employee employee=new Employee();
        CardEntity cardEntity=new CardEntity();
        cardEntity.setCardNo("123");
        //設置關聯
        employee.setCardEntity(cardEntity);
        employee.setFirstName("張");
        employee.setLastName("三");
        session.save(employee);
        ts.commit();
        session.close();

運行后sql輸出

insert 
    into
        employee
        (first_name, last_name, salary, department_id, phone) 
    values
        (?, ?, ?, ?, ?)
        
 insert 
    into
        jpa.t_card
        (card_no, id) 
    values
        (?, ?)

即同時插入了員工表和工牌表
這時你運行查詢方法

 List<Object> employees = session.createQuery("select e.cardEntity.cardNo from Employee  e").list();

是查詢不了數據的,因為剛剛插入的工牌和員工主鍵不一致
這里引入generator屬性用于保持主鍵的一致性
generator屬性有7種主鍵生成策略

  1. identity:用于mysql,主鍵遞增
  2. sequence:用于oracle數據庫
  3. native:跨數據庫時使用,由底層方言產生
  4. hilo:通過高低位合成id,先建表hi_value,再建列next_value。必須要有初始值
  5. sequencehilo:同過高低位合成id,建一個sequence序列,不用建表。
  6. assigned:用戶自定義id
  7. foreign:用于一對一關系共享主健時,兩id值一樣

所以將工牌對應的hbm修改為

<?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>

    <class name="bean.CardEntity" table="t_card" schema="jpa">
            <id name="id" column="id">
             <generator class="foreign">
                <param name="property">employee</param>
            </generator>
</id>
                <one-to-one name="employee" constrained="true" class="bean.Employee"></one-to-one>
        <property name="cardNo" column="card_no"/>
    </class>
</hibernate-mapping>

插入員工

Session session = sessionFactory.openSession();
        //獲取事務
        Transaction ts = session.beginTransaction();
        Employee employee=new Employee();
        CardEntity cardEntity=new CardEntity();
        cardEntity.setCardNo("123");
        employee.setFirstName("張");
        employee.setLastName("三");
        //相互關聯
        cardEntity.setEmployee(employee);
        employee.setCardEntity(cardEntity);
        session.save(employee);
        ts.commit();
        session.close();

唯一外鍵關聯

每一個員工都從屬于一個部門.員工表employee包含一個department_id字段,此字段與department的id字段關聯.這是一個典型的唯一外鍵關聯

hibernate中的唯一外鍵關聯由many-to-one定義,
因為唯一外鍵關聯的一對一只是多對一關系的特例
員工類hbm

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping SYSTEM
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping default-lazy="true">
    <class name="bean.Employee" table="employee">
        <meta attribute="class-description">
            This class contains the employee detail.
        </meta>
        <id name="id" type="int" column="id">
            <generator class="native"/>
        </id>
        <property name="firstName" column="first_name" type="string"/>
        <property name="lastName" column="last_name" type="string"/>
        <property name="salary" column="salary" type="int"/>
        <property name="departmentId" column="department_id" type="int" insert="false" update="false"/>
        <property name="phone" column="phone" type="bean.TestUseType"/>
        <many-to-one name="department" class="bean.Department" column="department_id"></many-to-one>
    </class>
</hibernate-mapping>

這樣就形成了一個單向關系
如果要形成雙向關系則需要修改Department類,為其追加one-to-one配置

<hibernate-mapping>
    <class name="bean.Department" table="department">
        <meta attribute="class-description">
            This class contains the employee detail.
        </meta>
        <id name="id" type="int" column="id">
            <generator class="native"/>
        </id>
        <property name="name" column="name" type="string"/>
       
            <one-to-one class="bean.Employee"></one-to-one>
       
    </class>
</hibernate-mapping>

一對多關聯

一對多關聯分為雙向和單向關聯

一對多關聯非常常見.例如每個員工都有多個地址,如辦公室地址,家庭住址等

單項一對多

員工hbm添加

 <set table="address" name="addressEntities" cascade="all">
            <key column="emp_id"></key>
            <one-to-many class="bean.AddressEntity"></one-to-many>
        </set>

地址hbm

<hibernate-mapping>
    <class name="bean.AddressEntity" table="address" schema="jpa">
        <id name="id" column="id">
        </id>
        <property name="address" column="address"/>
        <property name="type" column="type"/>
        <property name="empId" column="emp_id"/>
    </class>
</hibernate-mapping>

這就完成了單向一對多的配置,單向關聯時,為了保持關聯關系,我們只能通過主控方對被控方進行級聯更新,如果被關聯方的關聯字段為not null的話就會出現約束違例
這個問題可以通過雙向關聯來解決,它避免了約束違例并且提高了性能

雙向一對多

雙向一對多關聯,實際上是一對多和多對一關聯的組合,也就是說我們必須在主控方配置單向一對多關系的基礎上,在被控方配置對應的多對一

修改員工類hbm

<set table="address" name="addressEntities" cascade="all" inverse="true">
            <key column="emp_id"></key>
            <one-to-many class="bean.AddressEntity"></one-to-many>
        </set>

添加了inverse屬性,指定address為關系維護者
修改address對應hbm

 <many-to-one name="employee" class="bean.Employee" column="emp_id"></many-to-one>

多對多關聯

hibernate的多對多關系需要借助中間表來完成多對多映射信息的保存

多對多最常見的是在權限系統中使用,一個角色對應多個權限,一個權限對應多個角色

角色hbm

 <class name="bean.RoleEntity" table="role" schema="jpa">
        <id name="id" column="id">
            <generator class="native"></generator>
        </id>
        <property name="name" column="name"/>
        <set name="permissionEntities"
             table="role_permission_map"
             cascade="save-update"
             lazy="false"
             inverse="false"
        >
            <key column="role_id"></key>
            <many-to-many class="bean.PermissionEntity" column="permission_id" ></many-to-many>
        </set>
    </class>

權限hbm

<class name="bean.PermissionEntity" table="permission" schema="jpa">
        <id name="id" column="id">
            <generator class="native"/>
        </id>
        <property name="name" column="name"/>
        <set name="roleEntities"
        table="role_permission_map"
             cascade="save-update"
             lazy="false"
             inverse="true"
        >
            <key column="permission_id"></key>
            <many-to-many column="role_id" class="bean.RoleEntity"></many-to-many>
        </set>
    </class>

插入角色

Session session = sessionFactory.openSession();
        Transaction ts = session.beginTransaction();
        RoleEntity roleEntity = new RoleEntity();
        roleEntity.setName("test");

        RoleEntity roleEntity2 = new RoleEntity();
        roleEntity2.setName("test2");

        PermissionEntity permissionEntity = new PermissionEntity();
        permissionEntity.setName("新建用戶");

        PermissionEntity permissionEntity2 = new PermissionEntity();
        permissionEntity2.setName("刪除用戶");

        Set set = new HashSet<RoleEntity>();
        set.add(roleEntity);
        permissionEntity.setRoleEntities(set);

        Set set2 = new HashSet<RoleEntity>();
        set2.add(roleEntity2);
        permissionEntity2.setRoleEntities(set2);

        Set set3 = new HashSet<PermissionEntity>();
        set3.add(permissionEntity);
        set3.add(permissionEntity2);
        roleEntity.setPermissionEntities(set3);

        Set set4 = new HashSet<PermissionEntity>();
        set4.add(permissionEntity2);
        roleEntity2.setPermissionEntities(set4);


        session.save(roleEntity);
        session.save(roleEntity2);
        ts.commit();
        session.close();
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容