一、持久化类的编写规则

1、持久化类的概述

  持久化:将内存中的一个对象持久化到数据库中的过程.Hibernate 框架就是用来持久化的框架
  持久化类:一个 Java 类与数据库中的表建立映射关系.那么这个类在 Hibernate 中称为持久化类
  持久化类 = Java 类 + 映射文件

2、持久化类的编写规则

  • 对持久化类提供一个无参构造方法 :Hibernate 底层需要使用反射生成实例
  • 属性需要私有,私有的属性提供 get 和 set 方法 :Hibernate 中获取、设置对象的值
  • 对持久化类提供一个唯一标识 OID 与数据库主键对应 :Java 中通过内存地址区分是否是同一个
  • 对象,数据库中通过主键区分是否为同一条记录,Hibernate 中通过 OID 区分是否为同一个对象
  • 持久化类中属性尽量使用包装类 :因为基本数据类型默认值是:0,0有很多歧义.包装类默认值为 null
  • 持久化类不要使用 final 修饰 :延迟加载本身是 Hibernate 的一个优化手段,返回一个代理对象(javassist可以对没有实现接口的类产生代理--使用类非常底层的字节码增强技术,继承这个类进行代理)。如果不能被继承,就不能产生代理对象,延迟加载也就失效了。load和 get 方法一致。

二、主键生成策略

1、主键的分类

  • 自然主键
    自然主键:主键本身就是表中的一个字段(实体类中的一个属性)。创建一个人员表,使用身份证(唯一不可重复)作为主键,这种主键称为自然主键

  • 代理主键
    代理主键:主键本身不是表中必须的一个字段(不是实体中的具体的属性)。创建一个人员表,不使用身份证作为主键,使用不相关的ID作为主键,这种主键称为代理主键。实际开发中,尽量使用代理主键

2、主键的生成策略

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

  • increment
    Hibernate 中提供的自动增长机制,适用 short int lang 类型的主键,在单线程程序中使用首先发送一条SQL语句:select max(id) from 表; 然后让 id+1,作为下一条记录的主键

  • identity
    适用 short int lang 类型的主键,使用的是数据库底层的自动增长机制.适用于有自动增长机制的数据库(MySQL), Oracle 没有自动增长机制.

  • sequence
    适用于 short int lang 类型的主键,采用序列的方式.(Oracle支持序列),MySQL 不支持序列.

  • uuid
    适用于字符串类型的主键,使用 Hibernate 中随机的方式生成字符串主键

  • native
    本地策略,可以在 identity 和 sequence 之间切换.

  • assigned
    Hibernate 放弃外键的管理,需要通过手动编写程序和用户自己设置.

  • foreign
    外部的,在一对一的关联映射情况下使用.

三、持久化类的三种状态

  Hibernate 是持久层的 ORM 框架,专注于数据的持久化工作。在进行数据持久化操作时,持久化对象可能处于不同的状态当中。这些状态可分为三种,分别为瞬时态、持久态和脱管态。下面分别针对这三种状态进行简单介绍。

1、三种状态的介绍

  • 瞬时态(transient)
    瞬时态也称为临时态或者自由态,瞬时态的对象是由 new 关键字开辟内存空间的对象,不存在持久化标识 OID(相当于主键值),且未与任何的 Session 实例相关联,在数据库中也没有记录,失去引用后将被 JVM 回收。瞬时对象在内存孤立存在,它是携带信息的载体,不和数据库的数据有任何关联关系。

  • 持久态(persistent)
    持久态的对象存在一个持久化标识 OID,当对象加入到 Session 缓存中时,就与 Session 实例相关联。它在数据库中存在与之对应的记录,每条记录只对应唯一的持久化对象。需要注意的是,持久态对象是在事务还未提交前变成持久态的。

  • 脱管态(detached)
    脱管态也称离线态或者游离态,当持久化对象与 Session 断开时就变成了脱管态,但是脱管态依然存在持久化标识 OID,只是失去了与当前 Session 的关联。需要注意的是,脱管态对象发生改变时Hibernate 是不能检测到的。

2、三种状态的区分

package com.qidishixun.Hibernate;

import com.qidishixun.Hibernate.domain.Customer;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import java.io.Serializable;

