首页 > Hibernate 阅读███:463

Configuration、SessionFactory、Session▓▓、Transaction、Query和Criteria:Hibernate核心接口

Hibernate 中▄■▄,有六个常用的核心接口,它们分别是 Configuration、SessionFactory■■■、Session、Transaction、Query 和 Criteria▄■▄■。在接下来的几个小节中,将对这六个核心接口进行详细讲解。

Configuration

Configuration 主要用于启动▓▄▓▄、加载和管理 Hibernate 的配置文件信息,在启动 Hibernate 的过程中,Configuration 实例首先确定 Hibernate 文件的位置▄▓,然后读取相关配置▓█▄■,最后创建一个唯一的 SessionFactory 实例。

Hibernate 通常使用 Configuration config=new Configuration().configure(); 的方式创建实例,此种方式默认会在 src 下读取 hibernate.cfg.xml 配置文件▄■▓。如果不希望配置文件放置在 src 目录下,则可以在 configure() 方法中传入一个参数指定文件位置,其代码如下所示▄▓:

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

此种写法中 Hibernate 会到指定的位置查询配置文件。例如,读取 src 下 config 包中的 hibernate.cfg.xml 文件▓█,可以将代码写成如下形式:

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

需要注意的是,Configuration 对象只存在于系统的初始化阶段█■▄,它将 SessionFactory 创建完成后,就完成了自己的使命。

SessionFactory

SessionFactory 接口负责读取并解析映射文件███,以及建立 Session 对象,它在 Hibernate 中起到一个缓冲区的作用,会将 Configuration 对象中的所有配置信息▓▓、Hibernate 自动生成的 SQL 语句以及某些可重复利用的数据加载到缓冲区中。同时,它还维护了 Hibernate 的二级缓存▄■▄。

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

SessionFactory sessionFactory = config.buildSessionFactory();

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

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 所示▄■▓。

表 1 Session中的常用方法
名称 描述
save() 用于执行添加对象操作
update() 用于执行修改对象操作
saveOrUpdate() 用于执行添加或修改对象操作
delete() 用于执行删除对象操作
get() 根据主键查询数据
load() 根据主键查询数据
createQuery() 用于数据库操作对象
createSQLQuery() 用于数据库操作对象
createCriteria() 面向对象的条件查询

需要注意的是,Session 是线程不安全的,当多个并发线程同时操作一个 Session 实例时▄▓,就可能导致 Session 数据存取的混乱(当方法内部定义和使用 Session 时,不会出现线程问题)▓█。因此设计软件架构时,应避免多个线程共享一个 Session 实例。

Transaction

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

Transaction transaction = session.beginTransaction();

在 Transaction 接口中,提供了事务管理的常用方法▓▓,具体如下。
  • commit() 方法:提交相关联的 session 实例▄■▄。
  • rollback() 方法:撤销事务操作。
  • wasCommitted() 方法■■■:检查事务是否提交。

当应用程序执行完持久化操作后,需要调用 commit() 方法提交事务▄■▄■,或者调用 rollback() 方法回滚事务(取消事务),可以通过以下代码加以理解▓▄▓▄:
try{
    transaction = session.beginTransaction();   //开启事务
    session.save(user); //执行操作
    transaction.commit();   //提交事务
}catch(Exception e) {
    transaction.rollback(); //回滚事务
}finally{
    session.close();    //关闭资源
}
从上述代码中可以看出,Session 执行完保存操作后,使用了 Transaction 接口的 commit() 方法进行事务提交▄▓。只有事务执行提交后▓█▄■,才能真正地将数据操作同步到数据库中。在发生异常时,需要使用 rollback() 方法进行事务回滚▄■▓,以避免数据发生错误。

Query

Query 接口是 Hibernate 的查询接口,主要用于执行 Hibernate 的查询操作▄▓。Query 中包装了一个 HQL(Hibernate Query Language)查询语句,该语句采用了面向对象的查询方式▓█,具有丰富灵活的查询特征。因此,Hibernate 官方推荐使用 HQL 语言进行查询█■▄。
  1. 在 Hibernate 中,使用 Query 对象的步骤如下。
  2. 获得 Hibernate Session 对象███。
  3. 编写 HQL 语句。
  4. 调用 session.createQuery 创建查询对象。
  5. 如果 HQL 语句包含参数▓▓,则调用 Query 的 setXxx 设置参数。
  6. 调用 Query 对象的 list() 或 uniqueResult() 方法执行查询。

了解了使用 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 所示▄■▄■。
user表中的数据
图 1  user表中的数据

2)在 com.mengma.test 包中创建一个名称为 QueryTest 的类,在类中添加一个名称为 testFindAll() 的方法▓▄▓▄,编辑后如下所示。
package com.mengma.test;

import 博猫娱乐场.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 所示。

Query查询输出结果
图 2  Query 查询输出结果

从图 2 中可以看出,user 表中的数据已经全部被查询并输出▄▓。

在 Query 接口中,除了上面代码中使用的 list() 方法以外,还包含其他一些常用方法▓█,如表 2 所示。

表 2 Query 的常用方法
名   称 描   述
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

Criteria 接口是 Hibernate 提供的一个面向对象的查询条件接口,通过它完全不需要考虑数据库底层如何实现■■■,以及 SQL 语句如何编写。Criteria 查询又称为 QBC 查询(Query By Criteria)▄■▄■,是 Hibernate 的另一种对象检索方式。

一个单独的查询就是 Criterion 接口的一个实例,用于限制 Criteria 对象的查询▓▄▓▄,在 Hibernate 中 Criterion 对象的创建通常是通过 Restrictions 工厂类完成的,它提供了一系列的条件查询方法,如表 3 所示▄▓。

表 3 Criteria常用查询方法
名   称 描   述
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 博猫娱乐场.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"”的数据查询输出▓█▄■。

使用Criteria条件查询
图 3  使用Criteria条件查询

Java交流群:739993120(我们会不定期在群内分享Java知识,上传Java资料▄■▓)

编程帮,一个分享编程知识的公众号。跟着站长一起学习▄▓,每天都有进步。

通俗易懂,深入浅出▓█,一篇文章只讲一个知识点。

文章不深奥,不需要钻研█■▄,在公交、在地铁、在厕所都可以阅读███,随时随地涨姿势。

文章不涉及代码,不烧脑细胞▓▓,人人都可以学习。

当你决定关注「编程帮」,你已然超越了90%的程序员▄■▄!

编程帮二维码
微信扫描二维码关注