hibernate和数据库设计

什么是复合主键和联合主键?

联合主键=复合主键

所谓的复合主键 就是指你表的主键含有一个以上的字段组成 
比如 
create table test 
( 
   name varchar(19), 
   id number, 
   value varchar(10), 
   primary key (name,id) 
) 

上面的name和id字段组合起来就是你test表的复合主键 
它的出现是因为你的name字段可能会出现重名,所以要加上ID字段这样就可以保证你记录的唯一性

到底在哪用cascade=”…”?

 inverse属性默认是false的,就是说关系的两端都来维护关系。
 所以,当关系的两头都用inverse="true"是不对的,就会导致任何操作都不处发对关系表的操作。当两端都是inverse= "false"或是default值是,在代码对关系显示的维护也是不对的,会导致在关系表中插入两次关系。

inverse只对one-to-many(或many-to-many)有效,对many-to-one, one-to-one无效。cascade对关系标记都有效


自己的理解,inverse是在一方中设置的,默认是false,但是一般在维护关系时是由多方维持的,所以应该将inverse设置成true

主表从表主键外键

什么叫外键?  外键就是一个表(从表)的字段是另外一张表(主表)的主键
外键在从表上  这个外键叫做从表的外键

集合映射,映射的集合元素,都是普通的类型(1对多)

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

多对一映射与一对多

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



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





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

***总结:***

在一对多与多对一的关联关系中,保存数据最好的通过多的一方来维护关系,这样可以减少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>();
}
<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>





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


维护关联关系
设置inverse属性,在多对多种维护关联关系的影响?
1) 保存数据
有影响。
     inverse=false ,有控制权,可以维护关联关系; 保存数据的时候会把对象关系插入中间表;
    inverse=true,  没有控制权, 不会往中间表插入数据。
2) 获取数据
    无。

3) 解除关系
    // 有影响。
    // inverse=false ,有控制权, 解除关系就是删除中间表的数据。
    // inverse=true, 没有控制权,不能解除关系。
4) 删除数据
    有影响。
    // inverse=false, 有控制权。 先删除中间表数据,再删除自身。
    // inverse=true, 没有控制权。 如果删除的数据有被引用,会报错! 否则,才可以删除

注意

如果你想把一个对象映射成一个外键字段,只能用many-to-one
在由一方维护关系时,不管插入的顺序如何,都是先插入再更新,目的是为了确保每条维护好了,所以要有update语句,因此一般在一方设置控制反转,交给多方维护,

由一的一方维护关系,由一包含多 都有update语句,不管先save谁

            Country coun=new Country();
            Leader lea=new Leader();

            coun.setCname("联合国");
            lea.setLname("赵四");

            coun.getLeader().add(lea);   //一包含多

            session.save(coun);
            session.save(lea);

Hibernate: insert into t_country (cname) values (?)
Hibernate: insert into t_leader (lname, c_id) values (?, ?)
Hibernate: update t_leader set c_id=? where lid=?

由一的一方维护关系,由多包含一 先保存多有update语句 先保存一没有update语句

            Country coun=new Country();
            Leader lea=new Leader();

            coun.setCname("联合国");
            lea.setLname("赵四");

            lea.setConntry(coun);  //多包含一

            session.save(lea);
            session.save(coun);     //先保存多  有update语句

Hibernate: insert into t_leader (lname, c_id) values (?, ?)
Hibernate: insert into t_country (cname) values (?)
Hibernate: update t_leader set lname=?, c_id=? where lid=?

            //---------------------
            session.save(coun);
            session.save(lea);     //先保存一  无update语句
Hibernate: insert into t_country (cname) values (?)
Hibernate: insert into t_leader (lname, c_id) values (?, ?)

由多的一方维护关系,多包含一,先保存一没有update 先保存多有update

            Country coun=new Country();
            Leader lea=new Leader();

            coun.setCname("联合国");
            lea.setLname("赵四");

            lea.setConntry(coun);   //多包含一


            session.save(coun);
            session.save(lea);    //先保存一没有update   先保存多有update

