Hibernate 4 教程:从入门到实践
目录
-
第一部分:Hibernate 简介
(图片来源网络,侵删)- 什么是 ORM?
- Hibernate 是什么?
- 为什么使用 Hibernate?
- Hibernate 4 的核心组件
-
第二部分:环境搭建
- 准备工作
- 创建 Maven 项目
- 添加 Hibernate 4 和 MySQL 驱动依赖
-
第三部分:第一个 Hibernate 程序 (Hello World)
- 数据库准备
- 创建实体类
- 创建映射文件
- 创建 Hibernate 配置文件
- 编写核心 Java 代码
- 运行与测试
-
第四部分:Hibernate 核心 API
Configuration: 配置加载ServiceRegistry: 服务注册中心 (Hibernate 4 的关键)SessionFactory: 工厂类Session: 交互接口Transaction: 事务管理Query/Criteria: 查询接口
-
第五部分:CRUD 操作详解
(图片来源网络,侵删)- 创建 -
save()/persist() - 读取 -
get()/load() - 更新 -
update()/merge() - 删除 -
delete() - HQL (Hibernate Query Language) 简介
- 创建 -
-
第六部分:关联关系映射
- 多对一
- 一对多
- 一对一
- 多对多
-
第七部分:进阶特性
- 缓存机制 (一级缓存和二级缓存)
- 事务与并发
第一部分:Hibernate 简介
1 什么是 ORM?
ORM (Object-Relational Mapping),即“对象关系映射”,是一种编程技术,用于将面向对象模型与关系型数据库的数据结构进行映射,它允许开发者使用面向对象的方式来操作数据库,而无需编写繁琐的 SQL 语句。
- Java 对象 ↔ 数据库表
- 对象属性 ↔ 表的列
- 对象实例 ↔ 表的行
2 Hibernate 是什么?
Hibernate 是一个开源的、基于 ORM 模式的持久层框架,它对 JDBC 进行了轻量级的封装,使得 Java 开发者可以以面向对象的方式操作数据库。
3 为什么使用 Hibernate?
- 提高开发效率:告别手写复杂的 SQL 语句,专注于业务逻辑。
- 面向对象编程:代码更符合 Java 的编程思想,易于理解和维护。
- 数据库无关性:通过更换方言,可以轻松地将项目从一种数据库(如 MySQL)迁移到另一种(如 Oracle)。
- 强大的缓存机制:提供一级缓存和二级缓存,提升数据读取性能。
- 简化数据操作:提供了丰富的 API 来处理增删改查、关联关系等复杂操作。
4 Hibernate 4 的核心组件
Hibernate 4 引入了一个重要的变化:ServiceRegistry,它取代了早期版本中直接使用 Configuration 构建 SessionFactory 的方式,使得配置更加灵活和模块化。
Configuration: 负责加载和读取 Hibernate 的配置信息(如hibernate.cfg.xml)和映射文件(.hbm.xml)。ServiceRegistry: 一个服务注册中心,用于管理 Hibernate 所需的各种服务(如连接池、事务工厂、缓存等)。这是 Hibernate 4 的核心入口。SessionFactory: 线程安全的重量级对象,它是Session的工厂,一个数据库对应一个SessionFactory。Session: 轻量级非线程安全的对象,是 Java 应用程序与数据库交互的主要接口,它相当于 JDBC 中的Connection。Transaction: 管理事务,确保数据操作的原子性。Query/Criteria: 执行查询的接口,Query用于 HQL 查询,Criteria用于面向对象的、类型安全的查询。
第二部分:环境搭建
1 准备工作
- JDK 1.7 或更高版本
- IDE (如 IntelliJ IDEA 或 Eclipse)
- MySQL 数据库
- Maven (用于依赖管理)
2 创建 Maven 项目
在你的 IDE 中创建一个新的 Maven 项目。
3 添加依赖
打开 pom.xml 文件,添加以下依赖,我们使用 Hibernate 4.2.21 (一个稳定的 4.x 版本) 和 MySQL 5.1.38 驱动。
<dependencies>
<!-- Hibernate 4 Core -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.2.21.Final</version>
</dependency>
<!-- MySQL Connector/J -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<!-- (可选) JUnit 用于测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
第三部分:第一个 Hibernate 程序
我们将创建一个简单的 User 实体,并将其保存到数据库中。
1 数据库准备
在 MySQL 中创建一个数据库和一张表。
CREATE DATABASE hibernate_demo; USE hibernate_demo; CREATE TABLE `user` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(50) NOT NULL, `email` VARCHAR(100) DEFAULT NULL, PRIMARY KEY (`id`) );
2 创建实体类
创建一个 User.java 文件,它是一个普通的 Java Bean。
// src/main/java/com/example/entity/User.java
package com.example.entity;
public class User {
private Long id;
private String name;
private String email;
// 无参构造器 (Hibernate 反射需要)
public User() {
}
// Getters and Setters
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;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", email='" + email + '\'' +
'}';
}
}
3 创建映射文件
在 src/main/resources 目录下,创建 User.hbm.xml 文件,用于告诉 Hibernate 如何将 User 类映射到 user 表。
<!-- src/main/resources/User.hbm.xml -->
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.example.entity">
<class name="User" table="user">
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="name" column="name"/>
<property name="email" column="email"/>
</class>
</hibernate-mapping>
4 创建 Hibernate 配置文件
在 src/main/resources 目录下,创建 hibernate.cfg.xml 文件,配置数据库连接信息和 Hibernate 全局属性。
<!-- src/main/resources/hibernate.cfg.xml -->
<?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>
<!-- 1. 数据库连接信息 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate_demo</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">your_password</property>
<!-- 2. Hibernate 全局属性 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<!--
show_sql: 在控制台打印生成的 SQL 语句。
format_sql: 格式化输出的 SQL 语句。
hbm2ddl.auto: 自动管理表结构。
- update: 如果模型有变化,自动更新表结构(开发环境推荐)。
- create: 每次启动都删除并重建表(测试环境)。
- none: 不做任何操作(生产环境推荐)。
-->
<!-- 3. 映射文件 -->
<mapping resource="User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
5 编写核心 Java 代码
创建一个 HibernateUtil 工具类来获取 SessionFactory,以及一个 MainApp 类来执行操作。
HibernateUtil.java
// src/main/java/com/example/util/HibernateUtil.java
package com.example.util;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static final SessionFactory sessionFactory;
static {
try {
// 1. 加载配置文件
Configuration configuration = new Configuration().configure();
// 2. 创建 ServiceRegistry (Hibernate 4 的关键步骤)
StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties())
.build();
// 3. 使用配置和注册表创建 SessionFactory
sessionFactory = configuration.buildSessionFactory(registry);
} catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
MainApp.java
// src/main/java/com/example/MainApp.java
package com.example;
import com.example.entity.User;
import com.example.util.HibernateUtil;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
public class MainApp {
public static void main(String[] args) {
// 1. 获取 SessionFactory
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
// 2. 打开 Session
Session session = sessionFactory.openSession();
// 3. 开启事务
Transaction transaction = null;
try {
transaction = session.beginTransaction();
// 4. 创建 User 对象
User user = new User();
user.setName("John Doe");
user.setEmail("john.doe@example.com");
// 5. 保存 User 对象
session.save(user);
// 6. 提交事务
transaction.commit();
System.out.println("User saved successfully! ID: " + user.getId());
} catch (Exception e) {
if (transaction != null) {
transaction.rollback(); // 出错则回滚
}
e.printStackTrace();
} finally {
// 7. 关闭 Session
session.close();
}
// 8. 关闭 SessionFactory
sessionFactory.close();
}
}
6 运行与测试
运行 MainApp.java 的 main 方法。
- 你会在控制台看到 Hibernate 生成的
CREATE TABLE和INSERTSQL 语句。 - 登录你的 MySQL 数据库,查询
user表,会发现已经成功插入了一条数据。
第四部分:Hibernate 核心 API
我们已经在上面的例子中接触了这些核心 API,这里再详细解释一下它们的作用和关系。
-
Configuration:- 作用:读取配置文件(
hibernate.cfg.xml)和映射文件(.hbm.xml)。 - 在 Hibernate 4 中,它仍然是配置的起点。
- 作用:读取配置文件(
-
StandardServiceRegistry(ServiceRegistry):- Hibernate 4 的核心,它是一个服务注册中心,管理着 Hibernate 运行时所需的所有服务(如连接池、事务工厂、缓存提供商等)。
- 通过
StandardServiceRegistryBuilder构建,并将Configuration的属性应用到这些服务上。
-
SessionFactory:- 由
Configuration和ServiceRegistry共同构建。 - 它是重量级对象,创建和销毁成本高,通常一个应用只创建一个
SessionFactory实例。 - 它是线程安全的,可以被多个线程共享。
- 主要作用是生产
Session对象。
- 由
-
Session:- 轻量级对象,不是线程安全的,因此不能被多个线程共享。
- 它是应用程序与数据库进行交互的“门面”,相当于一个“工作单元”。
- 负责执行 CRUD 操作、管理事务、管理一级缓存。
-
Transaction:- 代表一次原子性操作(一个或多个 SQL 语句)。
- 必须显式地开始(
beginTransaction())和提交(commit()),如果发生异常则回滚(rollback())。
-
Query/Criteria:Query: 用于执行 HQL(Hibernate Query Language)查询,HQL 是一种面向对象的查询语言,语法类似于 SQL,但操作的是类和属性而不是表和列。Criteria: 提供了一种更面向对象、类型安全的方式来构建查询,无需手写 HQL 字符串。
第五部分:CRUD 操作详解
基于上面的 User 实体,我们演示完整的 CRUD 操作。
// 假设我们有一个 SessionFactory 实例
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
try {
// C: Create (创建)
User newUser = new User();
newUser.setName("Alice");
newUser.setEmail("alice@example.com");
session.save(newUser); // 插入
System.out.println("Created: " + newUser);
// R: Read (读取)
// get(): 立即加载,如果对象不存在返回 null
User user1 = (User) session.get(User.class, 1L); // 假设 ID 为 1
System.out.println("Get by ID 1: " + user1);
// load(): 延迟加载(返回代理对象),只有当访问对象属性时才真正去查询数据库,如果对象不存在,抛出 ObjectNotFoundException
User user2 = (User) session.load(User.class, 2L);
System.out.println("Load by ID 2: " + user2.getName()); // 这里才真正执行查询
// U: Update (更新)
if (user1 != null) {
user1.setEmail("alice_updated@example.com");
session.update(user1); // 更新
System.out.println("Updated: " + user1);
}
// D: Delete (删除)
if (user2 != null) {
session.delete(user2); // 删除
System.out.println("Deleted user with ID 2");
}
transaction.commit();
} catch (Exception e) {
if (transaction != null) {
transaction.rollback();
}
e.printStackTrace();
} finally {
session.close();
}
save(), update(), merge() 的区别:
save(): 将一个临时状态的对象变为持久状态,并分配一个 ID,如果对象已经有 ID,会抛异常。update(): 将一个游离状态(有 ID 但不在 Session 缓存中)的对象与 Session 关联,并同步到数据库,如果对象没有 ID,会抛异常。merge(): 更智能的更新方法,它会将对象的属性复制到持久状态对象中,并更新,Session 中没有对应的持久对象,它会从数据库加载一个,然后更新,通常推荐使用merge()来处理可能游离的对象。
第六部分:关联关系映射
关联关系是 ORM 的核心,我们以 User 和 Role(角色)为例,演示一对多关系。
场景: 一个用户可以有多个角色(如管理员、普通用户、访客),一个角色可以被多个用户拥有,这是一个典型的多对多关系,但为了演示,我们先简化成一对多:一个用户可以有多个地址。
1 多对一
场景: 多个 Address 属于一个 User。
-
创建
Address实体和映射文件// Address.java package com.example.entity; public class Address { private Long id; private String street; private String city; private User user; // 关联到 User // getters, setters, constructor... }<!-- Address.hbm.xml --> <hibernate-mapping package="com.example.entity"> <class name="Address" table="address"> <id name="id" column="id"> <generator class="native"/> </id> <property name="street" column="street"/> <property name="city" column="city"/> <!-- 多对一映射 --> <many-to-one name="user" class="User" column="user_id" not-null="true"/> </class> </hibernate-mapping>name="user":Address实体中关联的属性名。class="User": 关联的实体类。column="user_id": 在address表中,外键的列名。
-
在
User.hbm.xml中添加一对多映射<!-- User.hbm.xml --> <class name="User" table="user"> <!-- ... id 和 property ... --> <!-- 一对多映射 --> <set name="addresses" table="address" cascade="save-update,delete-orphan" inverse="true"> <key column="user_id"/> <one-to-many class="com.example.entity.Address"/> </set> </class><set>: 表示这是一个 Set 集合(地址不能重复)。name="addresses":User实体中存放地址集合的属性名。cascade="save-update,delete-orphan": 级联操作,保存或更新用户时,自动保存其地址;当从用户的地址集合中移除一个地址时,自动删除该地址。inverse="true": 将关系维护权交给对方(Address),这可以避免在更新两端时生成冗余的update语句。强烈建议在“一”的一方设置inverse="true"。
第七部分:进阶特性
1 缓存机制
Hibernate 提供了两级缓存来减少数据库访问次数,提升性能。
-
一级缓存 (Session-Level Cache):
- 作用域:
Session。 - 特性:
Session一关闭,缓存就失效,它是 Hibernate 自带的,无法关闭。 - 作用:在同一个
Session内部,多次获取同一个对象,只会发一次 SQL 查询。
- 作用域:
-
二级缓存 (SessionFactory-Level Cache):
- 作用域:
SessionFactory。 - 特性:可以被所有
Session共享,生命周期与SessionFactory相同,需要额外配置和第三方缓存提供商(如 Ehcache)。 - 作用:在不同
Session之间共享数据,避免重复查询数据库。
- 作用域:
配置二级缓存(以 Ehcache 为例):
- 添加
ehcache和hibernate-ehcache依赖。 - 在
hibernate.cfg.xml中启用二级缓存。<property name="hibernate.cache.use_second_level_cache">true</property> <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property> <property name="hibernate.cache.provider_configuration_file_resource_path">ehcache.xml</property>
- 在
src/main/resources下创建ehcache.xml文件进行配置。 - 在需要缓存的实体类的映射文件中,使用
<cache/>标注。<class name="com.example.entity.User" table="user"> <cache usage="read-write"/> <!-- read-write, read-only, transactional --> <!-- ... --> </class>
2 事务与并发
- 事务边界: 一个事务应该从一个明确的
beginTransaction()开始,到commit()或rollback()结束,一个业务方法通常对应一个事务。 - 并发问题: 当多个事务同时操作同一数据时,可能产生脏读、不可重复读、幻读等问题。
- 隔离级别: 数据库通过隔离级别来控制并发,Hibernate 允许你通过配置设置隔离级别。
<property name="hibernate.connection.isolation">2</property> <!-- 1: READ_UNCOMMITTED, 2: READ_COMMITTED, 4: REPEATABLE_READ, 8: SERIALIZABLE -->
- 乐观锁: 通过在表中增加一个版本号(
version)或时间戳(timestamp)字段来实现,当更新数据时,检查版本号是否与读取时一致,如果一致才更新,否则失败。<class name="User" table="user"> <id name="id" column="id"> <generator class="native"/> </id> <version name="version" column="version"/> <!-- 乐观锁 --> <!-- ... --> </class>
总结与 Hibernate 5/6 的提示
本教程详细介绍了 Hibernate 4 的核心概念和使用方法,Hibernate 4 引入了 ServiceRegistry,使得配置更加灵活和模块化,这是与 Hibernate 3 最大的区别。
重要提示:
- Hibernate 4 已经进入维护模式,官方不再推荐在新项目中使用。
- Hibernate 5 和 Hibernate 6 是当前的主流版本,它们带来了许多重大改进:
- Hibernate 5: 引入了 JPA 2.1 支持、更好的类型系统、对 Java 8 的支持等。
- Hibernate 6: 引入了革命性的 Jakarta EE 9/10 支持(包名从
javax.persistence变为jakarta.persistence)、大幅提升性能、简化配置等。
如果你要开始一个新项目,强烈建议直接学习 Hibernate 5 或 6,本教程为你打下的坚实基础(如 ORM 思想、核心 API、关联映射、缓存、事务等)在更高版本中同样适用,只是配置方式和部分 API 可能有所不同,在 Hibernate 5+ 中,获取 SessionFactory 的方式更加简化:
// Hibernate 5+ 方式 SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); // 或者使用更现代的 StandardServiceRegistry 方式(与 Hibernate 4 类似,但包名略有变化)
希望这份教程能帮助你顺利入门 Hibernate 4!
