欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java持久层之Hibernate(Hibernate操作表之间的关系)

程序员文章站 2022-06-16 13:26:04
文章目录表与表之间关系Hibernate一对多操作一对多的映射配置一对多的级联操作Hibernate多对多操作表与表之间关系一对多:分类与商品之间的关系:一个分类中可以有多种商品,一种商品只能属于某一分类多对多:订单和商品之间的关系:一个订单里面有多种商品,一种商品可以属于多个订单一对一:在实际开发中使用的不是很多Hibernate一对多操作一对多的映射配置第一步:创建两个实体类第二步:让两个实体类关联起来:对象关系第三步:配置映射文件一般一个实体类对应一个映射文...




表与表之间关系

  • 一对多:分类与商品之间的关系:一个分类中可以有多种商品,一种商品只能属于某一分类
  • 多对多:订单和商品之间的关系:一个订单里面有多种商品,一种商品可以属于多个订单
  • 一对一:在实际开发中使用的不是很多

Hibernate一对多操作

一对多关联关系的建立

  • 第一步:创建两个实体类
package com.ycom.hibernate.crm.po; // 实体类:客户类 public class Customer { private Integer id; // 客户id private String name; // 客户名称 private String level; // 客户级别 private String source; // 客户来源 private String phone; // 联系电话 private String mobile; // 联系手机 public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getLevel() { return level; } public void setLevel(String level) { this.level = level; } public String getSource() { return source; } public void setSource(String source) { this.source = source; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getMobile() { return mobile; } public void setMobile(String mobile) { this.mobile = mobile; } } ========================================================================== package com.ycom.hibernate.crm.po; // 实体类:联系人 public class LinkMan { private Integer id; // 联系人id private String name; // 联系人名称 private String gender; // 联系人性别 private String phone; // 联系人电话 public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } } 
  • 第二步:让两个实体类关联起来:对象关系
    (1) 一方关联多方
    Java持久层之Hibernate(Hibernate操作表之间的关系)
    (2) 多方关联一方
    Java持久层之Hibernate(Hibernate操作表之间的关系)
    Java持久层之Hibernate(Hibernate操作表之间的关系)
  • 第三步:配置映射文件:一般一个实体类对应一个映射文件
    (1) 把映射成两个类自己的最基本配置
<?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.ycom.hibernate.crm.po.Customer" table="t_customer"> <!-- 第一部分: 配置实体类唯一属性与表主键的映射关系 --> <id name="id" column="id"> <generator class="native"></generator> </id> <!-- 第二部分:配置实体类其他属性与表的字段的映射关系 --> <property name="name" column="name"></property> <property name="level" column="level"></property> <property name="source" column="source"></property> <property name="phone" column="phone"></property> <property name="mobile" column="mobile"></property> <!-- 第三部分:配置两个实体类之间的映射关系 --> </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.ycom.hibernate.crm.po.LinkMan" table="t_linkman"> <!-- 第一部分: 配置实体类唯一属性与表主键的映射关系 --> <id name="id" column="id"> <generator class="native"></generator> </id> <!-- 第二部分:配置实体类其他属性与表的字段的映射关系 --> <property name="name" column="name"></property> <property name="gender" column="gender"></property> <property name="phone" column="phone"></property> <!-- 第三部分:配置两个实体类之间的映射关系 --> </class> </hibernate-mapping> 

(2) 在映射配置文件中配置一对多的关系

