这章我们就来学习下hibernate的关系关联,即一对一(one-to-one),一对多(one-to-many),多对多(many-to-many)。这章也将是hibernate的最后一章了,用于初学者可以了。

首先讲述一对一:就以一个人对应一张身份证为列子。

第一步:新建表 persion(人)与card(身份证) 表结构如下  两个pid都给的varchar是为了在主键生成策略中使用uuid

第二步:项目/com.entity下新建两个实体类,与数据库对应,然后封装构造,有参构造中去掉pid。建好后再新建这两个类的hbm.xml文件,在persion.hbm.xml中将<id/>节点中的主键生成策略改成uuid

    <id name="pid" type="java.lang.String">
<column name="PID" />
//改uuid
<generator class="uuid" />
</id>

将card.hbm.xml中的<id/>节点中的主键生成策略改成foreign,等于外键的意思

<id name="pid" type="java.lang.String">
<column name="PID" />
<!-- 主键生成策略 改成外键 -->
<generator class="foreign">
</generator>
</id>

第三步:就要开始建立一对一关系了:先在persion实体类中定义一个card的对象,记住不要实例化(new),然后封装。

private Card card;
public Card getCard() {
return card;
} public void setCard(Card card) {
this.card = card;
}

接着在card实体类中定义一个persion的对象,也不要实例化(new),然后封装。

    private Person person;

    public Person getPerson() {
return person;
} public void setPerson(Person person) {
this.person = person;
}

第四步:就要开始建立一对关系的配置了。在persion.hbm.xml<class/>节点中添加<one-to-one/>节点;其中name属性值为persion实体类中定义的card对象的变量名。            

    <one-to-one name="card" class="com.entity.Card" cascade="all"></one-to-one>

在card.hbm.xml<class/>节点中添加<one-to-one/>节点;其中name属性值为card实体类中定义的persion对象的变量名。    

<one-to-one name="person" class="com.entity.Person"></one-to-one>

还要在card.hbm.xml主键生成策略中添加一个参数<param/>,其中name属性值为固定写法,persion为card实体类中定义的persion对象的变量名。  

<id name="pid" type="java.lang.String">
<column name="PID" />
<!-- 主键生成策略 改成外键 -->
<generator class="foreign">
<param name="property">person</param>
</generator>
</id>

配置到这里就完了。那么有人肯定会有疑问?

persion.hbm.xml 中的<one-to-one/>中cascade="all"是什么意思?

cascade这个属性就相当与两张表的关联属性,有以下属性值

none:所有情况下均不进行关联操作。这是默认值。 

all:所有情况下均进行关联操作

save-update:在执行save/update/saveOrUpdate时进行关联操作。

delete:在执行delete时进行关联操作。

all-delete-orphan:当对象图中产生孤儿节点时,在数据库中删除该节点

就拿delete来说吧,就是删除persion的对象数据时,对应的card对象数据也将被删除。

第五步:hibernate.cfg.xml配置文件中加上实体类.hbm.xml的映射关系<mapping/>

<mapping resource="com/entity/Card.hbm.xml" />
<mapping resource="com/entity/Person.hbm.xml" />

第六步:就要开始测试了:建立一个测试类,其中写个junit的@Test测试方法。

既然用了@Tset,那么就在再用下@Before(方法执行之前触发)与@Aafter(方法执行之后触发),这样我们就可以将重复的代码写在这两个方法里面,减轻代码量

private Configuration configuration;

private SessionFactory factory;

private Session session;

private Transaction transaction;


@Before
public void Before() {
configuration = new Configuration().configure();
factory = configuration.buildSessionFactory();
session = factory.openSession();
transaction = session.beginTransaction();
}
@After
public void after() {
// 关闭seeion
session.close();
// 关闭SessionFactory
factory.close();
}

增加:注意要互相添加值(互设)

@Test
    public void add() {

  // 增加
Person p = new Person("哈哈");
Card c = new Card("431088192215523305");
互设
p.setCard(c);
c.setPerson(p);
//这里因为建立cascade关联关系,所以只要添加设立了关系那端即可
session.save(p);
transaction.commit();
}

查询:

    // 查询
Person p = session.get(Person.class,
"4028abee5f2a0142015f2a0144280000");
System.out.println(p+"--"+p.getCard());

其余我就不再测试了。

接下来讲述一对多:以一个省份对应多个城市为例子。

第一步:一样要新建两张表,province(省份)与城市(city),表结构如下:

第二步:项目/com.entity下新建两个实体类,与数据库对应,然后封装构造,有参构造中去掉表主键。建好后再新建这两个类的hbm.xml文件,在province.hbm.xml与city.hbm.xml中将<id/>节点中的主键生成策略改成uuid。

第三步:在province(一端)实体类中定义并实例化city(多端)的集合,(set与list)以set为例。然后封装即可。

    private Set<City> cities = new HashSet<>();

        public Set<City> getCities() {
return cities;
} public void setCities(Set<City> cities) {
this.cities = cities;
}

