Hibernate 一对多关系配置、增删改查、级联操作等

本文详述了ORM框架中一对多与多对一的配置方法,包括Hibernate的DDL语句、POJO类定义、配置文件详解及增删改查操作实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

需求:有两个表,分别是客户表和联系人表,一个客户有多个联系人,一个联系人只有一个客户

两个POJO类

public class Customer {
    private Long cust_id;
    private String cust_name;
    private String cust_source;
    private String cust_industry;
    private String cust_level;
    private String cust_phone;
    private String cust_mobile;

    //一个客户有多个联系人
    private Set<Linkman> linkmen = new HashSet<>();
}
public class Linkman {
    private Long link_id;
    private String link_name;
    private String link_gender;
    private String link_phone;
    private String link_mobile;
    private String link_email;
    private String link_qq;
    private String link_position;
    private String link_memo;
    private Long link_cust_id;

    //一个联系人对应一个客户
    private Customer customer;
    }

数据库两张表的DDL

客户表:

CREATE TABLE `customer` (
  `cust_id` bigint(20) NOT NULL AUTO_INCREMENT,
  `cust_name` varchar(255) DEFAULT NULL,
  `cust_source` varchar(255) DEFAULT NULL,
  `cust_industry` varchar(255) DEFAULT NULL,
  `cust_level` varchar(255) DEFAULT NULL,
  `cust_phone` varchar(255) DEFAULT NULL,
  `cust_mobile` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`cust_id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;

联系人表:

CREATE TABLE `linkman` (
  `link_id` bigint(20) NOT NULL AUTO_INCREMENT,
  `link_name` varchar(255) DEFAULT NULL,
  `link_gender` varchar(255) DEFAULT NULL,
  `link_phone` varchar(255) DEFAULT NULL,
  `link_mobile` varchar(255) DEFAULT NULL,
  `link_email` varchar(255) DEFAULT NULL,
  `link_qq` varchar(255) DEFAULT NULL,
  `link_position` varchar(255) DEFAULT NULL,
  `link_memo` varchar(255) DEFAULT NULL,
  `link_cust_id` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`link_id`),
  KEY `link_cust_id` (`link_cust_id`),
  CONSTRAINT `linkman_ibfk_1` FOREIGN KEY (`link_cust_id`) REFERENCES `customer` (`cust_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

 配置文件:

客户表的配置文件    对客户来说是一对多   因此要配置一对多

<?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="com.bullet.domain.Customer" table="customer">
        <!--建立类中的属性与表中的主键对应-->
        <id name="cust_id" column="cust_id" >
            <generator class="native"/>
        </id>
        <!--建立类中的普通的属性和表的字段的对应-->
        <property name="cust_name" column="cust_name" />
        <property name="cust_source" column="cust_source"/>
        <property name="cust_industry" column="cust_industry"/>
        <property name="cust_level" column="cust_level"/>
        <property name="cust_phone" column="cust_phone"/>
        <property name="cust_mobile" column="cust_mobile"/>

       <!--  一对多的配置  -->
        <!--set集合属性名称-->
        <set name="linkmen" cascade="save-update,delete" inverse="true">
            <key column="link_cust_id"></key><!--外键-->
            <!--set集合泛型的全路径-->
            <one-to-many class="com.bullet.domain.Linkman"></one-to-many>
        </set>
    </class>
</hibernate-mapping>

联系人表的配置文件    对联系人来说是多对一   因此要配置多对一

<?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="com.bullet.domain.Linkman" table="linkman">
        <!--建立类中的属性与表中的主键对应-->
        <id name="link_id" column="link_id" >
            <generator class="native"/>
        </id>
        <!--建立类中的普通的属性和表的字段的对应-->
        <property name="link_name" column="link_name" />
        <property name="link_gender" column="link_gender"/>
        <property name="link_phone" column="link_phone"/>
        <property name="link_mobile" column="link_mobile"/>
        <property name="link_email" column="link_email"/>
        <property name="link_qq" column="link_qq"/>
        <property name="link_position" column="link_position"/>
        <property name="link_memo" column="link_memo"/>

        <!--  配置多对一关系  -->
           <!--存储关联对象的名称-->               <!--存储关联对象的全路径-->
        <many-to-one name="customer" class="com.bullet.domain.Customer">
                <!--外键-->
            <column name="link_cust_id"/>
        </many-to-one>
    </class>
</hibernate-mapping>

添加操作

在一对多的添加操作中

可以对双方的关系进行双向配置      也可以进行单向配置      但一般都采取双向配置

如果要使用双向配置,为了提高性能,就要让其中一方放弃维护权,一般是外键在哪张表里,就让谁来维护,也就是说要让另外一张表放弃外键维护权  。

例如上面两张波,外键在linkman表中,因此让customer放弃外键维护权

 <!--  一对多的配置  -->
        <set name="linkmen" cascade="save-update,delete" inverse="true">   <!--set集合属性名称-->
            <key column="link_cust_id"></key><!--外键-->
            <one-to-many class="com.bullet.domain.Linkman"></one-to-many><!--set集合存储的类型-->
        </set>

在保存操作时,保存时必须保存两边,如:

  //保存   必须保存两边
            // 如果只保存一遍,会发生瞬时对象异常
            //原因:持久态对象关联了一个瞬态对象

            //如果想只保存一边    得在配置文件中配置   cascade="save-update"
        currentSession.save(customer1);
        currentSession.save(customer2);
        currentSession.save(customer3);

        currentSession.save(linkman1);
        currentSession.save(linkman2);
        currentSession.save(linkman3);

 如果只保存一边,会跑出瞬时对象异常。

如果要保存一边,就要配置,保存谁就在谁的配置文件中配置级联保存

 <!--  一对多的配置  -->
        <set name="linkmen" cascade="save-update,delete" inverse="true">   <!--set集合属性名称-->
            <key column="link_cust_id"></key><!--外键-->
            <one-to-many class="com.bullet.domain.Linkman"></one-to-many><!--set集合存储的类型-->
        </set>

cascade=“save-update”   表示级联保存

查询操作

查询操作时,hibernate内置懒加载,如果没使用到关联对象的属性,是不会发送SQL语句,只有用到时才会发送。

删除操作

默认的删除操作是不会级联删除的,默认的删除操作时打破两者之间的联系,然后删除。注意:默认的删除是不会删除级联对象,只会删除操作对象

要想实现级联删除,同样删除谁在谁的配置文件中进行配置

cascade=“delete”  

更新操作

分别查出两个对象,然后设置外键即可。

设置双向维护    一方放弃维护权

进行级联保存,保存谁在谁的配置文件中配置。

 

 

代码:

public class HibernateTest {

    /**
     * 添加操作
     */
    @Test
    public void test1(){
        Session currentSession = HibernateUtil.getCurrentSession();
        Transaction transaction = currentSession.beginTransaction();
        Customer customer1 = new Customer();
        customer1.setCust_name("客户1");
        Customer customer2 = new Customer();
        customer2.setCust_name("客户2");
        Customer customer3 = new Customer();
        customer3.setCust_name("客户3");


        Linkman linkman1 = new Linkman();
        linkman1.setLink_name("联系人1");
        Linkman linkman2 = new Linkman();
        linkman2.setLink_name("联系人2");
        Linkman linkman3 = new Linkman();
        linkman3.setLink_name("联系人3");

        /**
         * 配置关系   单向维护 双向维护
         * 一般都采用双向维护
         * 双向维护时,一般让一方放弃维护权
         * 一般是外键在谁里面,就让谁维护  inverse="true"   true代表放弃外键维护权
         */
        customer1.getLinkmen().add(linkman1);
        customer1.getLinkmen().add(linkman2);
        customer2.getLinkmen().add(linkman3);
        //反过来再配置
        linkman1.setCustomer(customer1);
        linkman2.setCustomer(customer1);
        linkman3.setCustomer(customer2);
        //保存   必须保存两边
            // 如果只保存一遍,会发生瞬时对象异常
            //原因:持久态对象关联了一个瞬态对象

            //如果想只保存一边    得在配置文件中配置   cascade="save-update"
        currentSession.save(customer1);
        currentSession.save(customer2);
        currentSession.save(customer3);

        currentSession.save(linkman1);
        currentSession.save(linkman2);
        currentSession.save(linkman3);



        transaction.commit();
        currentSession.close();
    }


    /**
     * 查询操作
     */
    @Test
    public void test2(){
        Session currentSession = HibernateUtil.getCurrentSession();
        Transaction transaction = currentSession.beginTransaction();

        Linkman linkman = currentSession.get(Linkman.class, 1L);

        transaction.commit();
        System.out.println(linkman);
        currentSession.close();

    }

    /**
     * 删除操作
     */
    @Test
    public void test3(){
        Session currentSession = HibernateUtil.getCurrentSession();
        Transaction transaction = currentSession.beginTransaction();
        //默认删除
        //先打断两表之间的联系,再删除customer   但相关联的linkman并没有被删除
        //并没有级联的删除
        //进行配置,删除谁对谁配置
        Customer customer = currentSession.get(Customer.class, 8L);
        currentSession.delete(customer);

        transaction.commit();
        currentSession.close();
    }

    /**
     * 更新操作
     */
    @Test
    public void test4(){
        Session currentSession = HibernateUtil.getCurrentSession();
        Transaction transaction = currentSession.beginTransaction();
        //更新
        Linkman linkman1 = currentSession.get(Linkman.class, 1L);
        Customer customer3 = currentSession.get(Customer.class, 9L);
        //关联
        linkman1.setCustomer(customer3);


        transaction.commit();
        currentSession.close();
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值