hiberate關係對映大全

林加欣發表於2016-11-04

1. 集合對映

開發流程:

         需求分析/資料庫設計、專案設計/ 編碼/測試/實施部署上線/驗收

 

需求:

         使用者購買, 填寫地址!

資料庫:

程式碼:

        

// javabean設計

public class User {

 

    private int userId;

    private String userName;

    // 一個使用者,對應的多個地址

    private Set<String> address;

    private List<String> addressList = new ArrayList<String>();

    //private String[] addressArray; // 對映方式和list一樣     <array name=""></array>

    private Map<String,String> addressMap = new HashMap<String, String>();

   

}

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC

    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

 

<hibernate-mapping package="cn.itcast.a_collection">

   

    <class name="User" table="t_user">

        <id name="userId" column="id">

            <generator class="native"></generator>

        </id>  

        <property name="userName"></property>

       

        <!--

            set集合屬性的對映

                name 指定要對映的set集合的屬性

                table 集合屬性要對映到的表

                key  指定集合表(t_address)的外來鍵欄位

                element 指定集合表的其他欄位

                    type 元素型別,一定要指定

         -->

         <set name="address" table="t_address">

            <key column="uid"></key>

            <element column="address" type="string"></element>

         </set>

         

         <!--

            list集合對映

                list-index  指定的是排序列的名稱 (因為要保證list集合的有序)

          -->

          <list name="addressList" table="t_addressList">

              <key column="uid"></key>

              <list-index column="idx"></list-index>

              <element column="address" type="string"></element>

          </list>

         

          <!--

            map集合的對映

                key  指定外來鍵欄位

                map-key 指定map的key

                element  指定map的value

           -->

          <map name="addressMap" table="t_addressMap">

            <key column="uid"></key>

            <map-key column="shortName" type="string" ></map-key>

            <element column="address" type="string" ></element>

          </map>

         

         

    </class>

   

 

</hibernate-mapping>

 

 

    // 儲存set

    @Test

    public void testSaveSet() throws Exception {

        Session session = sf.openSession();

        session.beginTransaction();

       

        //-- 儲存

        Set<String> addressSet = new HashSet<String>();

        addressSet.add("廣州");

        addressSet.add("深圳");

        // 使用者物件

        User user = new User();

        user.setUserName("Jack");

        user.setAddress(addressSet);

       

        // 儲存

        session.save(user);

       

        session.getTransaction().commit();

        session.close();

    }

   

    // 儲存list/map

    @Test

    public void testSaveList() throws Exception {

        Session session = sf.openSession();

        session.beginTransaction();

        User user = new User();

        user.setUserName("Tom");

//      // 使用者物件  --  list

//      user.getAddressList().add("廣州");

//      user.getAddressList().add("深圳");

//      // 儲存

//      session.save(user);

       

        // 使用者物件  --  Map

        user.getAddressMap().put("A0001", "廣州");

        user.getAddressMap().put("A0002", "深圳");

       

        // 儲存

        session.save(user);

       

        session.getTransaction().commit();

        session.close();

    }

 

 

 

 

 

 

問題:

         集合對映,對映的集合元素,都是普通的型別, 能否為物件型別?

 

2. 關聯對映

 

需求1:

         部門與員工

                     一個部門有多個員工;       【一對多】

                     多個員工,屬於一個部門    【多對一】

需求2:

         專案與開發員工

                   一個專案,有多個開發人員!

                   一個開發人員,參與多個專案!   【多對多】

 

多對一對映與一對多

程式碼

ü  需求:員工與部門

ü  資料庫:

ü  設計javabean封裝:

ü  對映:

public class Dept {

 

   private int deptId;

   private String deptName;

   // 【一對多】 部門對應的多個員工

   private Set<Employee> emps = new HashSet<Employee>();

  

public class Employee {

 

   private int empId;

   private String empName;

   private double salary;

   // 【多對一】員工與部門

   private Dept dept;

 

Dept.hbm.xml 

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC

   "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

   "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

 

<hibernate-mapping package="cn.itcast.b_one2Many">

  

   <class name="Dept" table="t_dept">

      <id name="deptId">

        <generator class="native"></generator>

      </id>

      <property name="deptName" length="20"></property>

     

      <!--

        一對多關聯對映配置  (通過部門管理到員工)

        Dept 對映關鍵點:

        1.  指定 對映的集合屬性: "emps"