第四步:在city(多端)实体类中定义province(一端)对象,封装。注意:这个时候要将pid(多端表中一端表外键)这个属性在city的实体类中去掉(数据库表中依然存在),因为已经定义的province的对象,同时请将city.hbm.xml中所对应生成pid的<property/>节点也去掉!

     private Province province;

     public Province getProvince() {
return province;
} public void setProvince(Province province) {
this.province = province;
}

第五步:在一端的hbm.xml中<class/>节点中添加如下代码:

<!--name 一端类中定义多端的集合名 table 表名 -->
<set name="cities" table="city" inverse="true" cascade="save-update">
<key>
<!-- 一端(province)主键名 -->
<column name="pid" />
</key>
<!-- 多端类(city)全限定名 -->
<one-to-many class="com.entity.City" />
</set>

 在多端的hbm.xml中<class/>节点中添加如下代码:

<!--name="多端类中定义一端的集合名" class="一端类全限定名" -->
<many-to-one name="province" class="com.entity.Province">
<!-- 多端表中外键名(一端主键名) -->
<column name="pid" />
</many-to-one>

第六步:hibernate.cfg.xml配置文件中加上实体类.hbm.xml的映射关系<mapping/>

<mapping resource="com/entity/Province.hbm.xml" />
<mapping resource="com/entity/City.hbm.xml" />

这样配置就可以了,那么疑问又来了?在一端的hbm.xml<set/>中inverse又是什么?

Inverse:负责控制关系,默认为false,也就是关系的两端都能控制,但这样会造成一些问题,更新的时候会因为两端都控制关系,于是重复更新。一般来说有一端要设为true。那么SQL语句的维护关系就在多端进行操作。

第七步:测试:@Test就与一对一的测试方法一样即可

增加:

         Province p = new Province("湖南");
City c = new City("长沙");
City c1 = new City("株洲");
City c2 = new City("湘潭");
//互设
p.getCities().add(c);
p.getCities().add(c1);
p.getCities().add(c2); c.setProvince(p);
c1.setProvince(p);
c2.setProvince(p); session.save(p); transaction.commit();

查询:

    City c = (City) session.createQuery("from City where cname=?").setParameter(, "长沙").uniqueResult();
System.out.println(c.getProvince().getPid());

其余的方法就不测试了。

最后讲述多对多:就以多个角色对应多个权限,多个权限对应多个角色为例子:

第一步:还是老样子建表:角色表(users),权限表(role),还要一张中间表(users_role),表结构如下:

第二步:项目/com.entity下新建两个实体类,中间表不用,与数据库对应,然后封装构造,有参构造中去掉表主键。建好后再新建这两个类的hbm.xml文件,在hbm.xml中将<id/>节点中的主键生成策略改成uuid。

第三步:在这两个实体类中定义并实例化对方的集合,(set与list)以set为例。然后封装即可。

第四步:在users.hbm.xml中添加如下代码:

//name=集合对象名  table=中间表名 
<set name="roles" table="users_role" inverse="true" cascade="save-update">
//该类主键名
<key column="uid"></key>
//calss set集合中对象的全路径名 column外键名(set集合中对象的主键名)
<many-to-many class="com.entity.Role" column="rid" />
</set>

在role.hbm.xml中添加如下代码:


//name=集合对象名  table=中间表名 
<set name="users" table="users_role" inverse="true" cascade="save-update">
//该类主键名
<key column="rid"></key>
//calss set集合中对象的全路径名 column外键名(set集合中对象的主键名)
<many-to-many class="com.entity.Users" column="uid" />
</set>

第六步:hibernate.cfg.xml配置文件中加上实体类.hbm.xml的映射关系<mapping/>

    <mapping resource="com/entity/Users.hbm.xml" />
<mapping resource="com/entity/role.hbm.xml" />

最后测试:

增加:

         Users u = new Users("哈哈");
Role r = new Role("草鸡管理员");
Role r1 = new Role("普通管理员");
Role r2 = new Role("垃圾管理员"); u.getRoles().add(r);
u.getRoles().add(r1);
u.getRoles().add(r2); r.getUsers().add(u);
r1.getUsers().add(u);
r2.getUsers().add(u); transaction.commit();

查询:

Users s = session.get(Users.class, "4028abee5f664493015f6644959b0001");
     for (Role r : s.getRoles()) {
       System.out.println(r);
         }

//List<Users> ls = session.createQuery("from Users u left outer join fetch u.roles r where r.rid='4028abee5f664493015f6644958a0000'").list();
// for (Users users : ls) {
// System.out.println(users.getRoles());
// }

到此,hibernate结束!

