持久化框架开发Hibernate——从零开始的框架搭建生活
什么是框架?
基于对象关系映射的框架(ORM
hibernate框架
全自动的映射框架,对jdbc的一个封装
MyBatis框架
为什么要学持久化框架开发?
- 使用框架简化开发
体系结构
- 一层体系结构 应用程序层
- 二层体系结构 应用层序曾 数据库层
- 三层体系结构 表述层 业务逻辑层 数据库层
分层体系结构
- 将系统的组件分隔到不同的层中,每一层中的组件保持内聚性,每层都应与其下面各层保持松散耦合。
- 特点:
- 层与层存在自上而下的依赖关系。上层组件访问下层组件的API,下层不依赖上层
- 每个层对上层公开API,实现细节对外透明。当某一层实现改变,API不变则不影响其他层
持久化层的由来
- 由三层体系结构中的业务逻辑层分离出,将数据访问作为单独的持久化层
- 目的:为了把数据访问细节和业务逻辑分开
什么是持久化?
- 瞬时状态
- 保存在内存的程序数据,程序退出、数据消失
- 持久状态
- 保存在数据库(磁盘)的程序数据,程序退出,数据存在
- 持久化
- 将程序数据在瞬时状态和持久状态之间转换的机制(增删改查
持久化层
- 封装了数据访问细节,为业务逻辑层提供面向对象的API,使业务逻辑层可以专注于实现业务逻辑
持久化层的设计目标
- 代码重用性高,可完成对象持久化操作
- 支持多种数据库平台,可移植性
- 具有相对独立性,持久化层变化,不影响上层实现
MVC设计模式和四层结构的对应关系
- 视图———— 表述层
- 控制器________|
- 模型—————业务逻辑层
- |__________持久化层
- |__________数据库层
软件的模型—模型用来表示真实世界的实体
- 分析阶段:概念模型
- 设计阶段:域模型 、 数据模型
概念模型
- 用来模拟问题域中的真实实体
- 描述每个实体的概念和属性,实体之间的关系
- 不描述实体的行为
域模型
- 面向对象的,别称:设计模型
- 组成:具有状态和行为的域对象、域对象之间的关系
- 域对象可代表业务领域中的人、地点、事件或概念
- 域对象分类:
- 实体域对象:业务领域的名词
- 过程域对象:业务领域的动词
- 时间域对象:业务领域的事件
对象关系映射(面向对象和面向关系对应,解决不匹配问题
- 一个持久化类对应一个表
- 类的每个实例对应表的一条记录
- 类的一个属性对应表的一列
域模型和关系模型不匹配
- 域模型有继承关系,关系模型不能直接表示继承关系
- 域模型有多对多关联关系,关系模型通过连接表示
- 域模型有双向关联关系,关系模型只有单项参照关系
- 域模型提倡精粒度模型,关系模型提倡粗粒度模型
对象-关系映射(ORM
- 将域模型表示的对象映射到关系数据模型对应的数据库结构中
- ORM技术在对象和关系之间提供一条桥梁
JDBC缺点
- 软件维护难度增加,业务逻辑和关系数据绑定,关系数据模型变化,则sql必须修改
- 程序调试难度增加。sql语句包含语法错误,在编译时不能检查
- 持久化层产生大量冗余代码
Hibernate 框架
- 在分层体系结构中位于持久化层。是持久化的持久层框架
- 连接Java应用程序和关系型数据库的框架。
- 能够建立对象模型和关系数据模型之间的桥梁
- 自动的ORM框架
- 是JDCB轻量级封装框架。Hibernate是对JDBC API的封装
Hibernate的好处
- 实现了ORM,方便运用面向对象的编程思想来操纵关系型数据库
- 对JDBC封装,增强了代码的重用性,简化代码,提高编程效率
- 对JDBC的轻量级封装,可绕过hibernate直接访问JDBC API
- 可以应用在独立的Java程序、java Web项目、多种Web服务器集成、支持多种数据库平台
Gavin King在2001年创建Hibernate开放源代码的对象关系框架
hibernate项目结构
com.hibernate.entity 持久化类、持久化类的配置文件
com.hibernate.ui 测试类
com.hibernate.util 工具类
hibernate.cfg.xml hibernate配置文件
lib jar包
Hibernate配置文件:从配置文件中读取数据库配置信息,配置文件位于项目根路径
- hibernate.properties (键=值)
- hibernate.cfg.xml
持久化类:实例需要被Hibernate持久化到数据库中的类
- private 类型属性
- public set、get方法
- public/protected 无参数的构造方法
持久化类的配置文件
- <class>用于指定类和表之间的映
- name设定类名
- table设定表名
- 一个id元素、多个property元素
<id>设定持久化类的OID和表的主键的映射关系,name='"id" type="int"
- column 指定表字段的名称
- generator 元素指定OID的生成器(natived/
- <propernate>子元素设定类的其他属性和婊的字段的映射关系
- name 类的属性名称
- type 属性的类型
- column 表字段的名称
- not-null 是否允许为空
Hibernate API操纵数据库
- ServiceRegistry 注册服务的创建 //读取hibernate.cfg.xml配置信息
- SessionFactory 会话工厂
- 缓存Hibernate配置信息和映射元数据信息
- 创建Session实例
- SessionFactory线程安全,多个应用线程进行共享
- 一个应用只有唯一一个SessionFactory实例
- Session
- Session是Hibernate持久操作的基础核心⭐
- 代表和数据库之间的一次连续操作
- Session负责执行访问数据库的操作,保存、更新、删除、加载、查询。
- 被称为持久化管理器
- 创建:Session session = sessionFactory.openSession();
- session是一个轻量级对象,非线程安全,与数据库事务绑定
- Transaction
- 数据库事务
- Transaction ts = session.beginTransaction();//开始一次事务
- ts.commit();//提交事务
持久化类属性、访问方法
- 持久化类采用javaBean风格,为被访问的属性创建set/get方法。持久化类的访问方法
- set/get方法优点:有效控制属性的访问权限
Hibernate访问持久化类属性的策略(两种
- 在对象-关系映射文件中的<property>元素的access属性
- property : 默认值,通过getter和setter方法访问属性值;
- field : 通过Java反射机制直接访问属性值。(不适用set/get方法
Hibernate实体映射技巧
- 姓与名,split(" ")[0]
- <property> 的 formula 设置查询语句。实体类有属性、数据库不存在相应字段
控制持久化类的insert、update
- <property>属性的insert、update=“true”,插入更新一样更新。默认true
- <class> 的dynamic-insert、dynamic-update 等价于所有的<property>dynamic-insert、dynamimc-update属性。
-
-
会过滤过值为null的属性,只对有值的字段生成语句
- 只对修改的值生成更新语句
-
- <class> 的mutable 等价于所有的<property>update属性
对象标识符映射(OID):Hiberate采用对象标识符区分对象
- OID是关系数据库中主键在java对象模型中的等价物
- 采用OID维持java对象与数据库中对应关系
- OID也是整数类型
- Short
- Integer
- Long
- 为了保证OID唯一性,由Hiberate或底层数据库给OID赋值
- <id>的<generater>class属性
- increment Hiberate自带自增
- 不依赖底层数据库系统,适用所有数据库
- 适合单独的Hiberate,不适合集群(多个插入同一个主键
- identity数据库自增⭐(除此之外,其他都要和事务绑定
- 依赖底层数据库,需要数据库支持自动增长字段
- assigned自己控制
单实体映射注解
- @Entity 声明实体类
- @Table(name="tablename") 指定数据库表
- @Id 声明实体类的OID属性
- @GeneratedValue(generator=“increment_generator”) OID生成策略
- @GenericGenerator(name="increment_generator",strategy="increment") Hiberate提供生成策略
- @Column(name="name") 属性映射列 unique、nullable、insertable、updateable、length
- <mapping class="com.hibernate.entity.User"/>在配置文件中
Hibernate继承关系映射
- 每个具体类对应一个表
-
- 关系数据模型不支持域模型中的继承和多态
- 每个子类所对应的表中同时存在从父类继承的属性和自己的属性
- 父类不是抽象类并且需要被持久化 ,还需为父类建表
- 使用注解 父类@MappedSuperclass
- 父类对应一个表
-
- <discriminator column=" "/> 必须在<id/>下面
- <subclass name="类名" discriminator-value="X"><property name=“属性名”/></subclass>
- 如果父类要被持久化,在<class discriminator-value=“EE”>
- 使用注解 父类 @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
- @DiscriminatorColumn(name="EMPLOYEETYPE区分属性名")
- 子类:@DiscriminatorValue(value="区分")
- 支持多态查询
- 每个类对应一个表
-
- 用外键参照关系来表示继承关系,子类对应表存在外键参照父类对应表的主键
- 继承关系每个类和接口都对应一个表
- 支持多态查询
- <joined-subclass name="类名" table="表名">
- <key column="外键名"/>
- <property name=""/>
- </joined-subclass>
- 使用注解 父类 @Inheritance(strategy=InheritanceType.JOINED)
- 子类 @PrimaryKeyJoinColumn(name="EMPLOYEEID")
三种映射方式对比
- 关系模型复杂度
- 包含重复字段
- 引入额外区分类型(优点:只有一个表
- 表多,存在外键参照关系
- 查询性能
- 查询父类对象,需要遍历全部具体子类对应的表
- 很好的查询性能、【优点】
- 需要进行表的连接查询
- 数据库可维护性
- 父类变化,子类必须修改【缺】
- 只修改一张
- 某个类属性变化,只需修改该类对应的表
- 多态查询
- 不支持
- 支持
- 支持
Hibernate一对一关联映射
实体间联系
- 一对一联系
- 一对多联系
- 多对多联系
一对一关联关系映射:
- 主键关联映射
- 主键表配置 <one-to-one cascade="all" name="参照表名" class=“被参照类名”> 级联属性
- 外键表配置 <one-to-one name="被参照类类名" constrained="true"/>
- constrained=true,该id为外键,
- <generator class="foreign"> <param name="property">主表</param></generator>
- 使用注解配置
- 在被参照表的getXX()配置
- @OneToOne(cascade=CascadeType.ALL) 指定一对一关联关系,设置级联
- @PrimaryKeyJoinColumn(name="ID") 指定参照表主键列名
- 在参照表上getId()上配置
-
@GeneratedValue(generator="foreign")
@GenericGenerator(name="foreign",strategy="foreign"
,parameters={@Parameter(name="property",value="被参照表名")}) - 在getXX()上配置 @OneToOne(mappedBy="参照表")
- 在哪配置都在哪配置,防止两种混合,在方法上默认getset、在属性上是反射机制
- 唯一外键关联映射【外键必须unique约束
- 外键表User
- <many-to-one column="外键列" unique="true" cascade="all">
- unique唯一约束
- cascade 级联删除
- 主键表Person
- <one-to-one name="user" property-ref="person"/>建立从user到person的一对一关联映射
- 使用注解
- 在User类的person属性
-
@OneToOne(cascade=CascadeType.ALL) @JoinColumn(name="PERSONID"):指明USER表中的外键列名。
- 在Person的user属性上
-
@OneToOne(mappedBy="person")
组合关系映射
- 在配置文件中,
- <component name="" class="">
- <property name="" column=""/>
- <property name="" column=""/>
- <property name="" column=""/>
- </component>
- <component name="" class="">
- 使用注解
- 在部分类@Embeddable,不需要单独进行映射 ,指明嵌入式类
- 在整体类
- @Embedded
- @AttributeOverrides(
- value={
- @AttributeOverride( name = "province", column = @Column(name=“HOMEPROVINCE")),
- @AttributeOverride( name = "city", column = @Column(name=“HOMECITY")), ......
- })
- value={
Hibernate一对多关联映射
数据库一对多关联:只存在外键参照关系,many参照one
Hibernate单向一对多关联
- 在one类配置文件中
-
- SET(不可重复数据
- <set name="" cascade="">
- <key column=""/> //关联类对应表的外键
- <one-to-many class=""/> //class属性设定关联类
- </set>
- name="映射的属性名"
- cascade=“级联操作”
- save-update
- delete
- all
- none
-
- LIST(可重复、有序)
-
<list name="orders" cascade="all">
<key column="user_id"></key>
<index column="order_index"></index>
<one-to-many class="Order"/>
</list> - 在many表中ORDERINDEX表示插入顺序
- <index column="表记录插入顺序的列名">
- Map(
- 在many表中ORDERKEY记录Map的key值
-
<map name="orders" cascade="all">
<key column="user_id"></key>
<index column="order_key" type="string"></index>
<one-to-many class="Order"/>
</map> - <index column="key值字段名" type="key值类型">、
Hibernate双向一对多关联
- 在many类配置文件中
-
- <many-to-one name="user" column="user_id" class="关联类"></many-to-one>
Hibernate注解配置一对多关联
- 在many类getone()上
- @ManyToOne
- @JoinColumn(name="对应表外键列名")
- 在one类中
- Set集合在getManySet()方法上
-
@OneToMany(
-
mappedBy="user",
-
targetEntity=Order.class,
-
cascade=CascadeType.ALL)
- List集合在getManySet()方法上
-
@OneToMany(
-
mappedBy="user", //表名双向关联关系
-
targetEntity=Order.class, //关联类型
-
cascade=CascadeType.ALL) //级联操作
-
@OrderColumn(name="ORDERINDEX") //many对应表中记录顺序的列名
- Map集合在getManySet()方法上
-
@OneToMany(
-
mappedBy="user",
-
targetEntity=Order.class,
-
cascade=CascadeType.ALL)
-
@MapKeyColumn(name="orderKey") //many表中记录MapKey值得列名
-
@MapkeyClass(String.class) //Key值类型
Hibernate多对多关联关系映射
- 在多对多的某个类中
- <set name="属性" table="中间表">
- <key column="在中间表中对应的列"/>
- <many-to-many class="关联的类" column="关联类在中间表所对应的列"/>
- </set>
- <set name="属性" table="中间表">
- 在<set>的inverse属性,双向关联关系中设置由谁来维护
- true,被控方
- false 主控方
- cascade = “true” 级联删除添加
多对多关联注解表示
控制方
@ManyToMany
@JoinTable(name="中间表"
joinColumns=@joinColumn(name="对应中间表的列")
inverseJoinColumns=@JoinColumn(name="对应中间表的列"))
被控方
@ManyToMany(mappedBy="在控制方的属性名")
Session缓存
- 空引用
- 隔离引用
- 缓存:介于应用程序和永久性存储源之间
- 降低应用程序直接读写永久性存储源的频率,提高应用的运行效率
Session缓存:
- session 接口的实现类 SessionImpl 中定义了一系列的 Java 集合,这些集合构成了 Session 的缓存
- 工作过程
- 当 Session 执行查询方法时,先从 Session 缓存中读取据,如果缓存中有则直接读取,如果缓存中没有,从数据库中查询并加载到 Session 缓存中,再从缓存中读取。
- 当 Session 执行 save()、update() 方法时,将对象持久化到数据库中并将对象加载到 Session 缓存中。
- closed=false,session开启时,创建对象会缓存在session中
- closed=true,session关闭时,不会缓存
- Session清理缓存:在某一时间点按照缓存对象属性变化同步更新数据库
- 1.transaction.commit();事务提交
- 2.Session.flush();
- 3.Session的查询(不含load、get(),属性有变化触发
session对象快照:将对象与快照比较,不一致触发清理缓存操作
- session缓存清理模式:session.setHibernateFlushMode()
- FlushMode.ALWAYS 1、2、3都清理
- FlushMode.AUTO 1、2都清理 3变换才清理
- FlushMode.COMMIT 1、2都清理 3不清理
- FlushMode.MANUAL 2请理 1、3不清理
- FlushMode.NEVER
- session缓存的作用
- 减少数据库访问次数、提高数据库访问效率
- 保证缓存与数据库同步
- 当缓存中持久化对象存在循环关联关系时,session会保证不出现死循环

浙公网安备 33010602011771号