        2.  集合屬性對應的集合表: "t_employee"

        3.  集合表的外來鍵欄位   "t_employee. dept_id"

        4.  集合元素的型別

       

       -->

       <set name="emps">   <!-- table="t_employee" -->

          <key column="dept_id"></key>

          <one-to-many class="Employee"/>

       </set>

       

       

   </class>

  

 

</hibernate-mapping>

 

 

Employee.hbm.xml

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC

   "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

   "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

 

<hibernate-mapping package="cn.itcast.b_one2Many">

  

   <class name="Employee" table="t_employee">

      <id name="empId">

        <generator class="native"></generator>

      </id>

      <property name="empName" length="20"></property>

      <property name="salary" type="double"></property>

     

      <!--

        多對一對映配置

        Employee 對映關鍵點:

        1.  對映的部門屬性  :  dept

        2.  對映的部門屬性,對應的外來鍵欄位: dept_id

        3.  部門的型別

       -->

       <many-to-one name="dept" column="dept_id" class="Dept"></many-to-one>

       

   </class>

  

 

</hibernate-mapping>

 

測試

 

public class App {

  

   private static SessionFactory sf;

   static {

      sf = new Configuration()

        .configure()

        .addClass(Dept.class)  

        .addClass(Employee.class)   // 測試時候使用

        .buildSessionFactory();

   }

 

   // 儲存, 部門方 【一的一方法操作】

   @Test

   public void save() {

     

      Session session = sf.openSession();

      session.beginTransaction();

     

      // 部門物件

      Dept dept = new Dept();

      dept.setDeptName("應用開發部");

      // 員工物件

      Employee emp_zs = new Employee();

      emp_zs.setEmpName("張三");

      Employee emp_ls = new Employee();

      emp_ls.setEmpName("李四");

      // 關係

      dept.getEmps().add(emp_zs);

      dept.getEmps().add(emp_ls);

 

      // 儲存

      session.save(emp_zs);

      session.save(emp_ls);

      session.save(dept); // 儲存部門,部門下所有的員工 

     

      session.getTransaction().commit();

      session.close();

      /*

       *  結果

       *  Hibernate: insert into t_employee (empName, salary, dept_id) values (?, ?, ?)

        Hibernate: insert into t_employee (empName, salary, dept_id) values (?, ?, ?)

        Hibernate: insert into t_dept (deptName) values (?)

        Hibernate: update t_employee set deptId=? where empId=?    維護員工引用的部門的id

        Hibernate: update t_employee set deptId=? where empId=?

       */

   }

   // 【推薦】 儲存, 部員方 【多的一方法操作】

   @Test

   public void save2() {

     

      Session session = sf.openSession();

      session.beginTransaction();

     

      // 部門物件

      Dept dept = new Dept();

      dept.setDeptName("綜合部");

      // 員工物件

      Employee emp_zs = new Employee();

      emp_zs.setEmpName("張三");

      Employee emp_ls = new Employee();

      emp_ls.setEmpName("李四");

      // 關係

      emp_zs.setDept(dept);

      emp_ls.setDept(dept);

     

     

      // 儲存

      session.save(dept); // 先儲存一的方法

      session.save(emp_zs);

      session.save(emp_ls);// 再儲存多的一方,關係回自動維護(對映配置完)

     

      session.getTransaction().commit();

      session.close();

      /*

       *  結果

       *  Hibernate: insert into t_dept (deptName) values (?)

        Hibernate: insert into t_employee (empName, salary, dept_id) values (?, ?, ?)

        Hibernate: insert into t_employee (empName, salary, dept_id) values (?, ?, ?)

        少生成2條update  sql

       */

   }

  

}

 

 

總結:

  在一對多與多對一的關聯關係中,儲存資料最好的通過多的一方來維護關係,這樣可以減少update語句的生成,從而提高hibernate的執行效率!

        

配置一對多與多對一,這種叫“雙向關聯”

只配置一對多,           叫“單項一對多”

只配置多對一,           叫“單項多對一”

 

注意:

         配置了哪一方,哪一方才有維護關聯關係的許可權!

Inverse屬性

Inverse屬性,是在維護關聯關係的時候起作用的。

       表示控制權是否轉移。(在一的一方起作用)

 

Inverse , 控制反轉。

Inverse = false  不反轉;   當前方有控制權

                   True  控制反轉; 當前方沒有控制權

 

維護關聯關係中,是否設定inverse屬性:

