【Hibernate】Hibernate系列(一)
来源:互联网 发布:fm球员在线数据库 编辑:程序博客网 时间:2024/05/18 13:04
【概念】
Hibernate是一个持久化的框架,它对JDBC进行了轻量级的封装。对于源程序来说没有侵入性。能让我们通过操作实体关系模型来操作数据库。大大减轻了sql语句的书写,事务的处理,查询结果的管理等数据库操作。下面是一张hibernate的基本知识点的框架。总体来说hibernate还是比较好学习的,但是需要深入和优化性能还是需要仔细的研究。
【一对多映射】
一对多三种关系:单向一对多,单向多对一,双向一对多。我这里统称为它一对多。一对多关系是非常重要的关系,也是现实世界中最多的关系。这三个关系对应的是UML中的关联关系,也可以分成聚合和组合。之所以把一对多分成三种类型,是因为它们站的角度不同。这里就拿学生和班级的关系举例,站在学生的角度看这个关系是多对一,站在班级的角度看是一对多。但是为了更好的使用这个关系,也考虑到实际操作的原因。一般把它们设置成双向一对多。
单向多对一
单向多对一是站在多的角度去看关系的,在本例中就是站在学生的角度去看。首先看这个关系的UML图。
多个学生对应一个班级。这里的关系就是多对一的关系,站在学生的角度看。如果我们只是需要知道学生位于那个班级。这样就只是单向的关系,也就是拿到Student,hibernate会自动的给你抓取到对应的Classes。单向的多对一是由需求产生的。是人为的设定的。这样的关系中,Studnet一端负责维护关系。它的映射原理是在Studnet表的一段加入外键,指向一的一端。
下面看这两个实体对应的配置文件Student.hbm.xml和Classes.hbm.xml
- <?xmlversionxmlversion="1.0"?>
- <!DOCTYPEhibernate-mapping PUBLIC
- "-//Hibernate/HibernateMapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <classnameclassname="com.lsh.hibernate.Classes" table="t_class">
- <idnameidname="id">
- <generatorclassgeneratorclass="native"/>
- </id>
- <propertynamepropertyname="name"/>
- </class>
- </hibernate-mapping>
关系在多的一端维护,就在多的一端配置。
- <?xmlversionxmlversion="1.0"?>
- <!DOCTYPEhibernate-mapping PUBLIC
- "-//Hibernate/HibernateMapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <classnameclassname="com.lsh.hibernate.Student" table="t_student">
- <idnameidname="id">
- <generatorclassgeneratorclass="native"/>
- </id>
- <propertynamepropertyname="name"/>
- <many-to-onenamemany-to-onename="student" column="classId"cascade="save-update"/>
- </class>
- </hibernate-mapping>
单向一对多
同单向多一对的关系类似,单向一对多关系是同一个实体模型映射的不同关系模型。它是站在班级的角度去看问题的。也就是一的这一端去维护关系。也就是在加载一的时候,Hibernate会自动加载上多的一端数据。他的映射原理和单向一对多是一样的,都是在多的一端加入一个外键,指向一的一端。它的UML图如下,注意箭头的指向不同了。
对应的配置文件Student.hbm.xml和Classes.hbm.xml如下:
- <?xmlversionxmlversion="1.0"?>
- <!DOCTYPEhibernate-mapping PUBLIC
- "-//Hibernate/HibernateMapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <class name="com.lsh.hibernate.Student" table="t_student">
- <idnameidname="id">
- <generatorclassgeneratorclass="native"/>
- </id>
- <propertynamepropertyname="name"/>
- </class>
- </hibernate-mapping>
一的一端维护关系
- <?xmlversionxmlversion="1.0"?>
- <!DOCTYPEhibernate-mapping PUBLIC
- "-//Hibernate/HibernateMapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <class name="com.lsh.hibernate.Classes" table="t_classes">
- <idnameidname="id">
- <generatorclassgeneratorclass="native"/>
- </id>
- <propertynamepropertyname="name"/>
- <setnamesetname="students">
- <!--
- <keycolumn="classesid" not-null="true"/>
- -->
- <key column="classesid"/>
- <one-to-many class="com.lsh.hibernate.Student"/>
- </set>
- </class>
- </hibernate-mapping>
双向一对多
上面的两种关系都是单向的,但是在实际应用中,我们往往需要双向的加载。比如我拿到学生想知道他所在的班级,拿到班级想知道班里面有的学生。这样就需要双向的关系。还有一个很重要的原因就是,单向一对多关系在维护关系的过程中存在很大的缺陷。在插入学生的时候,如果班级不能为空,则学生是插入不了的。还有如果插入成功,在开始解决班级字段是空的,在事务提交阶段,班级需要更新每一个学生的班级ID,这样会产生大量的Update语句。影响效率。所以一对多关系大多使用双向一对多映射。
双向一对多映射的UML图是这样的。
它是一个双向的关联(这里仅限于对Hibernate使用,和现实关系有不一致的地方)
双向一对多的配置文件Student.hbm.xml和Classes.hbm.xml如下:
- <?xmlversionxmlversion="1.0"?>
- <!DOCTYPEhibernate-mapping PUBLIC
- "-//Hibernate/HibernateMapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <classnameclassname="com.lsh.hibernate.Student" table="t_student">
- <idnameidname="id">
- <generatorclassgeneratorclass="native"/>
- </id>
- <propertynamepropertyname="name"/>
- <many-to-onenamemany-to-onename="classes" column="classesid"/>
- </class>
- </hibernate-mapping>
- <?xmlversionxmlversion="1.0"?>
- <!DOCTYPEhibernate-mapping PUBLIC
- "-//Hibernate/HibernateMapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <classnameclassname="com.lsh.hibernate.Classes" table="t_classes">
- <idnameidname="id">
- <generatorclassgeneratorclass="native"/>
- </id>
- <propertynamepropertyname="name"/>
- <setnamesetname="students" inverse="true">
- <key column="classesid"/>
- <one-to-manyclassone-to-manyclass="com.lsh.hibernate.Student"/>
- </set>
- </class>
- </hibernate-mapping>
它的映射原理是
- 在一的一端的集合上采用<key>标签,在多的一端加入一个外键
- 在多的一端采用<many-to-one>标签
也就是两端都要配置,和上面的两种有所不同。但是需要注意的是
- <key>标签和<many-to-one>标签加入的字段保持一直,否则会产生数据混乱
- 在一的一端加上inverse="true"属性,让一的一端不去维护关系,专业就不会发出更新语句。
下面解释一下配置文件中各个标签的意义和用法:
<many-to-one>
通过many-to-one元素,可以定义一种常见的与另一个持久化类的关联。这种关系模型是多对一关联(实际上是一个对象引用-译注):这个表的一个外键引用目标表的主键字段。
<one-to-many>
一对多关联,定义一个表的外键到另一个表的主键,另一个是多的一端。
<inverse>
inverse的值有两种,“true”和“false”。inverse="false"是默认的值,如果设置为true则表示对象的状态变化不会同步到数据库 ;设置成false则相反;
inverse的作用:在hibernate中是通过inverse的设置来决定是有谁来维护表和表之间的关系的。
需要说明的几点:
1:hibernate中的实体类和我们以前做的实体类不太一样,主要是以前的实体类如果包含其它表的字段,直接加上一个String或者int类型的数据就行。而Hibernate中需要加入的是一个实体类属性字段。但是两者生成的表是一样的。就像上面UML图体现的那样,第一个是Studnet实体类中有一个Classes类型的字段,第二个是Classes中有一个Student类型的集合。第三个是他们双方都有对方的一个引用。
2:一对多关系是比较常用的关系,很多时候都会映射出双向的一对多。
3:学习Hibernate要认真体会里面的实体关系,由此去推出映射关系。这里面用到了很多UML的知识。需要重点研究。
【一对一映射】
单向一对一
单向一对一是站在其中的一端看的,主要是根据需求决定的。单向标明一端持有另一端的引用,而另一端则没有引用。如下UML图:
这里面Student持有Card的引用,在加载Student的时候,Hibernate会自动加载上Card来。它们的hbm配置文件如下:
Student.hbm.xml.负责维护关系
- <?xmlversionxmlversion="1.0"?>
- <!DOCTYPEhibernate-mapping PUBLIC
- "-//Hibernate/HibernateMapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <classnameclassname="com.lsh.hibernate.Student" table="t_student">
- <idnameidname="id">
- <!--采用foreign生成策略,forgeign会取得关联对象的标识 -->
- <generatorclassgeneratorclass="foreign">
- <!--property只关联对象 -->
- <paramnameparamname="property">card</param>
- </generator>
- </id>
- <propertynamepropertyname="name"/>
- <!--
- one-to-one指示hibernate如何加载其关联对象,默认根据主键加载
- 也就是拿到关系字段值,根据对端的主键来加载关联对象
- constrained="true表示,当前主键(person的主键)还是一个外键
- 参照了对端的主键(IdCard的主键),也就是会生成外键约束语句
- -->
- <one-to-onenameone-to-onename="idCard" constrained="true"/>
- </class>
- </hibernate-mapping>
Card.hbm.xml不负责维护主键,是一个简单的映射文件。
- <?xmlversionxmlversion="1.0"?>
- <!DOCTYPEhibernate-mapping PUBLIC
- "-//Hibernate/HibernateMapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <classnameclassname="com.lsh.hibernate.Card" table="t_card">
- <idnameidname="id">
- <generatorclassgeneratorclass="native"/>
- </id>
- <propertynamepropertyname="school"/>
- </class>
- </hibernate-mapping>
-
双向一对一
双向一对一是彼此都持有对方的引用,在一端加载的时候,另一端就会自动加载上来。看看双向一对一的UML图
配置文件如下
- Student.hbm.xml
- <?xmlversionxmlversion="1.0"?>
- <!DOCTYPEhibernate-mapping PUBLIC
- "-//Hibernate/HibernateMapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <class name="com.lsh.hibernate.Student" table="t_student">
- <idnameidname="id">
- <!--采用foreign生成策略,forgeign会取得关联对象的标识 -->
- <generatorclassgeneratorclass="foreign">
- <!--property只关联对象 -->
- <param name="property">card</param>
- </generator>
- </id>
- <propertynamepropertyname="name"/>
- <!--
- one-to-one指示hibernate如何加载其关联对象,默认根据主键加载
- 也就是拿到关系字段值,根据对端的主键来加载关联对象
- constrained="true表示,当前主键(person的主键)还是一个外键
- 参照了对端的主键(IdCard的主键),也就是会生成外键约束语句
- -->
- <one-to-one name="card" constrained="true"/>
- </class>
- </hibernate-mapping>
它和上面的单向的Student.hbm.xml配置一样,这两个不同的是在Card.hbm.xml中使用<one-to-one>标签把它持有的student加载上来。
- <?xmlversionxmlversion="1.0"?>
- <!DOCTYPEhibernate-mapping PUBLIC
- "-//Hibernate/HibernateMapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <class name="com.lsh.hibernate.Card" table="t_card">
- <idnameidname="id">
- <generatorclassgeneratorclass="native"/>
- </id>
- <property name="school"/>
- <one-to-one name="student"/>
- </class>
- </hibernate-mapping>
上面的两种一对一都是采用主键关联的方式,即它们两个表的主键是一样的,student用的表是采用foreign的方式,引用Card的主键。一对一关联还有一种外键关联的方式。它的UML图和双向一对一一样,只是配置文件不一样。
首先看一下它们各自的配置文件。Student.hbml.xml和Card.hbm.xml
- <?xmlversionxmlversion="1.0"?>
- <!DOCTYPEhibernate-mapping PUBLIC
- "-//Hibernate/HibernateMapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <classnameclassname="com.lsh.hibernate.Student" table="t_student">
- <idnameidname="id">
- <generatorclassgeneratorclass="native"/>
- </id>
- <propertynamepropertyname="name"/>
- <many-to-onenamemany-to-onename="card" unique="true"/>
- </class>
- </hibernate-mapping>
- <?xmlversionxmlversion="1.0"?>
- <!DOCTYPEhibernate-mapping PUBLIC
- "-//Hibernate/HibernateMapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <classnameclassname="com.bjpowernode.hibernate.Card" table="t_card">
- <idnameidname="id">
- <generatorclassgeneratorclass="native"/>
- </id>
- <propertynamepropertyname="school"/>
- <one-to-onenameone-to-onename="student" property-ref="card"/>
- </class>
- </hibernate-mapping>
一对一外键关联,其实可以看做是一对多的一种特殊形式,多方退化成一。多方退化成一只需要在<many-to-one>标签中设置"unique"="true"。
这里面重要的一个知识点就是<many-to-one>和<one-to-one>的区别,这里主要应用了这个不同。<many-to-one>不仅可以加载到另一端的数据,还会在多的一端表中加入一个外键,而<one-to-one>只会加载另一端数据,不会影响表结构。
【多对多映射】
单向多对多
如果要求拿到用户需要知道它的角色,而不去关心反向的加载。那么这个就是单向的。首先看UML图。
它们的配置文件User.hbm.xml和分别Role.hbm.xml如下:
- <?xmlversionxmlversion="1.0"?>
- <!DOCTYPEhibernate-mapping PUBLIC
- "-//Hibernate/HibernateMapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <classnameclassname="com.lsh.hibernate.User" table="t_user">
- <idnameidname="id">
- <generatorclassgeneratorclass="native"/>
- </id>
- <propertynamepropertyname="name"/>
- <setnamesetname="roles" table="t_user_role">
- <keycolumnkeycolumn="user_id"/>
- <many-to-manyclassmany-to-manyclass="com.lsh.hibernate.Role" column="role_id"/>
- </set>
- </class>
- </hibernate-mapping>
- <?xmlversionxmlversion="1.0"?>
- <!DOCTYPEhibernate-mapping PUBLIC
- "-//Hibernate/HibernateMapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <classnameclassname="com.lsh.hibernate.Role" table="t_role">
- <idnameidname="id">
- <generatorclassgeneratorclass="native"/>
- </id>
- <propertynamepropertyname="name"/>
- </class>
- </hibernate-mapping>
这里面User实体持有一个Role的set集合,使用第三方表把两个表的主键关联起来.
双向多对多
双向多对多就是双方都运用对方的一个引用。在任何一方加载的时候都会自动加载与其关联的另一端数据。首先看一下UML图
双向对多对的配置文件就是有两个单向多对多。其中User的一端和单向的是一样的。下面是Role.hbm.xml
- <?xmlversionxmlversion="1.0"?>
- <!DOCTYPEhibernate-mapping PUBLIC
- "-//Hibernate/HibernateMapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <classnameclassname="com.lsh.hibernate.Role" table="t_role">
- <idnameidname="id">
- <generatorclassgeneratorclass="native"/>
- </id>
- <propertynamepropertyname="name"/>
- <setnamesetname="users" table="t_user_role">
- <keycolumnkeycolumn="role_id" not-null="true"/>
- <many-to-manyclassmany-to-manyclass="com.lsh.hibernate.User" column="user_id"/>
- </set>
- </class>
- </hibernate-mapping>
其实多对多就是两个一对多,它的配置没什么新奇的相对于一对多。在多对多的关系设计中,一般都会使用一个中间表将他们拆分成两个一对多。<set>标签中的"table"属性就是用于指定中间表的。中间表一般包含两个表的主键值,该表用于存储两表之间的关系。由于被拆成了两个一对多,中间表是多方,它是使用外键关联的,<key>是用于指定外键的,用于从中间表取出相应的数据。中间表每一行数据只包含了两个关系表的主键,要获取与自己关联的对象集合,还需要取出由外键所获得的记录中的另一个主键值,由它到对应的表中取出数据,填充到集合中。<many-to-many>中的"column"属性是用于指定按那一列的值获取对应的数据。
- 【Hibernate】Hibernate系列(一)
- Hibernate入门系列(一)
- 深入Hibernate学习系列(一)
- 【Hibernate】Hibernate系列(二)
- Hibernate用户指导系列一
- hibernate系列一:入门篇
- Hibernate (一)hibernate入门
- 【Hibernate】初学Hibernate(一)
- Hibernate(一):Hibernate基本原理
- Hibernate(一):了解Hibernate
- Hibernate(一)---Hibernate简介
- Hibernate系列教程之一(Hibernate结构)
- Hibernate系列-Hibernate原理
- 【Hibernate系列】(一):心底好似旧相识
- 【Hibernate系列】(五):关联映射之多对一
- SSH系列(一):Spring + Hibernate + SpringMVC 整合
- J2EE系列之Hibernate4学习笔记(一)--Hibernate简介
- Hibernate系列
- Python Note
- 前端开发面试题
- 基于AP6212实现 Airkiss NDK编程
- visual stdio2013 + opencv3.0.0配置过程中遇到的问题
- cmd /c和cmd /k
- 【Hibernate】Hibernate系列(一)
- LinkedHashMap学习理解
- 七, seg(属性)
- opencv先选c++学习笔记(一)
- GPS邻近警告
- Android Fragment 真正的完全解析(下)
- HDU-5510 Bazinga(枚举+剪枝)
- 07.Spring Bean 加载 - BeanDefinitionReader
- ES6箭头函数(Arrow Functions)