SSH框架之Hibernate进阶持久化对象及事务管理(二)

第一节: 持久化类的编写规则

1.1 什么是持久化类

  • 持久化:将内存中的一个对象持久化到数据库中的过程,Hibernate是持久层的ORM映射框架。
  • 持久化类:一个java对象与数据库表建立了映射关系,则该类被称为持久化类。

1.2 持久化类的编写规则

  • ①对持久化类提供一个无参数的构造方法 :Hibernate底层需要使用反射生成实例;
  • ②属性需要私有,对私有属性提供public的get和set方法:Hibernate中获取对象值;
  • ③对持久化类提供一个唯一标识OID与数据库主键对应:Hibernate中通过持久化类的OID的属性来区分是否是同一个对象。
  • ④持久化类中的属性尽量使用包装类型类来定义:基本数据类型的默认值为0,易引起歧义。
  • ⑤持久化类不要使用final进行修饰:延迟加载本身是Hibernate一个优化的手段,返回的是一个代理对象(对没有实现接口的类产生代理,javassist使用了非常底层的字节码增强技术,集成这个类进行代理)如果该类不能被继承,则不能产生代理对象,则延迟加载也就失效了。

1.3 Hibernate中主键生成策略

  • 1.3.1 主键的分类
    自然主键:主键的本身就是表中的一个字段(实体中的一个具体属性);
    代理主键:主键的本身不是表中必须的一个字段(不是实体中的某个具体的属性)。
    在实际的开发中,尽量使用代理主键,满足OCP原则(对程序的扩展是open的,对源代码的修改是close)

  • 1.3.2 主键的生成策略
    在实际开发中一般不允许用户手动设置主键,一般将主键交给数据库。在Hibernate中提供了多种主键的生成策略。如下:


            
            
            
        

第二节:持久化类的三种状态

Hibernate是持久层框架,通过持久化类完成ORM操作。Hibernate为了更好的管理之间化类,将持久化类分成三种状态。

  • 瞬时态(transient)
    瞬时态也称为临时态或者自由态,瞬时态的实例是由new命令创建,开辟内存空间的对象,不存在持久化标识OID(相对于主键值),尚未与Hibernate session关联,在数据库中也没有记录,失去引用后将被JVM回收。瞬时状态的对象在内存中是gu孤立存在的,与数据库中的数据无任何关联,仅是一个信息携带的载体。
  • 持久态(presistent)
    持久态的对象拥有持久化标识OID,加入到了Session缓存中,并且相关联的Session没有关闭,在数据库中有对应的记录,每条记录只对应唯一的持久化对象,需要注意的是,持久态对象是在事务还未提交前变成持久态的。(持久态的对象可以自动更新数据库)
  • 脱管态(detached)
    脱管态也称离线态或者游离态,当某个持久化状态的实例与session的关联被关闭时就变成了脱管态。脱管态对象存在持久化标识OID,并且仍然与数据库中的数据存在关联,只是失去了与当前Session的关联,脱管状态对象发生改变时Hibernate不能检测到。

2.1 如何区分这三种状态?

瞬时态对象,没有唯一标识OID,没有被session管理。
持久态对象,拥有唯一标识OID且被session管理。
脱管态对象,拥有唯一标识OID,但没有被session管理。

2.2 持久化对象的三种状态转换

image.png

第三节 Hibernate的一级缓存

缓存是计算机领域非常通用的概念。它介于应用程序和永久性数据存储源(如硬盘上的文件或者数据库)之间,其作用是降低应用程序直接读写永久性数据存储源的频率,从而提供应用的运行性能。缓存汇总的数据是数据存储源中数据的拷贝。缓存的物理介子通常是内存。
Hibernate的缓存分为一级缓存和二级缓存,Hibernate的这两级缓存都位于持久化层,存储的都是数据库数据的备份。其中第一级缓存为Hibernate的内置缓存,不能被卸载。

3.1 什么是Hibernate的一级缓存

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

3.2 Hibernate的一级缓存特点:

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

3.3 Hibernate一级缓存的特殊区域(快照区)

image.png

第四节 Hibernate的事务管理

