Hibernate_Day02

一、Hibernate的持久化类的编写规则

1、持久化类的概述

  • 持久化: Hibernate是持久层的ORM映射框架,专注于数据的持久化工作。所谓的持久化,就是将内存中的数据永久存储到关系型数据库中。那么知道了什么是持久化,
  • 持久化类: 指的是一个Java 类与数据库表建立了映射关系,那么这个类称为是持久化类。其实你可以简单的理解为持久化类就是一个Java类有了一个映射文件与数据库的表建立了关系。但是那么我们在编写持久化类的时候有一些要求。
    • 持久化类=Java类+映射文件

2、持久化类的编写规则

  • 对持久化类提供一个无参的构造方法: hibernate的地秤需要使用反射生成实例
  • 属性是私有的,对私有属性提供public的set()/get()方法:hibernate需要获取、设置对象属性值
  • 持久化类的属性要尽量使用包装类如(Integer、Long、Double)的类型。因为包装类和基本数据类型的默认值不同,包装类的类型语义描述更清晰而基本数据类型不容易描述。比如0,对于一个客户开始存款是0,之后存了钱花完了变为0,那么0在此有多重含义,包装类类型默认是null
  • 持久化类要有唯一标识OID与表的主键对应:Java中通过地址判断是否是同一个对象;数据库中通过主键判断是否是同一条记录;因为Hibernate中需要通过这个唯一标OID区分在内存中是否是同一个持久化对象那个,hibernate是不允许在内存中出现两个OID相同的持久化对象的。
  • 持久化类尽量不要使用final修饰:因为Hibernate中有延迟加载的机制,这个机制中会产生代理对象,Hibernate 产生代理对象使用的是字节码的增强技术完成的,其实就是产生了当前类的一个子类对象实现的(javassist可以对没有实现接口的类产生代理–使用了非常底层的字节码增强技术,继承这个类进行代理)。如果使用了final 修饰持久化类。那么就不能产生子类,从而就不会产生代理对象,那么Hibernate的延迟加载策略(是一种优化手段)就会失效’。

至此持久化类我们已经可以正常编写了,但是在持久化类中需要有一个唯一一标识OID与表的主键去建立映射关系。而且主键-一般我们是不会让客户手动录入的,- -般我们是由程序生成主键。那么Hibernate中也提供了相应的主键生成的方式,那么我们来看下Hibernate的主键生成策略。

3、 Hibernate的主键(不可以修改的)

  • 自然主键: 主键的本身就是表中字段的一个字段(实体中的一个属性),且在表中每个记录是唯一的,比如学号,身份证号
  • 代理主键: 主键的本身不是表中必须的一个字段(不是实体中某个具体的属性),比如在学生表没有使用学号,使用了不相关的一个字段ID
    在实际开发中,要尽量使用代理主键
    • 因为一旦自然逐渐参与到实际开发/业务逻辑中中,后期有可能需要修改源代码
    • 好的程序设计满足OCP(Open Closed Principle,开闭原则)原则,对程序的扩展时open的,对修改源码时close的,

4、主键生成策略

在实际开发中,一般不允许用户手动设置主键,一般将之间交给数据库,手动编写程序进行设置。在hibernate的、中为了减少程序编写,提供了很多了很多种的主键生成策略。

  • increment: hibernate中提供的自动增长机制,适用于short、int、long类型的主键,在单线程程序中使用,适用于代理
  • identity: 适应于short、int、long类型的主键,使用的是数据库底层的自动增长机制,适用于有自动增长机制的数据库(Mysql、DB2、MS SQL Server、Sybas和HypersonicSQL,但是Oracle是没有自动增长的),适用于代理
  • sequence: 适应于short、int、long类型的主键,采用的是序列方式(Oracle采用的是序列方式),像MySql不可以使用,适用于代理
  • uuid: 采用128位的UUID算法来生成标识符,适用于字符串类型主键。像hibernate中的随即方式生成字符串主键,适用于代理
  • native: 本地策略,可以在identity和sequence之间进行自动切换,适用于代理
  • assigned: hibernate放弃外键的管理,需要自己通过手动编写程序或者用户自己进行设置,适用于自然主键
  • foreign: 外部的,一对一的一种关系映射的情况下的使用

如下演示主键生成策略

  • increment(采用的是hibernate的自动递增)
    • 先用create(如果数据库中已经有表,删除原有表,重新创建,如果没有表,新建表。(测试))将表改为不是数据库的自动递增
      在这里插入图片描述
    • 之后再改为update(如果数据库中有表,使用原有表,如果没有表,创建新表(更新表结构))
      在Debug的过程中使用多线程会出现错误,因此increment只可以使用单线程。
  • identity
    在这里插入图片描述

