在 Hibernate 中,有六个常用的核心接口,它们分别是 Configuration、SessionFactory、Session、Transaction、Query 和 Criteria。在接下来的几个小节中,将对这六个核心接口进行详细讲解。
Configuration 主要用于启动、加载和管理 Hibernate 的配置文件信息,在启动 Hibernate 的过程中,Configuration 实例首先确定 Hibernate 文件的位置,然后读取相关配置,最后创建一个唯一的 SessionFactory 实例。
Hibernate 通常使用 Configuration config=new Configuration().configure(); 的方式创建实例,此种方式默认会在 src 下读取 hibernate.cfg.xml 配置文件。如果不希望配置文件放置在 src 目录下,则可以在 configure() 方法中传入一个参数指定文件位置,其代码如下所示:
此种写法中 Hibernate 会到指定的位置查询配置文件。例如,读取 src 下 config 包中的 hibernate.cfg.xml 文件,可以将代码写成如下形式:
需要注意的是,Configuration 对象只存在于系统的初始化阶段,它将 SessionFactory 创建完成后,就完成了自己的使命。
SessionFactory 接口负责读取并解析映射文件,以及建立 Session 对象,它在 Hibernate 中起到一个缓冲区的作用,会将 Configuration 对象中的所有配置信息、Hibernate 自动生成的 SQL 语句以及某些可重复利用的数据加载到缓冲区中。同时,它还维护了 Hibernate 的二级缓存。
通常所使用的 SessionFactory 实例是通过 Configuration 对象获取的,其获取方法如下所示:
SessionFactory 具有以下特点。
由于 SessionFactory 是一个重量级的对象,占用的内存空间较大,所以通常情况下,一个应用程序只需要一个 SessionFactory 实例,只有应用中存在多个数据源时,才为每个数据源建立一个 SessionFactory 实例。为此,在实际开发时,通常会抽取出一个工具类提供 Session 对象。下面就介绍一个简单的抽取方式,如下所示。
public class HibernateUtils {
// 声明一个私有的静态final类型的Configuration对象
private static final Configuration config;
// 声明一个私有的静态的final类型的SessionFactory对象
private static final SessionFactory factory;
// 通过静态代码块构建SessionFactory
static {
config = new Configuration().configure();
factory = config.buildSessionFactory();
}
// 提供一个公有的静态方法供外部获取,并返回一个session对象
public static Session getSession() {
return factory.openSession();
}
}
上述代码中,首先声明了一个私有的静态 final 类型的 Configuration 对象和 SessionFactory 对象,供类中的其他成员使用,下面通过静态方法构建了 SessionFactory 实例,最后提供了一个公有的静态方法供外部获取 session 对象。使用此工具类,就可以直接通过 HibernateUtils.getSession() 的方式获取 session 对象。
Session 是 Java 应用程序和 Hibernate 进行交互时所使用的主要接口,是持久化操作的核心 API。它主要用于读取、创建和删除映射对象的实例,这一系列的操作将被转换为数据表中的增加、修改、查询和删除操作。
Session 是轻量级的,实例的创建和销毁不需要消耗太多的资源,同时它还是 Hibernate 的一级缓存,这个缓存主要用于存放当前工作单元加载的对象。
获取 Session 实例有两种方式,一种是通过 openSession() 方法,另一种是通过 getCurrentSession() 方法。两种方法获取 Session 的代码如下所示:
//采用openSession方法创建Session
Session session = sessionFactory.openSession();
//采用getCurrentSession()方法创建Session
Session session = sessionFactory.getCurrentSession();
以上两种获取 Session 实例的主要区别是:采用 openSession() 方法获取 Session 实例时,SessionFactory 直接创建一个新的 Session 实例,并且在使用完成后需要调用 close() 方法进行手动关闭;而 getCurrentSession() 方法创建的 Session 实例会被绑定到当前线程中,它在提交或回滚操作时会自动关闭。
在 Session 中,提供了多个持久化的操作方法,其常用方法如表 1 所示。
名称 | 描述 |
---|---|
save() | 用于执行添加对象操作 |
update() | 用于执行修改对象操作 |
saveOrUpdate() | 用于执行添加或修改对象操作 |
delete() | 用于执行删除对象操作 |
get() | 根据主键查询数据 |
load() | 根据主键查询数据 |
createQuery() | 用于数据库操作对象 |
createSQLQuery() | 用于数据库操作对象 |
createCriteria() | 面向对象的条件查询 |
需要注意的是,Session 是线程不安全的,当多个并发线程同时操作一个 Session 实例时,就可能导致 Session 数据存取的混乱(当方法内部定义和使用 Session 时,不会出现线程问题)。因此设计软件架构时,应避免多个线程共享一个 Session 实例。
Transaction 接口主要是用于管理事务,它是 Hibernate 的数据库事务接口,且对底层的事务接口进行了封装。Transaction 接口的实例对象是通过 Session 对象开启的,其开启方式如下所示:
在 Transaction 接口中,提供了事务管理的常用方法,具体如下。
当应用程序执行完持久化操作后,需要调用 commit() 方法提交事务,或者调用 rollback() 方法回滚事务(取消事务),可以通过以下代码加以理解:
try{
transaction = session.beginTransaction(); //开启事务
session.save(user); //执行操作
transaction.commit(); //提交事务
}catch(Exception e) {
transaction.rollback(); //回滚事务
}finally{
session.close(); //关闭资源
}
从上述代码中可以看出,Session 执行完保存操作后,使用了 Transaction 接口的 commit() 方法进行事务提交。只有事务执行提交后,才能真正地将数据操作同步到数据库中。在发生异常时,需要使用 rollback() 方法进行事务回滚,以避免数据发生错误。
Query 接口是 Hibernate 的查询接口,主要用于执行 Hibernate 的查询操作。Query 中包装了一个 HQL(Hibernate Query Language)查询语句,该语句采用了面向对象的查询方式,具有丰富灵活的查询特征。因此,Hibernate 官方推荐使用 HQL 语言进行查询。
了解了使用 Query 对象的步骤后,接下来通过具体示例演示 Query 对象的查询操作。
1)向 user 表中插入 4 条数据,插入数据的 SQL 语句如下所示:
INSERT INTO `hibernate`.`user` (`id`, `name`, `age`, `gender`)
VALUES
(1, 'zhangsan', '21', '男') ;
INSERT INTO `hibernate`.`user` (`id`, `name`, `age`, `gender`)
VALUES
(2, 'xiaozhang', '21', '男') ;
INSERT INTO `hibernate`.`user` (`id`, `name`, `age`, `gender`)
VALUES
(3, 'lisisi', '22', '女') ;
INSERT INTO `hibernate`.`user` (`id`, `name`, `age`, `gender`)
VALUES
(4, 'wangwu', '19', '男') ;
插入后,user 表中的数据如图 1 所示。
图 1 user表中的数据
2)在 com.mengma.test 包中创建一个名称为 QueryTest 的类,在类中添加一个名称为 testFindAll() 的方法,编辑后如下所示。
package com.mengma.test;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
import com.mengma.domain.User;
public class QueryTest {
@Test
public void testFindAll() {
Configuration config = new Configuration().configure();
SessionFactory sessionFactory = config.buildSessionFactory();
// 1.得到一个Session
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
// 2.编写 HQL,其中的User代表的是类
String hql = "from User";
// 3.创建Query查询对象
Query query = session.createQuery(hql);
// 4.使用query.list()方法查询数据,并放入list集合
List<User> list = query.list();
for (User u : list) {
System.out.println(u);
}
transaction.commit();
session.close();
sessionFactory.close();
}
}
上述代码中,按照 Query 对象的使用步骤,对 user 表的数据进行了查询。使用 Junit 运行测试方法成功后,执行结果如图 2 所示。
图 2 Query 查询输出结果
从图 2 中可以看出,user 表中的数据已经全部被查询并输出。
在 Query 接口中,除了上面代码中使用的 list() 方法以外,还包含其他一些常用方法,如表 2 所示。
名 称 | 描 述 |
---|---|
setter | Query 接口中提供了一系列的 setter 方法用于设置查询语句中的参 数,针对不同的数据类型,需要用到不同的 setter 方法 |
Iterator iterator() | 该方法用于查询语句,返回的结果是一个 Iterator 对象,在读取时只能按照顺序方式读取,它仅把使用到的数据转换成 Java 实体对象 |
Object uniqueResult() | 该方法用于返回唯一的结果,在确保只有一条记录的查询时可以 使用该方法 |
int executeUpdate() | 该方法是 Hibernate 3 的新特性,它支持 HQL 语句的更新和删除操作 |
Query setFirstResult(int firstResult) | 该方法可以设置获取第一个记录的位置,也就是它表示从第几条 记录开始查询,默认从 0 开始计算 |
Query setMaxResult(int maxResults) | 该方法用于设置结果集的最大记录数,通常与 setFirstResult() 方法结合使用,用于限制结果集的范围,以实现分页功能 |
Criteria 接口是 Hibernate 提供的一个面向对象的查询条件接口,通过它完全不需要考虑数据库底层如何实现,以及 SQL 语句如何编写。Criteria 查询又称为 QBC 查询(Query By Criteria),是 Hibernate 的另一种对象检索方式。
一个单独的查询就是 Criterion 接口的一个实例,用于限制 Criteria 对象的查询,在 Hibernate 中 Criterion 对象的创建通常是通过 Restrictions 工厂类完成的,它提供了一系列的条件查询方法,如表 3 所示。
名 称 | 描 述 |
---|---|
Criteria add(Criterion criterion) | 用于设置查询的条件,这个方法的参数为 Criterion 对象的实例 |
Criteria addOrder(Order order) | 用于设置结果集的排序规则,其参数为一个 Order 对象实例 |
Criteria createCriteria(String associationPath) | 用于创建一个新的 Criteria,这个方法用于执行符合查询时设置查询条件 |
List list() | 用于执行数据库查询,返回查询的结果 |
Criteria setFirstResult(int firstResult) | 设置获取第一个记录的位置,这个位置从 0 开始算 |
Object uniqueResult() | 这个方法用于得到唯一的结果对象实例。在确保最多只有一个 满足条件的查询结果时,可以选择适用这个方法 |
通常情况下,使用 Criteria 对象查询数据的主要步骤如下。
1)获得 Hibernate 的 Session 对象。
2)通过 Session 获得 Criteria 对象。
3)使用 Restrictions 的静态方法创建 Criterion 条件对象。Restrictions 类中提供了一系列用于设定查询条件的静态方法,这些静态方法都返回 Criterion 实例,每个 Criterion 实例代表一个查询条件。
4)向 Criteria 对象中添加 Criterion 查询条件。Criteria 的 add() 方法用于加入查询条件。
5)执行 Criteria 的 list() 或 uniqueResult() 获得结果。
了解了 Criteria 对象的使用步骤后,下面通过案例演示如何使用 Criteria 对象实现查询操作。在 hibernateDemo01 项目的 com.mengma.test 包中新建一个名称为 CriteriaTest 的类,在类中添加一个名称为 testQBC() 的方法,如下所示。
package com.mengma.test;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.Restrictions;
import org.junit.Test;
import com.mengma.domain.User;
public class CriteriaTest {
@Test
public void testQBC() {
Configuration config = new Configuration().configure();
SessionFactory sessionFactory = config.buildSessionFactory();
// 1.得到一个Session
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
// 2.通过session获得Criteria对象
Criteria criteria = session.createCriteria(User.class);
// 3.使用Restrictions的eq方法设定查询条件为name="zhangsan"
// 4.向Criteria对象中添加查询条件
criteria.add(Restrictions.eq("name", "zhangsan"));
// 5.执行Criterita的list()方法获得结果
List<User> list = criteria.list();
for (User u : list) {
System.out.println(u);
}
transaction.commit();
session.close();
sessionFactory.close();
}
}
上述代码中,按照 Criteria 对象查询数据的步骤查询了 user 表中 name 等于 zhangsan 的数据。使用 JUnit 测试运行 testQBC() 方法后,控制台的显示结果如图 3 所示。
从图 3 中可以看到,使用 Criteria 对象的查询方法,已将数据表中“name="zhangsan"”的数据查询输出。
图 3 使用Criteria条件查询