         1. 儲存資料

                   有影響。

            如果設定控制反轉,即inverse=true, 然後通過部門方維護關聯關係。在儲存部門的時候,同時儲存員工, 資料會儲存,但關聯關係不會維護。即外來鍵欄位為NULL

                  

 

         2. 獲取資料

                   無。

         3. 解除關聯關係?

                   有影響。

                  inverse=false,  可以解除關聯

inverse=true,  當前方(部門)沒有控制權,不能解除關聯關係

(不會生成update語句,也不會報錯)

         4. 刪除資料對關聯關係的影響?

                   有影響。

                   inverse=false, 有控制權, 可以刪除。先清空外來鍵引用,再刪除資料。

                   inverse=true,  沒有控制權: 如果刪除的記錄有被外來鍵引用,會報錯,違反主外來鍵引用約束!  如果刪除的記錄沒有被引用,可以直接刪除。

 

cascade 屬性

cascade  表示級聯操作  【可以設定到一的一方或多的一方】

         none          不級聯操作, 預設值

         save-update     級聯儲存或更新

         delete                  級聯刪除

         save-update,delete    級聯儲存、更新、刪除

         all                 同上。級聯儲存、更新、刪除

 

 

hibernate常見面試題: inverse與cascade區別?

 

多對多對映

需求:專案與開發人員

           Project   Developer

           電商系統

                      曹吉

                      王春

            OA系統

                            王春

                            老張

資料庫

 

程式碼

/**

 * 開發人員

 *

 * @author Jie.Yuan

 *

 */

public class Developer {

    private int d_id;

    private String d_name;

    // 開發人員,引數的多個專案

    private Set<Project> projects = new HashSet<Project>();

}

 

/**

 * 專案

 *

 * @author Jie.Yuan

 *

 */

public class Project {

    private int prj_id;

    private String prj_name;

    // 專案下的多個員工

    private Set<Developer> developers = new HashSet<Developer>();

   

Project.hbm.xml

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC

    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

 

<hibernate-mapping package="cn.itcast.c_many2many">

   

    <class name="Project" table="t_project">

        <id name="prj_id">

            <generator class="native"></generator>

        </id>  

        <property name="prj_name" length="20"></property>

        <!--

            多對多對映:

            1.  對映的集合屬性: “developers”

            2.  集合屬性,對應的中間表: “t_relation”

            3. 外來鍵欄位:  prjId

            4. 外來鍵欄位,對應的中間表欄位:  did

            5.   集合屬性元素的型別

         -->

         <set name="developers" table="t_relation" cascade="save-update">

            <key column="prjId"></key>

            <many-to-many column="did" class="Developer"></many-to-many>

         </set>

         

    </class>

   

 

</hibernate-mapping>

 

 

Developer.hbm.xml

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC

    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

 

<hibernate-mapping package="cn.itcast.c_many2many">

   

    <class name="Developer" table="t_developer">

        <id name="d_id">

            <generator class="native"></generator>

        </id>  

        <property name="d_name" length="20"></property>

       

        <!--

            多對多對映配置: 員工方

                name  指定對映的集合屬性

                table 集合屬性對應的中間表

                key   指定中間表的外來鍵欄位(引用當前表t_developer主鍵的外來鍵欄位)

                many-to-many

                    column 指定外來鍵欄位對應的專案欄位

                    class  集合元素的型別

         -->

        <set name="projects" table="t_relation">

            <key column="did"></key>

            <many-to-many column="prjId" class="Project"></many-to-many>

        </set>

       

         

    </class>

   

 

</hibernate-mapping>

 

 

維護關聯關係

設定inverse屬性,在多對多種維護關聯關係的影響?

1) 儲存資料

有影響。

          inverse=false ,有控制權,可以維護關聯關係; 儲存資料的時候會把物件關係插入中間表;

         inverse=true,  沒有控制權, 不會往中間表插入資料。

2) 獲取資料

         無。

 

3) 解除關係

         // 有影響。

         // inverse=false ,有控制權, 解除關係就是刪除中間表的資料。

         // inverse=true, 沒有控制權,不能解除關係。

4) 刪除資料

         有影響。

         // inverse=false, 有控制權。 先刪除中間表資料,再刪除自身。

         // inverse=true, 沒有控制權。 如果刪除的資料有被引用,會報錯! 否則,才可以刪除

 

相關文章