相信各位技术大牛应该一眼就看懂了,我呢,只是个菜鸟,只不过想在交流中进步。故工作之余会谢谢博客。下面是Hibernate的一对多关系的对象保存到数据库的一个图文分析。在使用Hibernate框架开发时,一般不会涉及这些Hibernate的API语句,不过一对多关系在开发中却经常用到,相关的业务需求也是非常多。
备注一下:下边的代码有些不是很标准,不过本人没有去改,不过大致可以看出各个图的各种情况所对应的代码。
以下情况是在非注解方式的分析(即一个实体类对应一个xml配置文件)。
环境:
1、假设有俩个实体类(客户Customer【一方】和联系人LinkMan【多方】);
2、实体类中互相有对方的属性,如:
客户实体类中有private Set<LinkMan> custLinkMan = new HashSet<LinkMan>(0);
联系人实体类中有private Customer lkmCustomer;
3、客户类对应的Customer.hbm.xml中除了其他属性的配置,还有的就是如下的一对多关系的映射
<set name="custLinkMan"> <!-- 此处不写inverse属性,后面图文中体现-->
<key column="lkm_cust_id"></key>
<one-to-many class="com.syh.entity.LinkMan" />
</set>
联系人类对应的LinkMan.hbm.xml中除了其他属性的配置,也有如下的关系映射配置
<many-to-one cascade="save-update" name="lkmCustomer" class="com.syh.entity.Customer" column="lkm_cust_id"></many-to-one>
4、准备一个HibernateUtil工具类,使用里面绑定了线程的方法得到session,其实因为这个不是正经开发,刻意使用普通的得到session的方法。
在保存一对多关系的实体对象到数据库的时候我们需要关注几个影响条件:
1、保存的方向性:在客户实体类中有设置联系人属性的方法,也就是那个setter方法,不过因为是set集合引用对象,实际上getter方法就够了,例如customer.getCustLinkMan().add(linkman)这个A(为了减少代码量,我先用A和B替代这个)方法就可以了;而在联系人实体类中使用的是如linkman.setLkmCustomer(costomer)这个B方法。
前面简单说明一下,这里保存的方向性指的是程序中有A方法而没有B方法(单向关系:客户知道了联系人),有B方法而没有A方法(单向关系:联系人知道了客户),有A和B俩个都存在(双向关系)。
2、保存的顺序(先保存客户还是先保存联系人的问题);
3、客户的配置文件中是否放弃维护权,即是否设置了inverse=“true”,这个只有一方有,而多方是一定会维护的,因为外键本来就是多方表的;
造成的结果我们需要关注几个东西:
1、Hibernate发送到数据库的sql语句数;
2、是否成功插入到数据库;
3、Hibernate发送的sql语句的异同;
在这里我们只分析上述影响条件下的情况,根据排列组合3*2*2=12种情况,实际上还有单双向保存(只保存客户或只保存联系人的情况)以及级联cascade属性(不级联、客户级联、联系人级联、都级联)的问题,但加上这些,情况会变成12*3*4=144种情况,本人才疏学浅时间有限,就简单说一下以下12种情况吧。
先看图:
图一如下:
该图为联系人知道客户,即只有linkman.setLkmCustomer(costomer)这个方法。然后根据保存顺序和是否放弃维护权来看结果。
而该图的结果:
1)sql语句数在图里了;
2)都成功插入数据到数据库;
3)Hibernate发送的sql语句也体现在图里了;
图中右下角是简单的分析,需要一级缓存和快照机制的知识为基础,如果不明白欢迎给本人留言,欢迎互相交流。
如果看到图二图三,会发现第3句sql语句有不一样的地方,这是因为外键的维护权在不在一方也就是维护权在不在客户的问题。
图一对应的代码:
public class TestOneToMany1 { @Test public void test1() { /** * 单向关系:联系人知道客户 * 保存顺序:先保存联系人,后保存客户 * 配置:默认(客户参与维护外键) * * 结果:出现3条sql语句 * 原因: */ Session session = HibernateUtil.getCurrentSession(); Transaction transaction = session.beginTransaction(); //=================================================== //客户实例化 Customer c = new Customer(); c.setCustName("客户001"); //联系人实例化 LinkMan l = new LinkMan(); l.setLkmName("1联系人1"); //单向关系:联系人->客户 l.setLkmCustomer(c); //保存 session.save(l); //保存联系人 LinkMan session.save(c); //保存客户 Customer //=================================================== transaction.commit(); } @Test public void test2() { /** * 单向关系:联系人知道客户 * 保存顺序:先保存联系人,后保存客户 * 配置:inverse="true"(客户不参与维护外键) * * 结果:出现3条sql语句 * 原因: */ Session session = HibernateUtil.getCurrentSession(); Transaction transaction = session.beginTransaction(); //=================================================== //客户实例化 Customer c = new Customer(); c.setCustName("客户001"); //联系人实例化 LinkMan l = new LinkMan(); l.setLkmName("2联系人1"); //单向关系:联系人->客户 l.setLkmCustomer(c); //保存 session.save(l); //保存联系人 LinkMan session.save(c); //保存客户 Customer //=================================================== transaction.commit(); } @Test public void test3() { /** * 单向关系:联系人知道客户 * 保存顺序:先保存客户,后保存联系人 * 配置:inverse="true"(客户不参与维护外键) * * 结果:出现2条sql语句 * 原因: */ Session session = HibernateUtil.getCurrentSession(); Transaction transaction = session.beginTransaction(); //=================================================== //客户实例化 Customer c = new Customer(); c.setCustName("客户001"); //联系人实例化 LinkMan l = new LinkMan(); l.setLkmName("3联系人1"); //单向关系:联系人->客户 l.setLkmCustomer(c); //保存 session.save(c); //保存客户 Customer session.save(l); //保存联系人 LinkMan //=================================================== transaction.commit(); } @Test public void test4() { /** * 单向关系:联系人知道客户 * 保存顺序:先保存客户,后保存联系人 * 配置:默认(客户参与维护外键) * * 结果:出现2条sql语句 * 原因: */ Session session = HibernateUtil.getCurrentSession(); Transaction transaction = session.beginTransaction(); //=================================================== //客户实例化 Customer c = new Customer(); c.setCustName("客户001"); //联系人实例化 LinkMan l = new LinkMan(); l.setLkmName("4联系人1"); //单向关系:联系人->客户 l.setLkmCustomer(c); //保存 session.save(c); //保存客户 Customer session.save(l); //保存联系人 LinkMan //=================================================== transaction.commit(); } }
图二如下:
该图为客户知道联系人,即只有customer.getCustLinkMan().add(linkman)这个方法。然后根据保存顺序和是否放弃维护权来看结果。
而该图的结果:
1)sql语句数在图里了;
2)插入数据到数据库中有俩条记录没有外键;
3)Hibernate发送的sql语句也体现在图里了;
左上角为第一种情况最左边那种情况的简单的分析,右上角是插入到数据库的情况。
插入数据异常的原因:
客户知道联系人,但由于设置了inverse="true"放弃了维护权,而联系人却不知道客户,想维护外键也维护不了,因此,无论先保存联系人还是先保存客户,设置了inverse=“true”的时候都会造成外键为空。
图二对应代码:
public class TestOneToMany2 { @Test public void test1() { /** * 单向关系:客户知道联系人 * 保存顺序:先保存联系人,后保存客户 * 配置:默认(客户参与维护外键) * * 结果:出现3条sql语句 * 原因: */ Session session = HibernateUtil.getCurrentSession(); Transaction transaction = session.beginTransaction(); //=================================================== //客户实例化 Customer c = new Customer(); c.setCustName("客户002"); //联系人实例化 LinkMan l = new LinkMan(); l.setLkmName("1联系人2"); //单向关系:客户->联系人 //l.setLkmCustomer(c); c.getCustLinkMan().add(l); //保存 session.save(l); //保存联系人 LinkMan session.save(c); //保存客户 Customer //=================================================== transaction.commit(); } @Test public void test2() { /** * 单向关系:联系人知道客户 * 保存顺序:先保存联系人,后保存客户 * 配置:inverse="true"(客户不参与维护外键) * * 结果:出现2条sql语句,无法建立外键 * 原因: */ Session session = HibernateUtil.getCurrentSession(); Transaction transaction = session.beginTransaction(); //=================================================== //客户实例化 Customer c = new Customer(); c.setCustName("客户002"); //联系人实例化 LinkMan l = new LinkMan(); l.setLkmName("2联系人2"); //单向关系:客户->联系人 //l.setLkmCustomer(c); c.getCustLinkMan().add(l); //保存 session.save(l); //保存联系人 LinkMan session.save(c); //保存客户 Customer //=================================================== transaction.commit(); } @Test public void test3() { /** * 单向关系:联系人知道客户 * 保存顺序:先保存客户,后保存联系人 * 配置:inverse="true"(客户不参与维护外键) * * 结果:出现2条sql语句,无法建立外键 * 原因: */ Session session = HibernateUtil.getCurrentSession(); Transaction transaction = session.beginTransaction(); //=================================================== //客户实例化 Customer c = new Customer(); c.setCustName("客户002"); //联系人实例化 LinkMan l = new LinkMan(); l.setLkmName("3联系人2"); //单向关系:客户->联系人 //l.setLkmCustomer(c); c.getCustLinkMan().add(l); //保存 session.save(c); //保存客户 Customer session.save(l); //保存联系人 LinkMan //=================================================== transaction.commit(); } @Test public void test4() { /** * 单向关系:联系人知道客户 * 保存顺序:先保存客户,后保存联系人 * 配置:默认(客户参与维护外键) * * 结果:出现3条sql语句 * 原因: */ Session session = HibernateUtil.getCurrentSession(); Transaction transaction = session.beginTransaction(); //=================================================== //客户实例化 Customer c = new Customer(); c.setCustName("客户002"); //联系人实例化 LinkMan l = new LinkMan(); l.setLkmName("4联系人2"); //单向关系:客户->联系人 //l.setLkmCustomer(c); c.getCustLinkMan().add(l); //保存 session.save(c); //保存客户 Customer session.save(l); //保存联系人 LinkMan //=================================================== transaction.commit(); } }
图三如下:
该图为双向关系,即既有customer.getCustLinkMan().add(linkman)这个方法,也有linkman.setLkmCustomer(costomer)。然后根据保存顺序和是否放弃维护权来看结果。
而该图的结果:
1)sql语句数在图里了;
2)都成功插入数据到数据库(图二右上角的最后4条数据);
3)Hibernate发送的sql语句也体现在图里了;
在这里解释一下为什么第3句sql语句会有所不同:
假如所有情况都由客户去维护外键,那么发送的第3句sql语句一定是只维护了主键,即下图中中间那个sql语句;
但由于有些情况是多方维护了外键,也就是联系人自己维护外键,所以会出现下图右下角的那个sql语句。
至于多方自己维护外键会更新自己全部的信息,这个要去研究Hibernate的源码,本人菜鸟一个,这个就交给各位大神了。
图三对应代码:
public class TestOneToMany3 { @Test public void test1() { /** * 单向关系:联系人知道客户,客户知道联系人 * 保存顺序:先保存联系人,后保存客户 * 配置:默认(客户参与维护外键) * * 结果:出现3条sql语句 * 原因: */ Session session = HibernateUtil.getCurrentSession(); Transaction transaction = session.beginTransaction(); //=================================================== //客户实例化 Customer c = new Customer(); c.setCustName("客户003"); //联系人实例化 LinkMan l = new LinkMan(); l.setLkmName("1联系人3"); //单向关系:联系人->客户、客户->联系人 l.setLkmCustomer(c); c.getCustLinkMan().add(l); //保存 session.save(l); //保存联系人 LinkMan session.save(c); //保存客户 Customer //=================================================== transaction.commit(); } @Test public void test2() { /** * 单向关系:联系人知道客户,客户知道联系人 * 保存顺序:先保存联系人,后保存客户 * 配置:inverse="true"(客户不参与维护外键) * * 结果:出现3条sql语句 * 原因: */ Session session = HibernateUtil.getCurrentSession(); Transaction transaction = session.beginTransaction(); //=================================================== //客户实例化 Customer c = new Customer(); c.setCustName("客户003"); //联系人实例化 LinkMan l = new LinkMan(); l.setLkmName("2联系人3"); //单向关系:联系人->客户、客户->联系人 l.setLkmCustomer(c); c.getCustLinkMan().add(l); //保存 session.save(l); //保存联系人 LinkMan session.save(c); //保存客户 Customer //=================================================== transaction.commit(); } @Test public void test3() { /** * 单向关系:联系人知道客户,客户知道联系人 * 保存顺序:先保存客户,后保存联系人 * 配置:inverse="true"(客户不参与维护外键) * * 结果:出现2条sql语句 * 原因: */ Session session = HibernateUtil.getCurrentSession(); Transaction transaction = session.beginTransaction(); //=================================================== //客户实例化 Customer c = new Customer(); c.setCustName("客户003"); //联系人实例化 LinkMan l = new LinkMan(); l.setLkmName("3联系人3"); //单向关系:联系人->客户、客户->联系人 l.setLkmCustomer(c); c.getCustLinkMan().add(l); //保存 session.save(c); //保存客户 Customer session.save(l); //保存联系人 LinkMan //=================================================== transaction.commit(); } @Test public void test4() { /** * 单向关系:联系人知道客户,客户知道联系人 * 保存顺序:先保存客户,后保存联系人 * 配置:默认(客户参与维护外键) * * 结果:出现3条sql语句 * 原因: */ Session session = HibernateUtil.getCurrentSession(); Transaction transaction = session.beginTransaction(); //=================================================== //客户实例化 Customer c = new Customer(); c.setCustName("客户003"); //联系人实例化 LinkMan l = new LinkMan(); l.setLkmName("4联系人3"); //单向关系:联系人->客户、客户->联系人 l.setLkmCustomer(c); c.getCustLinkMan().add(l); //保存 session.save(c); //保存客户 Customer session.save(l); //保存联系人 LinkMan //=================================================== transaction.commit(); } }
相关推荐
Hibernate支持一对一、一对多、多对一和多对多关系映射,如List、Set、Map等集合类型,通过配置XML映射文件来实现复杂的数据结构。 10. **延迟加载与立即加载** 延迟加载(Lazy Loading)是Hibernate的一个重要...
Hibernate ORM,全称Hibernate Object Relational Mapping,是Java领域中一款广泛应用的开源对象关系映射框架。它为开发者提供了一种将面向对象的模型与传统的关系数据库之间的转换工具,极大地简化了Java应用的数据...
在JavaEE开发中,Hibernate是一个非常重要的对象关系映射(ORM)框架,它极大地简化...通过分析这些代码,你将能更好地掌握Hibernate一对多关系的配置和使用。同时,也可以尝试修改配置或业务逻辑,以加深理解和应用。
Hibernate作为Java领域广泛使用的ORM框架,它极大地简化了数据库操作,将面向对象的编程思想与关系型数据库相结合,使得开发者可以更加专注于业务逻辑,而不是繁琐的SQL语句。在本书中,作者深入浅出地讲解了如何...
这个“hibernate框架基本包”包含了一系列必要的库文件,使得开发者能够轻松地将数据库操作与业务逻辑集成,从而减少对SQL的直接依赖。这个包与相关的博客内容配合,提供了学习Hibernate的完整资源。 **1. ...
字段映射使用@Column,主键用@Id,一对多、多对一、一对一等关系映射使用@OneToOne、@OneToMany、@ManyToOne等注解。 3. **Session与Transaction**:Session是操作数据库的对象,负责持久化对象,它支持CRUD...
3. **一对多关联**:例如,一个部门可以有多个员工,这可以通过在部门类上使用`@OneToMany`注解和在员工类上使用`@ManyToOne`注解来建立。`@JoinColumn`或`@JoinTable`用于指定关系。 4. **多对多关联**:当两个...
3.3 关联映射:@OneToOne、@OneToMany、@ManyToOne、@ManyToMany注解用于处理不同类型的关联关系,包括一对一、一对多、多对一和多对多。 四、Hibernate操作数据库 4.1 Session接口:Session是与数据库进行交互的...
8. **多对一、一对多、多对多关系映射**:在Hibernate中,可以轻松处理各种对象间的关联关系。例如,一个User可以有多个Post(一对多),一个Department可以有多个Employee(多对多)。 9. **级联操作**:在处理...
在Java的持久化框架Hibernate中,多对一(ManyToOne)关联关系是一种常见的对象关系映射(ORM)场景。这种关系通常出现在一个实体类拥有多条与另一个实体类相关的记录,而另一个实体类可能只有一条对应的记录。例如...
- 一对多(One-to-Many)、多对一(Many-to-One)、一对一(One-to-One)、多对多(Many-to-Many)关系的映射和处理。 - 支持懒加载(Lazy Loading)和立即加载(Eager Loading)策略。 11. **其他特性** - 支持...
标题"Hibernate双向一对多"指的是Hibernate框架中的一个重要关系映射概念,即在一个实体类中,一个实例可以与多个另一个实体类的实例相关联,而在另一个实体类中,每个实例也可以关联到该实体类的一个实例。这种关系...
Hibernate是一个强大的对象关系映射(ORM)工具,它简化了Java应用程序对数据库的操作,允许开发者以面向对象的方式处理数据,而无需直接编写SQL语句。 【知识点详述】 1. **JSP(JavaServer Pages)**:JSP是Java...
Hibernate 是一款开源的对象关系映射(ORM)框架,它极大地简化了Java应用程序对数据库的操作。这个框架允许开发者用面向对象的方式来处理数据库操作,从而避免了传统SQL语句的繁琐和易错性。在这个“hibernate框架...
- **集合映射**:如List, Set, Map等,以及一对多、多对一、一对一、多对多的关联映射。 - **级联操作**:在父对象操作时,自动处理子对象的增删改查。 - **动态模型**:允许在运行时动态创建和修改对象的映射。 **...
本案例主要探讨的是Hibernate中的一对多关系映射,这是一种常见的对象关系映射(ORM)配置,用于表示一个实体与多个其他实体之间的关联。 在传统的数据库设计中,一对多关系是指一个表(父表)中的记录可以与另一个...
Hibernate通过`<class>`标签(XML映射)或@Entity注解(注解映射)定义实体类,`<id>`表示主键,`<property>`或@Basic对应字段,`<many-to-one>`或@ManyToOne处理一对多关系,`<one-to-many>`或@OneToMany处理多对...
标题 "Hibernate基于连接表的一对多单向关联" 涉及的是数据库对象关系映射(ORM)框架Hibernate中的一个重要概念。在Java开发中,Hibernate是广泛使用的工具,它允许开发者将Java类与数据库表进行映射,简化了数据...
在这个"hibernate一对多关系"的资源中,我们主要探讨的是Hibernate如何处理一个实体类与多个实体类之间的关联关系。 在数据库设计中,一对多关系是非常常见的一种关系类型,比如一个部门可以有多个员工,一个学生...
7. **一对多、多对一、多对多关系映射**:详细解释这三种关联类型,如何在实体类和映射文件中配置,以及在实际操作中的注意事项。 8. **缓存机制**:介绍Hibernate的两级缓存(第一级缓存和第二级缓存),以及查询...