初学者易上手的SSH-hibernate04 一对一 一对多 多对多的更多相关文章

  1. JPA级联(一对一 一对多 多对多)注解【实际项目中摘取的】并非自己实际应用

    下面把项目中的用户类中有个:一对一  一对多  多对多的注解对应关系列取出来用于学习      说明:项目运行正常 问题类:一对多.一对一.多对多 ============一对多 一方的设置 @One ...

  2. Python进阶----表与表之间的关系(一对一,一对多,多对多),增删改查操作

    Python进阶----表与表之间的关系(一对一,一对多,多对多),增删改查操作,单表查询,多表查询 一丶表与表之间的关系 背景: ​ ​ ​  ​ ​ 由于如果只使用一张表存储所有的数据,就会操作数 ...

  3. mybatis 一对一 一对多 多对多

    一对一 一对多 多对多

  4. 使用NHibernate(7)-- 一对一 && 一对多 && 多对多

    1, 一对一. 对于数据量比较大的时候,考虑查询的性能,肯能会把一个对象的属性分到两个表中存放:比如用户和用户资料,经常使用的一般是Id和用户名,用户资料(学校,籍贯等)是不经常被查询的,所以就会分成 ...

  5. day 69-70 一对一 一对多 多对一联表查询

    day 69 orm操作之表关系,多对多,多对一 多对一/一对多, 多对多{类中的定义方法} day69 1. 昨日内容回顾 1. 单表增删改查 2. 单表查询API 返回QuerySet对象的: 1 ...

  6. JPA 一对一 一对多 多对一 多对多配置

    1 JPA概述 1.1 JPA是什么 JPA (Java Persistence API) Java持久化API.是一套Sun公司 Java官方制定的ORM 方案,是规范,是标准 ,sun公司自己并没 ...

  7. 初学者易上手的SSH-struts2 01环境搭建

    首先,SSH不是一个框架,而是多个框架(struts+spring+hibernate)的集成,是目前较流行的一种Web应用程序开源集成框架,用于构建灵活.易于扩展的多层Web应用程序. 集成SSH框 ...

  8. 初学者易上手的SSH-struts2 05拦截器与自定义拦截器

    因为自己对于struts2也不是很了解,这章将是struts2的最后一章了.那么这一章主要介绍的是拦截器以及怎么样来自定义一个拦截器. struts2的拦截器位于struts2-core(核心包)-& ...

  9. 初学者易上手的SSH-hibernate01环境搭建

    这里我们继续学习SSH框架中的另一框架-hibernate.那么hibernate是什么?Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序 ...

随机推荐

  1. 2019春第八周作业Compile Summarize

    这个作业属于那个课程 C语言程序设计II 这个作业要求在哪里 在这里 我在这个课程的目标是 能更加进一步的够熟练掌握指针的用法 这个作业在那个具体方面帮助我实现目标 指针对于高阶题目的做法 参考文献与 ...

  2. ORACLE——EXTRACT() 截取日期时间的函数使用

    1.截取日期的 年: --使用方法 EXTRACT(YEAR FROM DATE) SQL> SELECT EXTRACT( YEAR FROM SYSDATE ) FROM DUAL; --结 ...

  3. struts 2.5配置

    1.jar包的变动 必需jar包,旧版本: 必需jar包,新版本: 在struts-2.5.16版本的lib目录下没有xwork-core的jar包,原因是被合并到struts-core这个jar里了 ...

  4. extjs 跨域 ajax.request

    https://www.cnblogs.com/yuzhongwusan/p/3677955.html https://stackoverflow.com/questions/25727306/req ...

  5. sping Bean 的生命周期是如何被管理

    1. 实例化一个Bean,也就是我们通常说的new 2. 按照Spring上下文对实例化的Bean进行配置,也就是IOC注入 3. 如果这个Bean实现了BeanNameAware接口,会调用它实现的 ...

  6. Linux的发展历史

    创始人: linux操作系统由林纳斯·本纳第克特·托瓦兹编写而成,是管理电脑硬件以及运行电脑软件的操作系统. 创始发展过程:Linux操作系统的诞生.发展和成长过程始终依赖着五个重要支柱:UNIX 操 ...

  7. TCP 数据传输工具类

    package com.ivchat.test.propertysystem.util; import java.io.BufferedReader;import java.io.ByteArrayO ...

  8. Aspose是一个很强大的控件,可以用来操作word,excel,ppt等文件

    Aspose是一个很强大的控件,可以用来操作word,excel,ppt等文件,用这个控件来导入.导出数据非常方便.其中Aspose.Cells就是用来操作Excel的,功能有很多.我所用的是最基本的 ...

  9. Django中上传图片---避免因图片重名导致被覆盖

    上一篇文章中(https://www.cnblogs.com/lutt/p/10640412.html),我们以图片文件夹+图片名字的方式来储存图片,这样的做法会导致有重名的图片会导致之前的图片被覆盖 ...

  10. Oracle中row_number()、rank()、dense_rank() 的区别

    link:https://www.cnblogs.com/qiuting/p/7880500.html