持久化框架开发Hibernate——从零开始的框架搭建生活

什么是框架?

 

基于对象关系映射的框架(ORM

  hibernate框架  

    全自动的映射框架,对jdbc的一个封装

  MyBatis框架

 

为什么要学持久化框架开发?

  •   使用框架简化开发

体系结构

  • 一层体系结构    应用程序层
  • 二层体系结构    应用层序曾         数据库层
  • 三层体系结构    表述层 业务逻辑层   数据库层

 

分层体系结构

  •   将系统的组件分隔到不同的层中,每一层中的组件保持内聚性,每层都应与其下面各层保持松散耦合。
  • 特点:
    • 层与层存在自上而下的依赖关系。上层组件访问下层组件的API,下层不依赖上层
    • 每个层对上层公开API,实现细节对外透明。当某一层实现改变,API不变则不影响其他层

持久化层的由来

  • 由三层体系结构中的业务逻辑层分离出,将数据访问作为单独的持久化层
  • 目的:为了把数据访问细节和业务逻辑分开

 

什么是持久化?

  1. 瞬时状态
    • 保存在内存的程序数据,程序退出、数据消失
  2. 持久状态
    • 保存在数据库(磁盘)的程序数据,程序退出,数据存在
  3. 持久化
    • 将程序数据在瞬时状态和持久状态之间转换的机制(增删改查  

持久化层

  • 封装了数据访问细节,为业务逻辑层提供面向对象的API,使业务逻辑层可以专注于实现业务逻辑

持久化层的设计目标

  1. 代码重用性高,可完成对象持久化操作
  2. 支持多种数据库平台,可移植性
  3. 具有相对独立性,持久化层变化,不影响上层实现

 

MVC设计模式和四层结构的对应关系

  • 视图————  表述层 
  • 控制器________|

 

  • 模型—————业务逻辑层
  •  |__________持久化层
  •  |__________数据库层

 

软件的模型—模型用来表示真实世界的实体

  • 分析阶段:概念模型
  • 设计阶段:域模型    、 数据模型

概念模型

  • 用来模拟问题域中的真实实体
  • 描述每个实体的概念和属性,实体之间的关系
  • 不描述实体的行为

域模型

  • 面向对象的,别称:设计模型
  • 组成:具有状态和行为的域对象、域对象之间的关系
  • 域对象可代表业务领域中的人、地点、事件或概念
  • 域对象分类:
    • 实体域对象:业务领域的名词
    • 过程域对象:业务领域的动词
    • 时间域对象:业务领域的事件

 

 对象关系映射(面向对象和面向关系对应,解决不匹配问题

  • 一个持久化类对应一个表
  • 类的每个实例对应表的一条记录
  • 类的一个属性对应表的一列

域模型和关系模型不匹配

  1. 域模型有继承关系,关系模型不能直接表示继承关系
  2. 域模型有多对多关联关系,关系模型通过连接表示
  3. 域模型有双向关联关系,关系模型只有单项参照关系
  4. 域模型提倡精粒度模型,关系模型提倡粗粒度模型

对象-关系映射(ORM

  • 将域模型表示的对象映射到关系数据模型对应的数据库结构中
  • ORM技术在对象和关系之间提供一条桥梁

 JDBC缺点

  1. 软件维护难度增加,业务逻辑和关系数据绑定,关系数据模型变化,则sql必须修改
  2. 程序调试难度增加。sql语句包含语法错误,在编译时不能检查
  3. 持久化层产生大量冗余代码

Hibernate 框架

  • 在分层体系结构中位于持久化层。是持久化的持久层框架
  • 连接Java应用程序和关系型数据库的框架。
    • 能够建立对象模型和关系数据模型之间的桥梁
    • 自动的ORM框架
  • 是JDCB轻量级封装框架。Hibernate是对JDBC  API的封装

Hibernate的好处

  1. 实现了ORM,方便运用面向对象的编程思想来操纵关系型数据库
  2. 对JDBC封装,增强了代码的重用性,简化代码,提高编程效率
  3. 对JDBC的轻量级封装,可绕过hibernate直接访问JDBC API
  4. 可以应用在独立的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持久化到数据库中的类

  1. private  类型属性
  2. public    set、get方法
  3. 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操纵数据库

  1. ServiceRegistry  注册服务的创建    //读取hibernate.cfg.xml配置信息
  2. SessionFactory   会话工厂
    1. 缓存Hibernate配置信息和映射元数据信息
    2. 创建Session实例
    3. SessionFactory线程安全,多个应用线程进行共享
    4. 一个应用只有唯一一个SessionFactory实例  
  3. Session
    1. Session是Hibernate持久操作的基础核心⭐
    2. 代表和数据库之间的一次连续操作
    3. Session负责执行访问数据库的操作,保存、更新、删除、加载、查询。
    4. 被称为持久化管理器
    5. 创建:Session session = sessionFactory.openSession();
    6. session是一个轻量级对象,非线程安全,与数据库事务绑定  
  4. Transaction
    1. 数据库事务
    2. Transaction ts = session.beginTransaction();//开始一次事务
    3. ts.commit();//提交事务  

 持久化类属性、访问方法

  • 持久化类采用javaBean风格,为被访问的属性创建set/get方法。持久化类的访问方法
  • set/get方法优点:有效控制属性的访问权限

Hibernate访问持久化类属性的策略(两种

  • 在对象-关系映射文件中的<property>元素的access属性
  1. property : 默认值,通过getter和setter方法访问属性值;
  2. field : 通过Java反射机制直接访问属性值。(不适用set/get方法

Hibernate实体映射技巧

  1. 姓与名,split(" ")[0] 
  2. <property> 的 formula 设置查询语句。实体类有属性、数据库不存在相应字段

控制持久化类的insert、update

 

  1. <property>属性的insert、update=“true”,插入更新一样更新。默认true
  2. <class> 的dynamic-insert、dynamic-update 等价于所有的<property>dynamic-insert、dynamimc-update属性。
    • 会过滤过值为null的属性,只对有值的字段生成语句

    • 只对修改的值生成更新语句
  1. <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继承关系映射

 

  1. 每个具体类对应一个表
    • 关系数据模型不支持域模型中的继承和多态
    • 每个子类所对应的表中同时存在从父类继承的属性和自己的属性
    • 父类不是抽象类并且需要被持久化 ,还需为父类建表
    • 使用注解  父类@MappedSuperclass 
  1. 父类对应一个表
    • <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="区分")
    • 支持多态查询
  1. 每个类对应一个表
    • 用外键参照关系来表示继承关系,子类对应表存在外键参照父类对应表的主键
    • 继承关系每个类和接口都对应一个表
    • 支持多态查询
    • <joined-subclass name="类名" table="表名">
    • <key column="外键名"/>
    • <property name=""/>
    • </joined-subclass>
    • 使用注解  父类 @Inheritance(strategy=InheritanceType.JOINED)
    • 子类  @PrimaryKeyJoinColumn(name="EMPLOYEEID")

三种映射方式对比

  1. 关系模型复杂度
    • 包含重复字段
    • 引入额外区分类型(优点:只有一个表
    • 表多,存在外键参照关系
  2. 查询性能
    • 查询父类对象,需要遍历全部具体子类对应的表
    • 很好的查询性能、【优点】
    • 需要进行表的连接查询
  3. 数据库可维护性
    • 父类变化,子类必须修改【缺】
    • 只修改一张
    • 某个类属性变化,只需修改该类对应的表  
  4. 多态查询
    • 不支持
    • 支持
    • 支持 

Hibernate一对一关联映射

实体间联系

  1. 一对一联系
  2. 一对多联系
  3. 多对多联系

一对一关联关系映射:

 

  1. 主键关联映射
    • 主键表配置 <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、在属性上是反射机制
  2. 唯一外键关联映射【外键必须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>
  • 使用注解
    • 在部分类@Embeddable,不需要单独进行映射 ,指明嵌入式类
    • 在整体类
      • @Embedded
      • @AttributeOverrides(
        • value={
          • @AttributeOverride( name = "province", column = @Column(name=“HOMEPROVINCE")),
          • @AttributeOverride( name = "city", column = @Column(name=“HOMECITY")), ......
        • })

 Hibernate一对多关联映射

 

数据库一对多关联:只存在外键参照关系,many参照one

Hibernate单向一对多关联

  1. 在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双向一对多关联

  1. 在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>的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会保证不出现死循环
posted @ 2020-06-05 22:39  不爱学习的小策  阅读(230)  评论(0)    收藏  举报