5、持久化类的三种状态

		Hibermate为了更好的来管理,持久化类,特将持久化类分成了三种状态。
  • 瞬时态: 这种对象没有唯一标识OID,没有被session管理,称为是持久态对象。
  • 持久态: 这种对象有唯一的标识0ID.被session管理。称为是瞬时态对象。
    • 持久化类的持久化对象,可以自动更新数据库
  • 脱管态: 这种对象有唯一标识OID,没有被session管理,称为脱管态对象。
区分三种状态对象

在这里插入图片描述

持久化类的状态转换(了解)

在这里插入图片描述
瞬时态对象

  • 获取
    • 通过new创建:Customer customer = new Customer()
  • 状态转换
    • 瞬时–>持久:save()、saveOrUpdate()
    • 瞬时–>托管: customer.setCust_name(“文文”)

持久态对象

  • 获得
    • get()、load()、find()、iterate()
    • Customer customer =session.get(Customer.class,1L)
  • 状态转换
    • 持久–>瞬时:delete()
    • 持久–>托管:close()、clear()、evict()

托管态对象

  • 获得
    • Customer customer = new Customer(),customer.setCust_name(“文文”);
  • 状态转换
    • 托管–>瞬时: customer.setCust_name(null)
    • 托管–>持久:update()、saveOrUpdate()

持久态对象的特性

自动更新数据库(依赖的是hibernate的一级缓存)

在这里插入图片描述

6、hibernate的一级缓存

缓存: 是一种优化的方式,将数据存入到内存中,使用的时候直接从内存中获取,不需要通过存储源。

Hibernate框架中提供了优化手段:缓存、抓取策略。Hibernate 中提供了二种缓存机制:-级缓存、 二级缓存。Hibemate的一-级缓存:称为是Session级别的缓存,一级缓存生命周期与Session一致(-一级缓存是由Session中的一系列的Java集合构成)。一级缓存是自带的不可卸载的。(Hibernate 的二级缓存是SessionFactory级别的缓存,需要配置的缓存)。

Hibernate的一级缓存就是指Session缓存,Session 缓存是一块内存空间,用来存放相互管理的java对象,在使用Hibernate查询对象的时候,首先会使用对象属性的OID值在Hibernate的一级缓存中进行查找,如果找到匹配OID值的对象,就直接将该对象从一级缓存中取出使用,不会再查询数据库;如果没有找到相同OID值的对象,则会去数据库中查找相应数据。当从数据库中查询到所需数据时,该数据信息也会放置到一级缓存中。Hibernate一级缓存的作用就是减少对数据库的访问次数。
在Session接口的实现中包含一系列的Java集合,这些Java 集合构成了Session 缓存。只要Session实例没有结束生命周期,存放在它缓存中的对象也不会结束生命周期。故一级缓存也被称为是Session基本的缓存。

Hibernate的一-级缓存有如下特点:

  • 当应用程序调用Session接口的save()、update()、saveOrUpdate() 时,如果Session缓存中没有相应的对象,Hibernate 就会自动的把从数据库中查询到的相应对象信息加入到一级缓存中去。
  • 当调用Session接口的load()、get()方法,以及Query接口的list()、iterator()方法时,会判断缓存中是否存在该对象,有则返回,不会查询数据库,如果缓存中没有要查询对象,再去数据库中查询对应对象,并添加到一级缓存中。
  • 当调用Session的close()方法时,Session 缓存会被清空。

证明一级缓存的存在在这里插入图片描述

在这里插入图片描述

hibernate一级缓存的结构

hibernate的特殊区域:快照区

Hibernate向一级缓存放入数据时,同时复制一份数据放入到Hibernate快照中,当使用commit()方法提交事务时,同时会清理Session的一级缓存,这时会使用OID判断–级缓存中的对象和快照中的对象是否一致,如果两个对象中的属性发生变化,则执行update语句,将缓存的内容同步到数据库,并更新快照;如果一致, 则不执行update语句。Hibernate 快照的作用就是确保一级缓存中的数据和数据库中的数据一致。

  • 一级缓存的快照区主要有一下区域构成
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
当事务提交的时候,比较缓存区和快照区,若不一样,更新数据库。

7、hibernate的事务管理

什么是事务

事务:逻辑上的一组操作,做成事务操作的各个逻辑单元要么全部成功,要么全部失败

事务的特性

  • 原子性: 代表事务不可分割
  • 一致性: 代表事务执行的前后,数据的完整性保持一致
  • 持久性: 代表事务执行完成后,数据永久保存在数据库中
  • 隔离性: 代表一个事务执行的过程中,不应该受到其它事务的干扰

若不考虑隔离性,将会引发安全性问题

  • 读问题:
    • 脏读:一个事务读到另一个事务未提交的数据
    • 不可重复读:一个事务读到另一个事务已经提交的update数据,导致在前一个事务多次查询结果不一致
    • 幻读(幻读): 一个事务读到另一个事务已经提交的insert数据,导致在前一个事务多次查询结果不一致

