Hibernate介绍

Hibernate是一个开源的Java对象关系映射(ORM)框架,它提供了一种方便的方式将Java对象与关系型数据库进行映射和交互。通过Hibernate,开发人员可以使用面向对象的方式操作数据库,而不需要直接编写SQL查询语句

架构图

image-20250510200612347

Hibernate是一个开源的对象关系映射(ORM)框架,用于将Java对象映射到关系型数据库中的关系表。 它提供了一种面向对象的方式来操作数据库,简化了开发人员对数据库的访问和管理

如何理解提供了一种面向对象的方式来操作数据库。

一方面:Hibernate可以将定义好的java类映射为数据库中的表,并将java类的实例化的对象,映射为对应表中的一行记录。 另一方面:使用Hibernate,开发人员可以直接操作对象,不需要编写复杂的SQL语句。通过对象的属性和方法来进行数据的读取、修改和删除等操作。

Hibernate提供的核心功能和特性

ORM映射(可以将java对象与数据库表之间进行映射,实现对象和关系数据库之间的转换,支持各种映射策略和注解);

数据库查询(提供了一组丰富的API,用于执行数据库操作,包括插入、更新、删除、查询,还支持HQL和基于SQL的查询一级Criteria查询和原生SQL查询);

缓存机制(Hibernate内置了一级缓存和二级缓存机制,用于提供查询性能和减少数据库的访问。一级缓存是会话级别的缓存,保存了会话期间加载的实体对象。二级缓存是跨会话的缓存,可以在多个会话之间共享缓存数据);

事物管理(可以通过编程或声明式的方式管理数据库事物。支持标准的java事物API(JTA)和本地事物管理);

延迟加载(允许按需加载关联对象,提高查询性能。这意味着只有在需要访问关联对象时,才会从数据库中加载相应的数据。);

对象状态管理(通过跟踪对象的状态来管理对象的持久化。它提供了持久化、脱管和删除等状态之间的转换,使开发人员能够方便地操作对象。)

对象的持久化

把对象永久的保存到数据库中

持久化包括和数据库相关的各种操作

  • 保存
  • 更新
  • 删除
  • 查询
  • 加载:加载特定的 OID,把一个对象从数据库加载到内存中

OID:为了在系统中能找到所需对象,需要为对象分配一个唯一的标识号,在关系型数据库中称为主键,在对象术语中叫对象标识OID

ORM 对象关系映射

ORM主要解决对象-关系的映射

  • 类的一个对象可以对应一张表,对象对应表的行,属性对应位表的列

ORM的思想:将关系数据库中表中的记录映射成为对象,以对象的形式展现,程序员可以把对数据库的操作转化为对对象的操作。 ORM 采用元数据来描述对象-关系映射细节,元数据通常采用XML 格式,并且存放在专门的对象-关系映射文件中。描述数据的数据

image-20250510201350695

Hibernate框架的优点

  • 使开发更加面向对象化:Hibernate提供了一个面向对象的编程模型,使开发人员可以使用面向对象的思想来操作数据库。

  • 提高开发效率:Hibernate提供了许多强大的特性和工具:如自动生成数据库表结构,提供了公共的操作数据库的方法,让开发人员不用写SQL语句、缓存机制、事物管理。可以大大减少开发人员的工作量,提高开发效率。

  • 可移植性:Hibernate可以在不同的数据库系统上运行,如Mysql、Oracle、SQL Server等,开发人员可以使用统一的API和语法,无需关系底层数据库的差异。

Hibernate、jpa、jdbc他们三者之间是什么关系

  • jdbc:jdbc是Java提供的用于与关系型数据库进行交互的标准API,它提供了一组接口和类,使开发人员能够执行数据库的连接、查询、更新等操作。JDBC 需要开发人员手动编写 SQL 查询和处理数据库结果集,对于较低层次的数据库操作提供了灵活性。使开发人员能够执行数据库的连接、查询、更新等操作。JDBC 需要开发人员手动编写 SQL 查询和处理数据库结果集,对于较低层次的数据库操作提供了灵活性。
  • JPA:JPA是Java持久化标准,定义了一组API和规范,提供了一种与数据库无关的方式来操作实体对象。JPA定义了实体、映射关系、查询语言和事物管理等方面的规范,使开发人员能够以面向对象的方式进行数据库的操作。
  • Hibernate:Hibernate实现了JPA规范,同时还提供了一些额外的功能和特性。Hibernate封装了底层的JDBC操作,提供了更高层次的抽象,来简化开发人员对数据库的访问。通过 HIbernate 开发人员可以通过配置和注解来定义实体和映射关系,使用面向对象的方式进行数据库操作。