<?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.ycom.hibernate.crm.po.Customer" table="t_customer"> <!-- 第一部分: 配置实体类唯一属性与表主键的映射关系 --> <id name="id" column="id"> <generator class="native"></generator> </id> <!-- 第二部分:配置实体类其他属性与表的字段的映射关系 --> <property name="name" column="name"></property> <property name="level" column="level"></property> <property name="source" column="source"></property> <property name="phone" column="phone"></property> <property name="mobile" column="mobile"></property> <!-- 第三部分:配置两个实体类之间的映射关系
			name属性:就是客户实体类中联系人Set集合的属性名称
		--> <set name="linkMans" > <!-- 外键配置
				一对多建表有外键:Hibernate机制:双向维护外键,即在一方与多方都要配置外键
				column属性:外键名称
			--> <key column="fk_limlman_customer"></key> <!-- 一方关联多方 
				class属性:一方关联多方的多方的实体类的全限定类名 
			--> <one-to-many class="com.ycom.hibernate.crm.po.LinkMan"/> </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.ycom.hibernate.crm.po.LinkMan" table="t_linkman"> <!-- 第一部分: 配置实体类唯一属性与表主键的映射关系 --> <id name="id" column="id"> <generator class="native"></generator> </id> <!-- 第二部分:配置实体类其他属性与表的字段的映射关系 --> <property name="name" column="name"></property> <property name="gender" column="gender"></property> <property name="phone" column="phone"></property> <!-- 第三部分:配置两个实体类之间的映射关系 --> <!-- 多方关联一方 
			name属性:实体类中关联的一方的属性名称
			class属性:多方关联的一方的全限定类名
			column属性:外键名称,Hibernate要求关联双方必须双向维护外键	
		--> <many-to-one name="customer" class="com.ycom.hibernate.crm.po.Customer" column="fk_limlman_customer"> </many-to-one> </class> </hibernate-mapping> 
  • 第四步:编写核心配置文件:加载映射配置文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC
	"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
	"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- 第一部分:数据库配置 --> <!-- 数据库驱动 --> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <!-- 访问数据库服务器的url --> <property name="hibernate.connection.url">jdbc:mysql:///hibernate05</property> <!-- 访问数据库服务器的用户名 --> <property name="hibernate.connection.username">root</property> <!-- 访问数据库服务器的密码 --> <property name="hibernate.connection.password">root</property> <!-- 第二部分:Hibernate自身的配置 --> <!-- 让Hibernate输出SQL语句 --> <property name="hibernate.show_sql">true</property> <!-- 让Hibenate输出的SQL语句是格式化的SQL语句 --> <property name="hibernate.format_sql">true</property> <!-- 让Hibernate帮助我们创建数据表 --> <property name="hibernate.hbm2ddl.auto">update</property> <!-- 配置MySQL数据库方言 --> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <!-- 获取本地线程Session的配置 --> <property name="hibernate.current_session_context_class">thread</property> <!-- 第三部分:加载映射配置文件 --> <mapping resource="com/ycom/hibernate/crm/po/Customer.hbm.xml"/> <mapping resource="com/ycom/hibernate/crm/po/LinkMan.hbm.xml"/> </session-factory> </hibernate-configuration> 
  • 第五步:测试能否自动创建两张表
    Java持久层之Hibernate(Hibernate操作表之间的关系)
    Java持久层之Hibernate(Hibernate操作表之间的关系)

一对多操作:级联保存

  • 复杂的操作
