返回介绍

类级别的检索策略

发布于 2025-01-04 01:27:29 字数 3985 浏览 0 评论 0 收藏 0

知识点

类级别可选的检索策略包括立即检索和延迟检索, 默认为延迟检索。

  • 立即检索: 立即加载检索方法指定的对象;
  • 延迟检索: 延迟加载检索方法指定的对象。在使用具体的属性时,再进行加载。

类级别的检索策略可以通过 元素的 lazy 属性进行设置。

如果程序加载一个对象的目的是为了访问它的属性,可以采取立即检索;如果程序加载一个持久化对象的目的是仅仅为了获得它的引用,可以采用延迟检索,但 需要注意懒加载异常 (LazyInitializationException:简单理解该异常就是 Hibernate 在使用延迟加载时,并没有将数据实际查询出来,而只是得到了一个代理对象,当使用属性的时候才会去查询,而如果这个时候 session 关闭了,则会报该异常)!

下面通过一个例子来进行讲解:

Demo

在该 Demo 中,我们只需要使用一个 Customer 的对象即可,其中包含了 id,name 等属性。

延迟检索

首先我们来测试一下元素的 lazy 属性为 true 的情况,也就是默认情况(不设置)。

public class HibernateTest {

    private SessionFactory sessionFactory;
    private Session session;
    private Transaction transaction;
    @Before
    public void init() {
        Configuration configuration = new Configuration().configure();
        ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
                .applySettings(configuration.getProperties())
                .buildServiceRegistry();
        sessionFactory = configuration.buildSessionFactory(serviceRegistry);

        session = sessionFactory.openSession();
        transaction = session.beginTransaction();
    }
    @After
    public void destroy() {
        transaction.commit();
        session.close();
        sessionFactory.close();
    }
    @Test
    public void testClassLevelStrategy() {
        Customer customer = (Customer) session.load(Customer.class, 1);
        System.out.println(customer.getClass());
        System.out.println(customer.getCustomerId());
        System.out.println(customer.getCustomerName());
    }
}

看一下上面的代码,该代码是利用 Junit 进行测试(关于 Junit 的知识在这不多说,并不是重点)。其中 init 方法是对 SessionFactory、Session 等进行初始化,destroy 方法是进行关闭。

当我们运行 testClassLevelStrategy() 方法时,会得到以下输出结果:

class com.atguigu.hibernate.strategy.Customer_$$_javassist_1
1
Hibernate:
    select
        customer0_.CUSTOMER_ID as CUSTOMER1_0_0_,
        customer0_.CUSTOMER_NAME as CUSTOMER2_0_0_
    from
        CUSTOMERS customer0_
    where
        customer0_.CUSTOMER_ID=?
AA

通过控制台的输出结果,我们可以清楚的看到,当我们执行 session.load(Customer.class, 1) 方法时,Hibernate 并没有发送 SQL 语句,而只是返回了一个对象,通过调用 getClass() 方法,可以看到该对象 class com.atguigu.hibernate.strategy.Customer_$$_javassist_1 是一个代理对象,并且当调用 customer.getCustomerId() 获取 ID 的时候,也没有发送 SQL 语句;当我们这个再调用 customer.getCustomerName() 方法来得到 name 的时候,这个时候才发送了 SQL 语句进行真正的查询,并且 WHERE 条件中带上的就是 ID。

如果我们在 System.out.println(customer.getCustomerName()); 语句前插入 session.close() 将 Session 关闭,就能看到之前上文中提到的懒加载异常。

立即检索

为了让 Customer 类可以立即检索,我们要修改 Customer.hbm.xml 文件,在标签中加入 lazy="false"。

<hibernate-mapping package="com.atguigu.hibernate.strategy">

    <class name="Customer" table="CUSTOMERS" lazy="false">

        <id name="customerId" type="java.lang.Integer">
            <column name="CUSTOMER_ID" />
            <generator class="native" />
        </id>
    ...

这个时候,我们再运行之前的单元测试代码,控制台会得到以下输出结果:

Hibernate:
    select
        customer0_.CUSTOMER_ID as CUSTOMER1_0_0_,
        customer0_.CUSTOMER_NAME as CUSTOMER2_0_0_
    from
        CUSTOMERS customer0_
    where
        customer0_.CUSTOMER_ID=?
class com.atguigu.hibernate.strategy.Customer
1
AA

我们可以看到,当调用 load 方法时,会发送 SQL 语句,并且得到的不再是代理对象。这个时候就算我们在输出 name 属性之前将 session 关闭,也不会报错。

小结

上文中对 Hibernate 的类级别的检索策略进行了总结,当然这些是建立在有一定基础的前提下。 需要注意的是:

  • 无论元素的 lazy 属性是 true 还是 false,Session 的 get() 方法及 Query 的 list() 方法在类级别总是使用立即检索策略。
  • 若 元素的 lazy 属性为 true 或取默认值, Session 的 load() 方法不会执行查询数据表的 SELECT 语句,仅返回代理类对象的实例,该代理类实例有如下特征:
    • 由 Hibernate 在运行时采用 CGLIB 工具动态生成;
    • Hibernate 创建代理类实例时,仅初始化其 OID 属性;
    • 在应用程序第一次访问代理类实例的非 OID 属性时, Hibernate 会初始化代理类实例。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文