读问题的解决

  • 设置事务的隔离级别
    • 读未提交(Read Uncommitted,1级): 以上读问题都会发生
    • 已提交读(Read Committed,2级):解决脏读,但是不可重复读和虚读有可能发生(一般Oracle使用)
    • 可重复读(Repeatable Read,4级):解决脏读和不可重复读,但是虚读有可能发生(一般MySsql使用)
    • 序列化/串行化(Serializable,8级):解决所有读问题(但是效率低)

一般采用中间两种

hibernate中设置事务隔离级别

在核心配置文件hibernate.cfg.xml中进行通过hibernate.connection.isolation设置
在这里插入图片描述

Service层事务

hibernate解决Service的事务管理
  • 在事务操作中必须保证连接对象是同一个
    • 向下传递DBUtiis
    • 使用ThreadLocal对象
      • 将这个连接绑定到当前线程中
      • DAO的方法中,通过当前的线程获得到连接对象
  • Hibernate框架内部已经绑定好了ThreadLocal
    • 在SessionFactory中提供了一个方法getCurrentSession() ;
    • 通过一个配置完成
      • hibernate.current_session_context_class
        • thread: Session 对象的生命周期与本地线程绑定
        • jta: Session 对象的生命周期与JTA事务(跨数据库的事务)绑定
        • managed: Hibernate 委托程序来管理Session 对象的生命周期

改写工具类HibernateUtils

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtils {
    private static final Configuration configuration;
    private static final SessionFactory sessionFactory;

    static {
        configuration = new Configuration().configure();
        sessionFactory = configuration.buildSessionFactory();
    }

    public static Session openSession() {
        return sessionFactory.openSession();
    }

    public static Session getCurrentSession() {
        return sessionFactory.getCurrentSession();//需要配置,因为默认没有开启
    }

}

配置hibernate事务

在这里插入图片描述
getcurrentSession()不需要使用close()方法关闭,因为线程结束自动释放
测试代码
在这里插入图片描述
在这里插入图片描述

8、hibernate的其它API

  • Query

    Query代表面向对象的一-个Hibermate查询操作。在Hibernate中,通常使用session.createQueryO方法接受一个HQL语句,然后调用Query的list)或uniqucRcsultQ方法执行查询。所谓的HQL是
    Hibernate Query Language缩写,其语法很像SQL语法,但它是完全面向对象的。
    在Hibernate中使用Query对象的步骤,具体所示:
    (1)获得Hibernate的Session对象。
    (2)编写HQL语句。
    (3)谓用session.createQuery创建查询对象。
    (4)如果HQL语句包含参数,则调用Query的setXxx或者setParameter设置参数。
    (5)谓用Query对象的list()或uniqueResult()方法执行查询。

    • 获取表中所有内容

      在这里插入图片描述

    • 根据指定条件查询某个人的信息,比如姓刘的

      在这里插入图片描述

    • 分页查询

      在这里插入图片描述

  • Criteria

    Criteria是-一个完全面向对象,可扩展的条件查询API,通过它完全不需要考虑数据库底层如何
    实现,以及SQL语句如何编写,它是Hibernate框架的核心查询对象。Criteria 查询,又 称为QBC
    查询(Query By Criteria),它是Hibernate的另-一种对象检索方式。
    org. hibernate criterion. Criterion是Hibernate提供的一个面向对象查询条件接口,一个单独的查询
    就是Criterion接口的-一个实例,用于限制Criteria对象的查询,在Hibernate中Criterion对象的创建
    通常是通过Restrictions工厂类完成的,它提供了条件查询方法。
    通常,使用Criteria对象查询数据的主要步骤,具体如下:
    (1)获得Hibernate的Session对象。
    (2)通过Session获得Criteria对象。.
    (3)使用Restrictions的静态方法创建Criterion 条件对象。Restrictions 类中提供了- -系列用于
    设定查询条件的静态方法,这些静态方法都返回Criterion实例,每个Criterion实例代表一
    个查询条件。
    (4)向Criteria对象中添加Criterion查询条件。Criteria 的add0方法用于加入查询条件。
    (5)执行Criterita的list() 或uniqueResult)获得结果。

    • 获取表中所有内容
      在这里插入图片描述
    • 根据指定条件查询某个人的信息
      在这里插入图片描述
    • 分页查询
      在这里插入图片描述
  • SQLQuery

    SQLQuery这个就比较简单了,这个接口用于接收-一个sql语句进行查询,然后调用list()或者uniqueResult()方法进行查询。但是sql语句不会直接封装到实体对象中,需要我们手动写代码才可
    以封装到实体中。

    • 获取表中所有内容
      在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值