@Test public void testSave() { Customer customer = new Customer(); customer.setName("AAAAA"); customer.setLevel("Vip"); customer.setSource("网络"); customer.setPhone("110"); customer.setMobile("123456"); LinkMan man1 = new LinkMan(); man1.setName("M1"); man1.setGender("male"); man1.setPhone("123456"); LinkMan man2 = new LinkMan(); man2.setName("M2"); man2.setGender("female"); man2.setPhone("12345678"); // 建立对象的关联关系 // 一方关联多方 customer.getLinkMans().add(man1); customer.getLinkMans().add(man2); // 多方关联一方 man1.setCustomer(customer); man2.setCustomer(customer); SessionFactory sessionFactory = null; Session session = null; Transaction tx = null; try { sessionFactory = HibernateUtils.getSessionFactory(); session = sessionFactory.openSession(); tx = session.beginTransaction(); session.save(customer); session.save(man1); session.save(man2); tx.commit(); } catch (Exception e) { tx.rollback(); } finally { session.close(); sessionFactory.close();//在Web项目开发中不关闭 } } ------------------------------------------------------------------------------- 结果:
Hibernate: insert 
    into
        t_customer (name, level, source, phone, mobile) values (?, ?, ?, ?, ?) Hibernate: insert 
    into
        t_linkman (name, gender, phone, fk_limlman_customer) values (?, ?, ?, ?) Hibernate: insert 
    into
        t_linkman (name, gender, phone, fk_limlman_customer) values (?, ?, ?, ?) Hibernate: update
        t_linkman 
    set
        fk_limlman_customer=? where
        id=? Hibernate: update
        t_linkman 
    set
        fk_limlman_customer=? where
        id=? 

Java持久层之Hibernate(Hibernate操作表之间的关系)
(1) 需要一方关联多方,同样需要多方关联一方
(2) session.sqve()既需要保存一方,也需要报错多方:例如多方有100个,那么需要save一百次

  • 简单的操作:就是对上面的关联关系进行简化,同时对session.save()操作进行简化:前提:需要在一方的映射配置文件中进行相关属性的配置:在客户实体类的映射配置文件中的set标签中进行配置
    (1) 映射配置文件如下
    Java持久层之Hibernate(Hibernate操作表之间的关系)
    (2)程序代码如下
@Test public void testSave2() { Customer customer = new Customer(); customer.setName("AAAAA"); customer.setLevel("Vip"); customer.setSource("网络"); customer.setPhone("110"); customer.setMobile("123456"); LinkMan man1 = new LinkMan(); man1.setName("M1"); man1.setGender("male"); man1.setPhone("123456"); LinkMan man2 = new LinkMan(); man2.setName("M2"); man2.setGender("female"); man2.setPhone("12345678"); // 建立对象的关联关系:只需要关联一次即可 customer.getLinkMans().add(man1); customer.getLinkMans().add(man2); SessionFactory sessionFactory = null; Session session = null; Transaction tx = null; try { sessionFactory = HibernateUtils.getSessionFactory(); session = sessionFactory.openSession(); tx = session.beginTransaction(); // 只需要保存一方对象即可 session.save(customer); tx.commit(); } catch (Exception e) { tx.rollback(); } finally { session.close(); sessionFactory.close();//在Web项目开发中不关闭 } } ------------------------------------------------------------------------------ Hibernate: insert 
    into
        t_customer (name, level, source, phone, mobile) values (?, ?, ?, ?, ?) Hibernate: insert 
    into
        t_linkman (name, gender, phone, fk_limlman_customer) values (?, ?, ?, ?) Hibernate: insert 
    into
        t_linkman (name, gender, phone, fk_limlman_customer) values (?, ?, ?, ?) Hibernate: update
        t_linkman 
    set
        fk_limlman_customer=? where
        id=? Hibernate: update
        t_linkman 
    set
        fk_limlman_customer=? where
        id=? 

(3)结果:
Java持久层之Hibernate(Hibernate操作表之间的关系)

一对多操作:级联删除

  • 级联删除:删除主表中的记录,子表中的所有关联的记录都被删除
  • 先查询主表中的记录得到持久化的对象,执行删除操作
  • 代码
@Test public void testDeleteCascade() { SessionFactory sessionFactory = null; Session session = null; Transaction tx = null; try { sessionFactory = HibernateUtils.getSessionFactory(); session = sessionFactory.openSession(); tx = session.beginTransaction(); Customer customer = session.get(Customer.class, 4); session.delete(customer); tx.commit(); } catch (Exception e) { tx.rollback(); } finally { session.close(); sessionFactory.close();//在Web项目开发中不关闭 } } 

*结果:
Java持久层之Hibernate(Hibernate操作表之间的关系)

  • 删除主表中的记录,子表中关联的记录是逻辑删除,即并不是真正的删除子表中的关联记录,而是将子表中关联的记录的外键字段置为NULL:如果要达到级联删除的目的,需要在映射配置文件中进行相关的配置:在一方的映射配置文件中的set标签中的cascade属性添加delete值
    Java持久层之Hibernate(Hibernate操作表之间的关系)
  • 执行过程
    Java持久层之Hibernate(Hibernate操作表之间的关系)
  • 那么问题来了:既然是要删除子表中关联的记录,那么在删除之间为什么还需要进行外键字段的置空操作呢?实际上直接先删除子表中的关联记录再删除主表中的记录即可!不需要再搞什么update操作了:之所以有这个操作是因为:Hibernate双向维护外键,一方与多方都需要维护外键!解决办法:让其中一方放弃维护外键:在一对多的关系中让一方放弃维护外键:需要在一方的映射配置文件中的set标签的inverse属性值为true
    Java持久层之Hibernate(Hibernate操作表之间的关系)
  • 注意:不能在任何时候都放弃外键关系的维护:如果是这样那就不能做级联添加了:子表记录的外键字段为NULL,因为一方没有维护外键是不行的

一对多修改(inverse=true)

Java持久层之Hibernate(Hibernate操作表之间的关系)

@Test public void testUpdateCascade() { SessionFactory sessionFactory = null; Session session = null; Transaction tx = null; try { sessionFactory = HibernateUtils.getSessionFactory(); session = sessionFactory.openSession(); tx = session.beginTransaction(); Customer customer = session.get(Customer.class, 12); LinkMan man = session.get(LinkMan.class, 21); customer.getLinkMans().add(man); man.setCustomer(customer); System.out.println(customer); System.out.println(man); tx.commit(); } catch (Exception e) { tx.rollback(); } finally { session.close(); sessionFactory.close();//在Web项目开发中不关闭 } } ---------------------------------------------------------------------------- Hibernate: select
        customer0_.id as id1_0_0_, customer0_.name as name2_0_0_, customer0_.level as level3_0_0_, customer0_.source as source4_0_0_, customer0_.phone as phone5_0_0_, customer0_.mobile as mobile6_0_0_ 
    from
        t_customer customer0_ 
    where
        customer0_.id=? Hibernate: select
        linkman0_.id as id1_1_0_, linkman0_.name as name2_1_0_, linkman0_.gender as gender3_1_0_, linkman0_.phone as phone4_1_0_, linkman0_.fk_limlman_customer as fk_limlm5_1_0_ 
    from
        t_linkman linkman0_ 
    where
        linkman0_.id=? Hibernate: select
        linkmans0_.fk_limlman_customer as fk_limlm5_1_0_, linkmans0_.id as id1_1_0_, linkmans0_.id as id1_1_1_, linkmans0_.name as name2_1_1_, linkmans0_.gender as gender3_1_1_, linkmans0_.phone as phone4_1_1_, linkmans0_.fk_limlman_customer as fk_limlm5_1_1_ 
    from
        t_linkman linkmans0_ 
    where
        linkmans0_.fk_limlman_customer=? Customer [id=12, name=BBBBB, level=null, source=null, phone=null, mobile=null] LinkMan [id=21, name=M2, gender=female, phone=12345678, customer=Customer [id=12, name=BBBBB, level=null, source=null, phone=null, mobile=null]] Hibernate: update
        t_linkman 
    set
        name=?, gender=?, phone=?, fk_limlman_customer=? where
        id=? Hibernate: update
        t_linkman 
    set
        fk_limlman_customer=? where
        id=? 

Java持久层之Hibernate(Hibernate操作表之间的关系)
Java持久层之Hibernate(Hibernate操作表之间的关系)

  • inverse属性:因为Hibernate双向维护外键,在客户和联系人里面都需要维护外键,修改客户时候修改一次外键,修改联系人时候也修改一次外键,造成效率问题
  • 解决方式:让其中的一方不维护外键:一对多里面,让其中一方放弃外键维护
    Java持久层之Hibernate(Hibernate操作表之间的关系)
    Java持久层之Hibernate(Hibernate操作表之间的关系)
  • 上面说错了 :

Hibernate多对多操作

本文地址:https://blog.csdn.net/MOOG007/article/details/107900140

相关标签: Java Hibernate