public class HibernateDemo2 {


    @Test
    public void test1(){
        Session session = HibernateUtils.openSession();
        Transaction transaction = session.beginTransaction();

        Customer customer = new Customer();
        //瞬时态对象:没有唯一标识OID,被session 管理
        customer.setCust_name("张三丰");

        Serializable id = session.save(customer);

        //持久态对象:有唯一表示OID,被session 管理
        Customer customer2 = session.get(Customer.class,id);

        transaction.commit();
        session.close();

        //托管态对象:有唯一表示OID, 没有被session管理,session已经close了
        System.out.println("客户名称:" + customer.getCust_name());

    }

}

3、三种状态转换

  • 三种状态转换图

Hibernate学习笔记二-LMLPHP

  • 瞬时态对象
获得
Customer customer = new Customer();

状态转换
瞬时 --> 持久
save(Object obj)、saveOrUpdate(Object obj)

瞬时 --> 托管
customer.setCust_id(1L);

  • 持久态对象
获得
get()、load()

状态转换
持久 --> 瞬时
delete();

持久 --> 托管
close()、clear()、evict()
  • 托管态对象
获得
Customer customer = new Customer();
customer.setCust_id(1L);

状态转换
托管 --> 持久
update()、saveOrUpdate();

托管 --> 瞬时
customer.setCust_id(null);

4、持久态对象的特性

  • 持久态对象可以自动更新数据库
    @Test
    public void test2(){
        Session session = HibernateUtils.openSession();
        Transaction transaction = session.beginTransaction();

        //获得持久态对象 get load
        Customer customer = session.get(Customer.class, 1L);
        customer.setCust_name("王娜");
//        session.update(customer);

        transaction.commit();
        session.close();
    }

四、Hibernate 的一级缓存

1、Hibernate 的一级缓存

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

2、证明 Hibernate 的一级缓存存在

package com.qidishixun.Hibernate;

import com.qidishixun.Hibernate.domain.Customer;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

/**
 * Hibernate 的一级缓存
 * @ClassName: HibernateDemo3
 * @Author Gui
 * @Date 2021/6/28
 * @Version 1.0
 */
public class HibernateDemo3 {


    @Test
    public void test1(){

        Session session = HibernateUtils.openSession();
        Transaction transaction = session.beginTransaction();

        Customer customer1 = session.get(Customer.class, 1L);
        System.out.println(customer1);

        Customer customer2 = session.get(Customer.class, 1L);
        System.out.println(customer2);

        System.out.println(customer1 == customer2);

        transaction.commit();
        session.close();


    }
}

Hibernate学习笔记二-LMLPHP

五、Hibernate 事务管理

1、绑定线程的 Session

  Hibernate5 中自身提供了三种管理 Session 对象的方法

  • Session 对象的生命周期与本地线程绑定
  • Session 对象的生命周期与 JTA 事务绑定
  • Hibernate 委托程序管理 Session 对象的声明周期

  在 Hibernate 配置文件中,hibernate.current_session_context_class 属性用于指定 Session 管理方式,可选值包括

  • thread: Session 对象的生命周期与本地线程绑定
  • jta: Session 对象的生命周期与 JTA 事务绑定
  • managed: Hibernate 委托程序管理 Session 对象的声明周期

  在 hibernate.cfg.xml 配置文件中进行如下配置:

<!-- 配置 Session 绑定本地线程 -->
<property name="hibernate.current_session_context_class">thread</property>

Hibernate学习笔记二-LMLPHP

2、修改 HibernateUtils 工具类

    /**
     * 提供获得 Session方法
     * @return
     */
    public static Session getCurrentSession(){
        return sessionFaction.getCurrentSession();
    }

测试

    @Test
    public void test3(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();

        Customer customer = new Customer();
        customer.setCust_name("大哥哥");
        session.save(customer);

        transaction.commit();
        //这里不需要关闭session,因为线程结束Session自动销毁
    }

六、Hibernate 的其他 API

1、Query

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

  1. 获得 Hibernate 的 Session 对象
  2. 编写 HQL 语句
  3. 调用 session.createQuery() 创建查询对象
  4. 如果 HQL 语句包含参数,则调用 Query 的 setXXX 方法设置参数
  5. 调用 Query 的 list() 或 uniqueResult() 方法执行查询

  • 查询所有
