• 04.Hibernate一对一关联


        前言:本文主要介绍使用Hibernate映射一对一的关联关系的两种方式:使用外键映射、使用主键映射。

    1.数据库表的一对一关联关系

        本文根据客户信息表(tb_customer)和地址信息表(tb_address)来说明其一对一的关系,每一个客户都有一个家庭住址,而每一个地址都对应一个客户。
    (1)使用外键映射的数据库表说明
        数据库表模型图如下:
         
        数据库建表语句如下:
    1. CREATE TABLE tb_customer
    2. (
    3. id bigint NOT NULL auto_increment COMMENT 'ID',
    4. name varchar(50) NOT NULL COMMENT '客户名称',
    5. home_address bigint COMMENT '客户家庭地址',
    6. PRIMARY KEY (id)
    7. ) COMMENT = '客户信息表';

    8. CREATE TABLE tb_address
    9. (
    10. id bigint NOT NULL auto_increment COMMENT 'ID',
    11. zipcode varchar(50) NOT NULL COMMENT '邮政编码',
    12. address varchar(200) NOT NULL COMMENT '地址',
    13. PRIMARY KEY (id)
    14. ) COMMENT = '地址信息表';
    15. -- 可选的外键约束
    16. ALTER TABLE tb_customer ADD CONSTRAINT fk_tb_customer_tb_address_1 FOREIGN KEY (home_address) REFERENCES tb_address (id);
    (2)使用主键映射的数据库表关系
        数据库表模型图如下:
        
        数据库建表语句如下:
    1. CREATE TABLE tb_customer
    2. (
    3. id bigint NOT NULL auto_increment COMMENT 'ID',
    4. name varchar(50) NOT NULL COMMENT '客户名称',
    5. PRIMARY KEY (id)
    6. ) COMMENT = '客户信息表';

    7. CREATE TABLE tb_address
    8. (
    9. id bigint NOT NULL auto_increment COMMENT 'ID',
    10. zipcode varchar(50) NOT NULL COMMENT '邮政编码',
    11. address varchar(200) NOT NULL COMMENT '地址',
    12. PRIMARY KEY (id)
    13. ) COMMENT = '地址信息表';
    14. -- 可选的外键约束
    15. ALTER TABLE tb_address ADD CONSTRAINT fk_tb_address_tb_customer_1 FOREIGN KEY (id) REFERENCES tb_customer (id);
    (3)编写实体类如下
        虽然使用外键关联与使用主键关联在数据库层面上表结构不同,但是对于实体类来说这种关联关系是一样的,所以实体类是一样的,代码如下:
    1. package model;
    2. public class Address
    3. {
    4. private Long id;
    5. private String zipcode;
    6. private String address;
    7. private Customer customer;
    8. @Override
    9. public String toString()
    10. {
    11. return "Address [id=" + id + ", zipcode=" + zipcode + ", address=" + address + ", customer=" + customer.getName() + "]";
    12. }
    13. // 省略setter、getter...
    14. }
    1. package model;
    2. public class Customer
    3. {
    4. private Long id;
    5. private String name;
    6. private Address homeAddress;
    7. @Override
    8. public String toString()
    9. {
    10. return "Customer [id=" + id + ", name=" + name + ", homeAddress=" + homeAddress.getAddress() + "]";
    11. }
    12. // 省略setter、getter...
    13. }
        注意:这里的toString()方法只输出实体类的基本属性,如:", homeAddress=" + homeAddress.getAddress(),而不输出整个实体类(", homeAddress=" + homeAddress),是因为这样做很容易造成循环输出,形成死循环!

    2.按照外键映射一对一关联

        使用外键映射一对一关联需要使用many-to-one元素和one-to-one元素,并且在外键方使用many-to-one元素配置外键。配置如下:
    1. <hibernate-mapping package="model">
    2. <class name="Address" table="tb_address">
    3. <id name="id">
    4. <generator class="native"></generator>
    5. </id>
    6. <property name="zipcode" column="zipcode" />
    7. <property name="address" column="address" />
    8. <one-to-one name="customer" class="model.Customer" property-ref="homeAddress"/>
    9. </class>
    10. </hibernate-mapping>
    1. <hibernate-mapping package="model">
    2. <class name="Customer" table="tb_customer">
    3. <id name="id">
    4. <generator class="native"></generator>
    5. </id>
    6. <property name="name" column="name" />
    7. <many-to-one name="homeAddress" class="model.Address" column="home_address" unique="true" cascade="all"/>
    8. </class>
    9. </hibernate-mapping>
        根据上面配置需要注意一下几点:
      1. 在外键方使用many-to-one元素配置外键,如:<many-to-one column="home_address"
      2. 在外键参照的主键方要使用one-to-one元素映射关联对象,如:<one-to-one name="customer" class="model.Customer"
      3. many-to-one元素中要配置unique属性值为true,表明每个Customer对象都有唯一的Address对象关联,形成一对一。
      4. many-to-one元素中建议配置cascade属性值为all,表明保存、更新、删除Customer对象会级联操作Address对象。
      5. one-to-one元素中要配置property-ref属性值为homeAddress,表明建立了从Customer对象的homeAddress属性到Address对象的关系。
        编写如下的测试程序,测试关联关系,程序代码以及打印结果如下:
    1. public static void main(String[] args)
    2. {
    3. Customer customer;
    4. Address address;
    5. Configuration cfg = new Configuration();
    6. cfg.configure();
    7. ServiceRegistry sr = new ServiceRegistryBuilder().applySettings(cfg.getProperties()).buildServiceRegistry();
    8. SessionFactory sf = cfg.buildSessionFactory(sr);
    9. System.out.println("连接数据库");
    10. Session session = sf.openSession();
    11. Transaction transaction = session.beginTransaction();
    12. try
    13. {
    14. customer=new Customer();
    15. address=new Address();
    16. customer.setName("测试客户01");
    17. address.setZipcode("123456");
    18. address.setAddress("湖北省武汉市");

    19. customer.setHomeAddress(address);
    20. address.setCustomer(customer);
    21. session.save(customer);//配置使用了级联保存
    22. transaction.commit();
    23. }
    24. catch (Exception e)
    25. {
    26. transaction.rollback();
    27. System.out.println("错误:" + e);
    28. }
    29. finally
    30. {
    31. session.close();
    32. System.out.println("关闭数据库");
    33. }
    34. System.exit(0);
    35. }
    1. 连接数据库
    2. Hibernate: insert into tb_address (zipcode, address) values (?, ?)
    3. Hibernate: insert into tb_customer (name, home_address) values (?, ?)
    4. 关闭数据库
        注意:由于配置了级联保存,所以调用session.save(customer)时,会保存customeraddress两个对象!

    3.按照主键映射一对一关联

        使用主键映射一对一关联只需要使用one-to-one元素配置,配置如下:
    1. <hibernate-mapping package="model">
    2. <class name="Address" table="tb_address">
    3. <id name="id">
    4. <generator class="foreign">
    5. <param name="property">customer</param>
    6. </generator>
    7. </id>
    8. <property name="zipcode" column="zipcode" />
    9. <property name="address" column="address" />
    10. <one-to-one name="customer" class="model.Customer" constrained="true"/>
    11. </class>
    12. </hibernate-mapping>
    1. <hibernate-mapping package="model">
    2. <class name="Customer" table="tb_customer">
    3. <id name="id">
    4. <generator class="native"></generator>
    5. </id>
    6. <property name="name" column="name" />
    7. <one-to-one name="homeAddress" class="model.Address" cascade="all"/>
    8. </class>
    9. </hibernate-mapping>
        对于上面配置需要注意一下几点:
      1. Address对象的映射配置中的one-to-one元素属性constrained="true",表示tb_address表的ID主键同时作为外键参照tb_customer表的ID主键,此时Address对象的OID生成策略必须使用foreign
      2. Address主键生成使用了foreign策略,Hibernate就会保证对象与关联的对象共享同一个OID。
      3. Customer对象映射配置文件中建议配置cascade="all",表明保存、更新、删除Customer对象会级联操作Address对象。
        再次运行前面的测试程序,控制台输出结果如下:
    1. 连接数据库
    2. Hibernate: insert into tb_customer (name) values (?)
    3. Hibernate: insert into tb_address (zipcode, address) values (?, ?)
    4. 关闭数据库

    4.相关配置详解

    (1)one-to-one节点配置详解
    1. <one-to-one name="PropertyName"
    2. access="field|property"
    3. class="ClassName"
    4. property-ref="PropertyNameFromAssociatedClass"
    5. constrained="true|false"
    6. formula="arbitrary SQL expression"
    7. cascade="all|none|save-update|delete"
    8. fetch="join|select"
    9. outer-join="true|false"
    10. foreign-key="foreign-key"
    11. lazy="true|false"
    12. embed-xml="true|false"
    13. entity-name="EntityName"
    14. node="element-name"/>
        如上展示了one-to-one节点常用的配置,是面对其配置进行详细的说明:
    1. name:实体类属性名。
    2. access:默认的实体类属性访问模式,取值为property表示访问getter、setter方法间接访问实体类字段,取值为field表示直接访问实体类字段(类成员变量)。
    3. class:关联的类的名字,默认是通过反射得到属性类型。
    4. property-ref:指定关联类的一个属性,这个属性将会和本外键相对应。如果没有指定,会使用对方关联类的主键。
    5. constrained:表示使用主键关联一对一关系,一张表的主键同时也是外键,参照另一张表的主键。
    6. formula:一个SQL表达式,定义了这个计算属性的值,计算属性没有和它对应的数据库字段。
    7. cascade:指明哪些操作会从父对象级联到关联的对象。
    8. fetch:参数指定了关联对象抓取的方式是select查询还是join查询,默认为selectfetch="join"等同于outer-join="true"fetch="select"等同于outer-join="false"
    9. outer-join:设置Hibernate是否使用外连接获取关联的数据,设置成true可以减少SQL语句的条数。
    10. foreign-key:关联的数据库外键名。
    11. lazy:是否采用延迟加载策略。
    12. embed-xml:如果embed-xml="true",则对应于被关联实体或值类型的集合的XML树将直接嵌入拥有这些关联的实体的XML树中,默认值为true
    13. entity-name:Hibernate3新增特性,用于动态模型(Dynamic Model)支持。Hibernate3允许一个类进行多次映射(前提是映射到不同的表)。
    14. node:配置说明。
    -------------------------------------------------------------------------------------------------------------------------------




  • 相关阅读:
    PRelu和一些激活函数
    一个编程入门参考网站
    GPT/Bert/Attention等一些总结
    [Go] struct
    [Typescript Challenges] 15. Medium Get return type of function
    [GO] Pass by reference
    [Go] Error
    [Go] Defer, panic, recover
    [Go] Method
    [Go] Pointer
  • 原文地址:https://www.cnblogs.com/LiZhiW/p/4279005.html
Copyright © 2020-2023  润新知