4.1 数据库事务的回顾

  • 4.1.1 什么是事务:
    事务指的是逻辑上的一组操作,组成这组操作的各个逻辑单元执行时要么全部成功,要么全部失败;

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

  • 4.1.3 如果不考虑事务的隔离性,会引发那些问题:
    ①读问题

    • 脏读:一个事务读到另一个事务未提交的数据
    • 不可重复读:一个事务读到另一个事务已经提交update的数据,导致在前一事务中多次查询结果不一致
    • 虚读:一个事务读到另一个事务已经插入insert数据,导致在前一个事务多次查询结果不一致

    ②写问题(了解)

    • 引发两类丢失更新问题。
  • 4.1.4 读问题的解决方法
    设置事务的隔离级别:

    • Read uncommitted:以上读问题都会发生
    • Read committed:解决脏读,不可重复读和虚读有可能发生
    • Repeatable read:解决脏读和不可重复读,虚读有可能发生
    • Serializable:解决所有读的问题

4.2 Hibernate中事务隔离级别的设置

在hibernate配置文件中配置如下属性:

   
        
        4

4.3 Service层事务管理

Service业务层的复杂业务对DAO层的调用必须保证连接对象是同一个,通常的解决方案有:
①:向下传递
②:使用ThreadLocal对象进行绑定,将连接对象绑定到当前线程中,在DAO的方法调用中,通过当前线程来获取连接对象。

4.5 Hibernate中针对Service层事务的管理方法

Hibernate框架内部已经绑定了ThreadLocal,在SessionFactory中提供了一个方法getCurrentSession()来获取连接对象。但这个方法的调用前提需修改Hibernate的属性,如下

 
        
        thread

则session连接对象的获取方式:该连接对象在执行完成后无需手动关闭。

/**
     * currentSission对象的获取
     * @return
     */
    public static Session getCurrentSission(){
        return sessionFactory.getCurrentSession();
    }

第五节:Hibernate中的查询对象简介

5.1 Query

Query代表面向对象的一个Hibernate查询操作。在Hibernate中,通常使用session.createQuery()方法接受一个HQL语句,然后调用Query的list()或uniqueResult()方法执行查询。所谓的HQL是Hibernate Query Language缩写,其语法很像SQL语法,但它是完全面向对象的。

在Hibernate中使用Query对象的步骤:

  • 获得Hibernate的Session对象
  • 编写HQL语句
  • 调用session.createQuery()创建查询对象
  • 如果HQL语句包含参数,则调用Query的setXxx设置参数
  • 调用Query对象的list()或uniqueResult()方法执行查询
    @Test
    public void findByQuery(){
        Session currentSission = HibernateUtil.getCurrentSission();
        Transaction transaction = currentSission.beginTransaction();
        //查询所有人员数据
//        String hql = "from Customer";
        //条件查询(使用命名参数的方式)
//        String hql = "SELECT c from Customer c where c.cust_name like :name ";
        //分页查询
        String hql = "from Customer";

        Query query = currentSission.createQuery(hql);
        //插入检索条件
//        query.setParameter("name","小%");
        //插入分页查询条件
        query.setFirstResult(0);//从第i条开始
        query.setMaxResults(1);//每页展示的数据为0条
        List list = query.list();
        for (Customer customer: list) {
            System.out.println(customer.toString());
        }
        transaction.commit();
    }

5.2 criteria

Query by Criteria 是更加面向对象的一种查询方式。

 @Test
    public void findByCriteria(){
        Session currentSission = HibernateUtil.getCurrentSission();
        Transaction transaction = currentSission.beginTransaction();
        //通过criteria进行查询
//        Criteria criteria = currentSission.createCriteria(Customer.class);已过时
        //1.import javax.persistence.criteria.CriteriaQuery;获取Criteria对象
        CriteriaQuery query = currentSission.getCriteriaBuilder().createQuery(Customer.class);
        //2.指定根条件
        query.from(Customer.class);
        //3.执行查询
//        List resultList = currentSission.createQuery(query).getResultList();
        //3.1 执行分页查询
        List resultList = currentSission.createQuery(query)
                .setFirstResult(0)//设置开始位置
                .setMaxResults(1)//设置每页条数
                .getResultList();
        for (Customer customer: resultList) {
            System.out.println(customer.toString());
        }
        transaction.commit();
    }

5.3 SQL Query

SQLQuery用于结束sql,特别复杂的情况下使用SQL。

你可能感兴趣的:(SSH框架之Hibernate进阶持久化对象及事务管理(二))