Hibernate 是 JPA 的实现之一,而 JPA 则是对数据库持久化操作的规范。JDBC 是底层的数据库连接和操作技术,Hibernate 和 JPA 则在 JDBC 的基础上提供了更高层次的抽象和便利性,使得开发人员能够以面向对象的方式进行数据库操作

下载安装

现在 Spring Boot JPA 集成的 Hibernate 进行数据持久化更加常见,

一般不用安装,装好依赖就行了,配置文件配置properties就行。

不用maven导入,jar包到 官网 下就行。

下载网站:https://sourceforge.net/projects/hibernate/files/hibernate-orm/

Hibernate开发步骤

image-20250511142748170

第一个例子——学生信息管理

编写例子

  1. 创建了一个Java项目(Maven或Gradle)

  2. 添加了Hibernate依赖(如果是Maven项目,在pom.xml中添加)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <!-- Hibernate核心依赖 -->
    <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>5.6.14.Final</version>
    </dependency>
    <!-- 数据库驱动(这里使用H2内存数据库作为示例) -->
    <dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>2.1.214</version>
    </dependency>
  3. 创建实体类

    使用hibernate时候,不需要自己手动创建表,hibernate帮把表创建

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    import javax.persistence.*;

    @Entity
    @Table(name = "students")
    public class Student {

    // Hibernate作为JPA的实现,支持这些标准JPA注解
    // 注解表示了对象关系映射的基本信息
    // Hibernate 要求实体类有一个属性是唯一的
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name", nullable = false)
    private String name;

    @Column(name = "email")
    private String email;

    @Column(name = "age")
    private Integer age;

    // 必须有无参构造函数
    public Student() {}

    // 全参构造函数
    public Student(String name, String email, Integer age) {
    this.name = name;
    this.email = email;
    this.age = age;
    }

    // Getter和Setter方法
    public Long getId() {
    return id;
    }

    public void setId(Long id) {
    this.id = id;
    }

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }

    public String getEmail() {
    return email;
    }

    public void setEmail(String email) {
    this.email = email;
    }

    public Integer getAge() {
    return age;
    }

    public void setAge(Integer age) {
    this.age = age;
    }

    @Override
    public String toString() {
    return "Student{" +
    "id=" + id +
    ", name='" + name + '\'' +
    ", email='" + email + '\'' +
    ", age=" + age +
    '}';
    }
    }
  4. 使用xml或者纯注解配置

    Hibernate配置文件 hibernate.cfg.xml 是Hibernate框架中至关重要的部分,它负责初始化Hibernate并提供与数据库交互所需的所有配置信息。在这个配置文件中,开发者需要指定数据库连接的URL、用户名和密码,以及数据库使用的方言,这些信息是Hibernate能够正常工作所必须的。

    该配置文件的结构通常包含以下几个主要部分:

    • hibernate-configuration :这是配置文件的根元素,其中可以包含一个或多个 session-factory 元素。
    • session-factory :定义了一个或多个 session-factory ,每一个 session-factory 都可以配置不同的数据库连接信息。
    • property :在 session-factory 内部,使用多个 property 元素来指定Hibernate连接数据库所需的参数,如
    • connection.url 、 connection.username 、 connection.password 、 dialect 等。
    • mapping :这个元素用于指定实体类与数据库表的映射关系,可以通过 class 或 mapping-file 指定。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
    <hibernate-configuration>
    <session-factory>
    <!-- 数据库连接设置 -->
    <property name="hibernate.connection.driver_class">org.h2.Driver</property>
    <property name="hibernate.connection.url">jdbc:h2:mem:testdb</property>
    <property name="hibernate.connection.username">sa</property>
    <property name="hibernate.connection.password"></property>

    <!-- JDBC连接池大小 -->
    <property name="hibernate.connection.pool_size">1</property>

    <!-- SQL方言 - 告诉Hibernate使用哪种数据库语法 -->
    <property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property>

    <!-- 在控制台显示SQL语句 -->
    <property name="hibernate.show_sql">true</property>

    <!-- 自动创建/更新数据库表结构 -->
    <property name="hibernate.hbm2ddl.auto">update</property>

    <!-- 映射实体类 -->
    <mapping class="com.example.Student"/>
    </session-factory>
    </hibernate-configuration>

    数据库连接和方言配置: 配置数据库连接信息是通过 hibernate.cfg.xml 中 property 元素的几个关键属性来完成的。 connection.url 指定了数据库的连接字符串, connection.username 和 connection.password 分别指定了数据库的用户名和密码,而 dialect 属性则指定了对应数据库的方言。 方言配置对于Hibernate的SQL生成至关重要。方言是Hibernate为不同数据库提供的抽象,它知道如何生成特定数据库支持的SQL语法。这样,Hibernate可以为不同的数据库产生正确的SQL语句而无需修改代码。

    参数说明 :

    connection.url :该属性定义了数据库的连接URL,格式取决于所使用的JDBC驱动程序。
    connection.username 和 connection.password :分别定义了访问数据库时所需的用户名和密码。
    dialect :该属性指定了数据库方言的完全限定类名,Hibernate根据这个类来生成特定数据库的SQL语句。 

    使用properties配置文件和xml配置属于是一样的

    在纯注解方式下,我们可以完全摆脱hibernate.cfg.xml文件,使用Java配置类和JPA注解来配置Hibernate。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    import java.util.Properties;
    import javax.sql.DataSource;
    import org.hibernate.SessionFactory;
    import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
    import org.hibernate.cfg.AvailableSettings;
    import org.hibernate.cfg.Configuration;
    import org.hibernate.service.ServiceRegistry;

    public class HibernateUtil {

    private static SessionFactory sessionFactory;

    public static SessionFactory getSessionFactory() {
    if (sessionFactory == null) {
    try {
    Configuration configuration = new Configuration();

    // 设置数据库连接属性
    Properties settings = new Properties();
    settings.put(AvailableSettings.DRIVER, "org.h2.Driver");
    settings.put(AvailableSettings.URL, "jdbc:h2:mem:testdb");
    settings.put(AvailableSettings.USER, "sa");
    settings.put(AvailableSettings.PASS, "");

    // Hibernate特定属性
    settings.put(AvailableSettings.DIALECT, "org.hibernate.dialect.H2Dialect");
    settings.put(AvailableSettings.SHOW_SQL, "true");
    settings.put(AvailableSettings.HBM2DDL_AUTO, "update");

    configuration.setProperties(settings);

    // 添加实体类
    configuration.addAnnotatedClass(Student.class);

    ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
    .applySettings(configuration.getProperties()).build();

    sessionFactory = configuration.buildSessionFactory(serviceRegistry);
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    return sessionFactory;
    }

    public static void shutdown() {
    if (sessionFactory != null) {
    sessionFactory.close();
    }
    }
    }
  5. 创建主程序进行 CURD 操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    ,创建SessionFactory对象import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.Transaction;
    import org.hibernate.cfg.Configuration;

    import java.util.List;

    public class HibernateDemo {

    public static void main(String[] args) {
    // 1. 创建SessionFactory,对应hibernate基本配置信息
    // 加载hibernate核心配置文件,Configuration类加载 hibernate.cfg.xml
    SessionFactory sessionFactory = new Configuration()
    .configure("hibernate.cfg.xml")
    .buildSessionFactory();

    try {
    // 2. 创建Session,创建SessionFactory对象
    // 并且使用SessionFactory创建session对象,类似于连接
    Session session = sessionFactory.openSession();

    // 3. 开始事务
    Transaction transaction = session.beginTransaction();

    // 4. 创建学生对象并保存
    Student student1 = new Student("张三", "zhangsan@example.com", 20);
    Student student2 = new Student("李四", "lisi@example.com", 22);

    System.out.println("保存学生...");
    // 调用session的方法实现添加
    session.save(student1);
    session.save(student2);

    // 5. 提交事务
    transaction.commit();

    // 6. 查询所有学生
    transaction = session.beginTransaction();
    System.out.println("\n查询所有学生...");
    List<Student> students = session.createQuery("from Student", Student.class).list();
    students.forEach(System.out::println);

    // 7. 更新学生信息
    System.out.println("\n更新学生信息...");
    Student studentToUpdate = session.get(Student.class, student1.getId());
    studentToUpdate.setEmail("newemail@example.com");
    session.update(studentToUpdate);

    // 8. 再次查询验证更新
    System.out.println("\n查询更新后的学生...");
    Student updatedStudent = session.get(Student.class, student1.getId());
    System.out.println(updatedStudent);

    // 9. 删除学生
    System.out.println("\n删除学生...");
    session.delete(student2);

    // 10. 最终查询
    System.out.println("\n最终学生列表...");
    students = session.createQuery("from Student", Student.class).list();
    students.forEach(System.out::println);

    transaction.commit();

    // 11. 关闭Session
    session.close();

    } finally {
    // 12. 关闭SessionFactory
    sessionFactory.close();
    }
    }
    }

    这个例子使用了H2内存数据库,所以不需要额外安装数据库服务器,H2数据库非常适合学习和测试。

    这个简单的示例展示了Hibernate的核心功能:

    1. 对象-关系映射:通过注解将Java类映射到数据库表
    2. CRUD操作
      • 创建(Create):session.save()
      • 读取(Read):session.get()和HQL查询
      • 更新(Update):session.update()
      • 删除(Delete):session.delete()
    3. 事务管理:通过Transaction对象管理
    4. HQL查询:使用面向对象的查询语言from Student

    使用新的配置方式,该如何写

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    import org.hibernate.Session;
    import org.hibernate.Transaction;

    public class HibernateAnnotationDemo {

    public static void main(String[] args) {
    // 获取SessionFactory
    SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
    Session session = sessionFactory.openSession();

    try {
    // 开始事务
    Transaction transaction = session.beginTransaction();

    // 创建并保存学生
    Student student1 = new Student("王五", "wangwu@example.com", 21);
    Student student2 = new Student("赵六", "zhaoliu@example.com", 23);

    System.out.println("保存学生...");
    session.save(student1);
    session.save(student2);

    // 提交事务
    transaction.commit();

    // 查询示例
    transaction = session.beginTransaction();
    System.out.println("\n所有学生:");
    List<Student> students = session.createQuery("from Student", Student.class).list();
    students.forEach(System.out::println);

    transaction.commit();

    } finally {
    session.close();
    HibernateUtil.shutdown();
    }
    }
    }

    其中的注解声明

    注解 来源 说明
    @Entity JPA 标记类为实体类,将映射到数据库表
    @Table JPA 指定映射的表名
    @Id JPA 标记主键字段
    @GeneratedValue JPA 指定主键生成策略
    @Column JPA 指定字段与列的映射关系
    @Transient JPA 标记不持久化的字段

涉及到的API

Configuration

在使用Hibernate时,首先要创建Configuration实例,Configuration实例主要用于启动、加载、管理hibernate的配置文件信息

  • Hibernate 运行的底层信息:数据库的 URL,用户名,密码,JDBC驱动类,数据库Diaiect,数据库连接池等,对应hibernate.cfg.xml 文件
  • 持久化类与数据表的映射关系 hbm.xml文件

在启动Hibernate的过程中,Configuration实例首先确定Hibernate配置文件的位置,然后读取相关配置,最后创建一个唯一的SessionFactory实例。Configuration对象只存在于系统的初始化阶段,它将SessionFactory创建完成后,就完成了自己的使命。

Hibernate通常使用Configuration config = new Configuration().configure();的方式创建实例,此种方式默认会去src下读取hibernate.cfg.xml配置文件。如果不想使用默认的hibernate.cfg.xml配置文件,而是使用指定目录下(或自定义)的配置文件,则需要向configure()方法中传递一个文件路径的参数,其代码写法如下:

1
Configuration config = new Configuration().configure("xml文件位置");

传递 hibernate.properties 属性文件

1
Configuration config = new Configuration();

此种写法hibernate会去指定位置查找配置文件,例如,想要使用src下config包中的hibernate.cfg.xml文件,只需将文件位置加入configure()中即可,其代码如下所示:

1
Configuration config = new Configuration().configure("/config/hibernate.cfg.xml");

SessionFactory

SessionFactory接口负责Hibernate的初始化和建立Session对象。它在Hibernate中起到一个缓冲区作用,Hibernate可以将自动生成的SQL语句、映射数据以及某些可重复利用的数据放在这个缓冲区中。同时它还保存了对数据库配置的所有映射关系,维护了当前的二级缓存。

  • 针对单个数据库映射关系经过编译后的内存镜像,是线程安全的。
  • SessionFactory对象一且构造完毕,即被赋予特定的配置信息。
  • SessionFactory是生成Session的工厂
  • 构造SessionFactory很消耗资源,一般情况下一个应用中只初始化一个SessionFactory对象。
  • Hibernate4 新增了一个ServiceRegistry接口,所有基于Hibernate 的配置或者服务都必须统一向这个ServiceRegistry注册后才能效,但是 Hibernate5 又不需要了

SessionFactory实例是通过Configuration对象获取的,其获取方法如下所示:

1
SessionFactory sessionFactory = config.buildSessionFactory();

SessionFactory具有以下特点:

  • 它是线程安全的,它的同一个实例能够供多个线程共享。
  • 它是重量级的,不能随意的创建和销毁它的实例。

由于SessionFactory的这些特点,一般情况下,一个项目中只需要一个SessionFactory,只有当应用中存在多个数据源时,才为每个数据源建立一个SessionFactory实例。因此,在实际项目使用中,通常会抽取出一个HibernateUtils的工具类,用来提供Session对象。

Session

Session是应用程序与数据库之间交互操作的一个单线程对象,是Hibernate运作的中心,它的主要功能是为持久化对象提供创建、读取和删除的能力,所有持久化对象必须在session的管理下才可以进行持久化操作。

相当于 JDBC 的 Connection,持久化类与 Session 关联起来之后就具有了持久化的能力

创建SessionFactory实例后,就可以通过它获取Session实例。获取Session实例有两种方式,一种是通过openSession()方法,另一种是通过getCurrentSession()方法。两种方法获取session的代码如下:

1
2
3
4
// 采用openSession方法创建session => 获得全新session
Session session = sessionFactory.openSession();
// 采用getCurrentSession方法创建session => 获得与线程绑定的session
Session session = sessionFactory.getCurrentSession();

以上两种获取session实例方式的主要区别是,采用openSession方法获取Session实例时,SessionFactory直接创建一个新的Session实例,并且在使用完成后需要调用close方法进行手动关闭。而getCurrentSession方法创建的Session实例会被绑定到当前线程中,它在提交或回滚操作时会自动关闭。

Session是线程不安全的,多个并发线程同时操作一个Session实例时,就可能导致Session数据存在混乱(方法内部定义和使用Session时,不会出现线程问题)。因此设计软件架构时,应避免多个线程共享一个Sesion实例。同时它也是轻量级的,实例的创建和销毁不需要消耗太多的资源。它还有一个缓存,即Hibernate的一级缓存,这个缓存主要用于存放当前工作单元加载的对象。

在Session中提供了大量的常用方法,具体如下:

  • save()update()saveOrUpdate()方法:用于增加和修改对象
  • delete()方法:用于删除对象
  • get()load()方法:根据主键查询
  • createQuery()createSQLQuery()方法:用于数据库操作对象
  • createCriteria()方法:条件查询

Transaction

Transaction接口主要用于管理事务,它是Hibernate的数据库事务接口,且对底层的事务接口进行了封装。Transaction接口的事务对象是通过Session对象开启的,其开启方式如下所示:

1
Transaction transaction = session.beginTransaction();

在Transaction接口中,提供了事务管理的常用方法,具体如下:

  • commit()方法:提交相关联的session实例。
  • rollback()方法:撤销事务操作
  • wasCommitted()方法:检查事务是否提交

**Session执行完数据库操作后,要使用Transaction接口的commit()方法进行事务提交,才能真正的将数据操作同步到数据库中。

发生异常时,需要使用rollback()方法进行事务回滚,以避免数据发送错误。因此,在持久化操作后,必须调用Transaction接口的commit()方法和rollback()方法。如果没有开启事务,那么每个Session的操作,都相当于一个独立的操作。