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();
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,366评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,521评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,689评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,925评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,942评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,727评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,447评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,349评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,820评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,990评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,127评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,812评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,471评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,017评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,142评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,388评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,066评论 2 355

推荐阅读更多精彩内容