package com.qidishixun.Hibernate;

import com.qidishixun.Hibernate.domain.Customer;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import java.util.List;

/**
 * 利用Hibernate API 查询数据库表
 * @ClassName: HibernateDemo4
 * @Author Gui
 * @Date 2021/6/28
 * @Version 1.0
 */
public class HibernateDemo4 {

    @Test
    public void test1(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();

        String hql = "from Customer";
        Query query = session.createQuery(hql);
        List<com.qidishixun.Hibernate.domain.Customer> customers = query.list();
        for (com.qidishixun.Hibernate.domain.Customer customer :customers){
            System.out.println(customer);
        }
        transaction.commit();
    }

}

  • 条件查询
    /**
     * 模糊查询
     */
    @Test
    public void test2(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();

        String hql = "from Customer where cust_name like ?";
        Query query = session.createQuery(hql);
        query.setParameter(0, "大%");
        List<com.qidishixun.Hibernate.domain.Customer> customers = query.list();
        for (com.qidishixun.Hibernate.domain.Customer customer : customers){
            System.out.println(customer);
        }
        transaction.commit();
    }
  • 分页查询
    /**
     * 分页查询
     */
    @Test
    public void test3(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();

        String hql = "from Customer";
        Query query = session.createQuery(hql);

        //设置分页查询的条件
        query.setFirstResult(3); //从几开始
        query.setMaxResults(3); //每页显示几条

        List<com.qidishixun.Hibernate.domain.Customer> customers = query.list();
        for (Customer customer : customers){
            System.out.println(customer);
        }
        transaction.commit();
    }

2、Criteria

  Criteria:QBC查询(Query By Criteria) ,更加面向对象的一种查询方式

  • 查询所有
package com.qidishixun.Hibernate;

import com.qidishixun.Hibernate.domain.Customer;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;
import org.junit.Test;

import java.util.List;

/**
 * 更加面向对象的一种查询
 * @ClassName: HibernateDemo5
 * @Author Gui
 * @Date 2021/6/28
 * @Version 1.0
 */
public class HibernateDemo5 {

    @Test
    public void test1(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();

        //通过 Session 获取 criteria
        Criteria criteria = session.createCriteria(com.qidishixun.Hibernate.domain.Customer.class);
        List<com.qidishixun.Hibernate.domain.Customer> customers = criteria.list();
        for (com.qidishixun.Hibernate.domain.Customer customer : customers){
            System.out.println(customer);
        }

        transaction.commit();
    }
}

  • 条件查询
    @Test
    public void test2(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();

        //通过Session 获取 criteria
        Criteria criteria = session.createCriteria(com.qidishixun.Hibernate.domain.Customer.class);

        //设置条件
        criteria.add(Restrictions.ilike("cust_name","小%"));

        List<com.qidishixun.Hibernate.domain.Customer> list = criteria.list();
        for (com.qidishixun.Hibernate.domain.Customer customer : list){
            System.out.println(customer);
        }

        transaction.commit();
    }

  • 分页查询
    /**
     * 分页查询
     */
    @Test
    public void test3(){

        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();

        //通过 Session 获取 criteria
        Criteria criteria = session.createCriteria(com.qidishixun.Hibernate.domain.Customer.class);

        //设置分页
        criteria.setFirstResult(1); //跳过几个开始查询
        criteria.setMaxResults(3);

        List<com.qidishixun.Hibernate.domain.Customer> list = criteria.list();
        for (Customer customer : list){
            System.out.println(customer);
        }
        transaction.commit();
    }

3、SQLQuery


    /**
     * HQL  和  SQL 的写法
     */
    @Test
    public void test4(){
        Session session = HibernateUtils.openSession();
        Transaction transaction = session.beginTransaction();

        SQLQuery sqlQuery = session.createSQLQuery("select * from cst_customer");
        List<Object[]> list1 = sqlQuery.list();
        for (Object[] object : list1){
            System.out.println(object.toString());
        }

        transaction.commit();
        session.close();
    }
06-30 03:47