由多的一方维护关系,一包含多,不管先保存谁, 数据正常插入,但是 外键没有设置

            Country coun=new Country();
            Leader lea=new Leader();

            coun.setCname("联合国");
            lea.setLname("赵四");

            coun.getLeader().add(lea);

            session.save(lea);   //不管先保存谁, 数据正常插入,但是  外键没有设置
            session.save(coun);  

重点:如果 设置联合主键,实现序列化接口,重写hashcode和equals方法

联合主键demo

rose类对应的hbm.xml

<class name="com.yun.nsfw.role.entity.Role" table="role">
        <id name="roleid" type="java.lang.String">
            <column name="id" length="32" />
            <generator class="uuid.hex" />
        </id>
        <property name="rolename" type="java.lang.String">
            <column name="name" length="20" not-null="true" />
        </property>
        <property name="rolestate" type="java.lang.String">
            <column name="state" length="1" />
        </property>

        <set name="RolePrivileges" lazy="false" inverse="true" cascade="save-update,delete">
            <key>
                <column name="role_id"/>
            </key>
            <one-to-many class="com.yun.nsfw.role.entity.RolePrivilege"/>
        </set>

</class>




RolePrivilege类对应的hbm.xml
<class name="com.yun.nsfw.role.entity.RolePrivilege" table="roleprivilege">
        <composite-id class="com.yun.nsfw.role.entity.RolePrivilegeId" name="id">
            <key-many-to-one name="role" class="com.yun.nsfw.role.entity.Role">
                <column name="role_id"/>
            </key-many-to-one>
            <key-property name="code" type="string">
                <column name="code" length="20"/>
            </key-property>
        </composite-id>
</class>

java代码
rose类

            private  String roleid;        //id
            private String rolename;  //名字
            private String rolestate;  //状态
            private Set<RolePrivilege> RolePrivileges = new HashSet<RolePrivilege>();

RolePrivilege类

private RolePrivilegeId id;

RolePrivilegeId类

    private Role role;
    private String code;

一对一映射(基于主键)

<class name="IdCard" table="t_IdCard">
        <id name="user_id">
            <!-- 
                id 节点指定的是主键映射, 即user_id是主键
                主键生成方式: foreign  即把别的表的主键作为当前表的主键;
                        property (关键字不能修改)指定引用的对象     对象的全名 cn..User、  对象映射 cn.User.hbm.xml、   table(id)
             -->
            <generator class="foreign">
                <param name="property">user</param>
            </generator>
        </id>
        <property name="cardNum" length="20"></property>
        <property name="place" length="20"></property>

        <!-- 
            一对一映射,有外键方
            (基于主键的映射)
             constrained="true"  指定在主键上添加外键约束
         -->
        <one-to-one name="user" class="User" constrained="true"  cascade="save-update"></one-to-one>

    </class>


上面的基于外键运用就是说设置主键的生成策略为外键引用,引用为user那个属性,两张表的id要一致,这还不够,下面的one-to-one才是告诉hibernate形成映射,可以从idcard类中找到user类。constrained="true" 必须加,生成外键约束的意思.
在保存的时候,由于一对一的映射特性,自动有级联功能,不用保存非维护关系的一端,也能保存,和一对多不一样

one-to-one不会增加字段    many-to-one会增加数据库字段

一对一映射(基于外键)

<class name="IdCard" table="t_IdCard">
        <id name="cardNum">
            <generator class="assigned"></generator>
        </id>   
        <property name="place" length="20"></property>

        <!-- 
            一对一映射,有外键方
            unique="true"   给外键字段添加唯一约束
         -->
         <many-to-one name="user" unique="true" column="user_id" class="User" cascade="save-update"></many-to-one>

</class>

//-------------------------------

<class name="User" table="t_user">
        <id name="userId">
            <generator class="native"></generator>
        </id>   
        <property name="userName" length="20"></property>
        <!-- 
            一对一映射: 没有外键方
         -->
         <one-to-one name="idCard" class="IdCard"></one-to-one>

</class>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

发疯的man

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值