大家好,我叫苏莱曼,在这个视频中,我们将看看如何使用 NCache 作为 Java 应用程序的 Hibernate 二级缓存。
通常情况下,情况就是这样。 NCache 它部署在企业环境中。上面是应用层,客户端应用程序将在此运行,也称为缓存客户端。然后是独立的缓存层,由缓存服务器组成,最下面是数据库层。好的,我的设置与这里的结构非常相似。
通常情况下,Hibernate 就是这样配置的。如果 Hibernate 默认配置,它总是使用一级缓存。接下来,我们将在配置中添加二级缓存。 NCache您还可以选择添加查询缓存,用于存储 Hibernate 查询结果,我们也会在本视频中介绍这一点。
所以,我也会解释一下二级缓存的好处。一级缓存只在单个会话中有效。因此,如果您打开一个新会话,一级缓存的数据就会丢失。二级缓存的好处在于,缓存数据可以在多个 Hibernate 会话之间共享,这正是我们想要实现的目标。
好的,我们来看看我的项目设置。正如你所看到的,这是一个简单的控制台应用程序。我们有一个 Hibernate 配置,我添加了客户、订单、产品和供应商这几个实体。我将这些实体添加到我的 Hibernate 配置中。我创建了一个会话工厂,然后打开了一个会话。之后会弹出一个菜单,你可以从中选择选项。你可以添加对象、获取对象,也可以打开一个新的会话。
所以接下来我们要尝试所有这些操作。你会看到这是我当前的 Hibernate 配置文件。可以看到我没有配置二级缓存,这里只有一些基本选项。
好了,现在我们开始设置。首先,你需要添加…… NCache Hibernate Maven 依赖项。如果您想知道在哪里可以找到此依赖项,可以前往…… NCache 网站。我们将进入开发者 Java 集成部分。这将引导我找到…… Maven 中央仓库 所以我知道最新的构件 ID 和版本。正如你在这里看到的,缓存版本是 Hibernate 5.3.6。所以,我只需要把它复制到我的…… pom.xml 文件中。
<dependency>
<groupId>com.alachisoft.ncache</groupId>
<artifactId>ncache-hibernate</artifactId>
<version>5.3.6</version>
</dependency>
让我们重新加载并同步 Maven 的更改。再仔细检查一下库。我已经准备好了。 NCache 客户, NCache Hibernate和Cache运行时已加载完毕,完美。
下一步是在 ncache-hibernate.xml 文件中配置缓存区域。这里需要指定缓存区域、缓存服务器以及其他配置选项。我将在 resources 目录下创建此文件。
现在,对于这个文件的 XML 布局,我将导航到…… NCache 网站上有很棒的设置指南。我直接进入文档部分,打开程序员指南,在这里找到 Hibernate 集成部分。我记得它就在这里,这里介绍如何使用 XML 映射文件进行配置。这里介绍如何为实体添加注解。下面应该还有配置缓存区域的部分。我直接把它复制到我的 XML 文件中。
<configuration>
<application-config application-id="myapp" enable-cache-exception="true" default-region-name="DefaultRegion" key-case-sensitivity="false">
<cache-regions>
<region name="default" cache-name="demoCache" priority="default" expiration-type="None" expiration-period="0"/>
</cache-regions>
</application-config>
</configuration>
我们暂时移除数据库依赖项标签,因为我们不需要它。但您可以看到这里设置了多个区域。Hibernate 允许您这样做。我们这里只使用一个区域,但这样做的目的是——我将其命名为 default。设置多个区域的目的是为了让您可以将 Hibernate 实体关联到不同的区域,并将不同的区域关联到不同的缓存服务器。最终,您将得到一个保存在完全不同的缓存中的实体。这里还有一些选项,例如项目优先级和过期类型,目前设置为“无”,但您当然也可以进行配置。
好的。我们先保持现状,继续下一步,也就是在 Hibernate 配置文件中配置 Hibernate 属性。我之前提到过,我们目前还没有配置二级缓存。我们需要复制四个属性,我这就返回到 EndCache 网站,进入“配置应用程序”页面,你会看到这些属性。现在我把它们复制到我的项目中。
<hibernate-configuration>
<session-factory>
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.region.factory_class">com.alachisoft.ncache.NCacheRegionFactory</property>
<property name="ncache.application_id">myapp</property>
<property name="hibernate.cache.use_query_cache">true</property>
</session-factory>
</hibernate-configuration>
您可以看到我们使用了二级缓存,并将其设置为 true。我们设置了 NCache 区域工厂作为区域工厂类。这对于二级缓存的设置至关重要。你可以看到这就是全部内容。 NCache 这里是代码。我们设置了应用程序 ID,在本例中是“myapp”。这个应用程序 ID 必须与 XML 文件中的应用程序配置匹配。最后,我们启用查询缓存标签。目前我将其设置为 true,但查询缓存尚未启用。我们还需要执行一个步骤才能启用它。稍后我会在视频中讲解。
现在,在我们继续之前,让我们先看一下我们的…… NCache 管理中心。您可以看到,我已经配置了一个名为 demoCache 的缓存。它目前使用单个服务器节点,当然,在您的设置中,您可以使用多个服务器。接下来,我将检查一下统计数据,确保没有数据,完美。我们初始状态为空。
最后一步是指定可缓存对象。您可以使用注解来完成此操作,也可以在 XML 映射文件中完成。但简单来说,我们只需告知 Hibernate 我们要为哪些实体启用缓存即可。
Hibernate/JPA 注解
所以,接下来我们要在实体类中添加注解。可以看到,我已经配置好了 JPA。这个实体表是 Jakarta 持久化的一部分。我在这里添加缓存注解,稍后会在幻灯片中展示。我们只需要添加这个缓存注解,并且之前也提到过缓存并发策略和区域。这就是我们需要记录的内容。
@Entity
@Table(name = "Products")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, region = "default")
public class Product implements Serializable {}
@Id
@Column(name = "ProductID")
Private Long productid;
这应该是 Hibernate 注解,我将传入缓存并发策略。在我的例子中,我将使用非严格读写策略。此外,我还将指定默认区域。这个并发策略是为了确保数据库事务和缓存之间的一致性。非严格读写策略意味着这种一致性不必在事务结束后立即执行。这是一个安全的选项,可以避免数据库锁。当然,您可以看到这里还有其他选项,例如严格读写、事务只读等等。所以,我们暂时先使用非严格读写策略。
我这就把它复制粘贴到其他实体里。好的,完美。这样我们就完成了实体的注解。
如果您想在 XML 中实现此功能,并且不想修改源代码,也可以在 XML 中指定这些内容,并达到完全相同的效果。您需要为每个实体定义一个单独的 XML 文件,并在这些文件中添加这些 XML 标签。我来快速演示一下。例如,对于订单,我会定义一个 order.hbm.xml 文件,并将 XML 布局粘贴到这里。现在我导航到…… NCache 之所以用这个网站,是因为我相信我们已经在这里配置好了 XML。它看起来是这样的。所以,它已经使用了订单对象。我就直接复制粘贴过来。
<hibernate-mapping package="com.alachisoft.ncache.sample">
<class name="Orders" table="Orders">
<cache usage="nonstrict-read-write" region="OrderRegion"/>
<id name="orderID" type="int">
<column name="OrderID"/>
<generator class="assigned"/>
</id>
<property name="orderDate" type="date">
<column name="OrderDate"/>
</property>
<property name="shippedDate" type="date">
<column name="ShippedDate"/>
</property>
<property name="shipAddress" type="string">
<column name="ShipAddress"/>
</property>
<property name="shipCountry" type="string">
<column name="ShipCountry"/>
</property>
</class>
</hibernate-mapping>
您可以看到,这里需要输入类名、并发策略选项、区域和列名,就像我们之前做的那样,只不过这次是用 XML 格式。所以,您需要对每个实体都执行此操作。最后,您需要在 Hibernate 配置文件中声明映射资源。所以,您需要在这里声明映射资源这一行。
<mapping resource="order.hbm.xml"/>
我再确认一下它的样子。是的,是 order.hbm.xml 文件。同样,你需要对每个实体文件都进行这样的操作。我现在先把它移除,并把这个文件注释掉,因为我们接下来要只使用注解。
我们应该基本就设置好了。在开始应用程序之前,我想先给你们看看我的数据库。我的所有表中都预先存在一些数据。同样,我们将使用这些数据进行一些操作。现在,我直接启动我的应用程序。
趁着加载的空档,我打算试着打开我的 NCache 统计数据并排显示。这样,我们就可以实时查看操作情况。可以看到,客户端应用程序已连接,菜单也已准备就绪。接下来,我将从数据库加载所有产品并将其保存到缓存中。保存到缓存意味着它将同时保存到一级缓存和二级缓存中。如果我点击这里的 3,可以看到返回了 32 个对象,缓存计数也增加了 32。
如果我再次以完全相同的方式获取我的产品信息,我希望是从缓存而不是数据库中获取。所以,我照做了。我获取了所有产品信息,但需要注意的是,这些数据是从一级缓存而不是二级缓存中检索的。
如果我想从二级缓存中检索数据,我会打开一个新会话,然后执行完全相同的操作。所以,如果我点击这里的 7,我也会在代码中向您展示它的样子。您可以看到这里是案例 7。它会关闭当前会话,打开一个新会话。这就是我们要做的事情。
我相信这应该会清除一级缓存中的数据。但你会注意到,我的二级缓存中仍然保留着所有数据。所以,如果我在新会话中获取所有产品,我希望数据来自二级缓存。你可以看到每秒请求数被触发了,因此,我们已经从二级缓存中检索到了数据。好了,我们已经解决了这个问题。
在 hibernate.cfg.xml 中声明此属性
<property name="hibernate.cache.use_query_cache">true</property>
在创建查询时(在 Java 中)调用 setCacheable(true) 函数
products = session.createQuery(query)
.setCacheable(true)
.getResultList();
接下来我想讲解的另一个内容是查询缓存。查询缓存的好处在于,你可以存储 Hibernate 查询的结果,以便在下次请求时更快地查找。我们已经声明了这个属性,现在只需要在 Java 代码中调用 `.setCacheable` 方法并将其设置为 `true`。我检查了一下配置文件,可以看到查询缓存已设置为 `true`。我只需要在我的 Java 代码中添加一行代码。当然,查询缓存将在我的 `get` 操作中使用,例如获取可用产品。在这里,我们创建一个会话对象查询。这是 Hibernate 会话。我只需要调用 `.getCacheable` 方法。 .setCacheable(true) 这边。这样应该就能启用查询缓存了。
所以,我打算在我所有的……中都这样做。 getOperations(), 获取供应商() 好的。这样我们就完成了,目前查询缓存已经启用。在启动应用程序之前,我想重启一下。我想清除缓存内容,以便一切从头开始。所以,在管理中心,我点击“清除演示缓存”。好的。现在点击统计信息,可以看到计数已经恢复为零。那么,现在启动应用程序吧。
应用程序似乎正在运行,客户端也已连接。当然,首先我要获取所有产品。由于我们删除了缓存中的数据,所以要从数据库加载。因此,选择选项 3:获取所有产品。不出所料,我已经检索到所有产品。共有 32 个对象,这些数据也已加载到缓存中。
你会注意到缓存计数是 33 而不是 32。所以,多出来的那项是 Hibernate 查询。现在它也被缓存了。在 SQL 中,它看起来像是 `SELECT ALL FROM products TABLE`。如果我再次获取所有产品,你可以看到,这次我希望它从缓存中获取数据。所以你可以看到每秒请求数被触发了。我们刚刚使用 Hibernate 查询从缓存中检索了数据。接下来我们要做的是按 ID 获取客户。我们点击第四个选项。它要求我输入客户 ID。所以,我们随机查找一个 ID 作为示例。我们使用 BLAUS。现在我希望检索到客户 ID,缓存该结果,然后缓存 Hibernate 查询。所以你可以看到客户已获取,客户数据已与 Hibernate 查询一起保存。所以,一切都按预期运行。
我们的演示就到这里。如果您想了解更多信息,请继续阅读。 NCache,它的 建筑, 功能如果您想了解如何将其整合到您的应用程序中,请联系我们。 安排演示非常感谢您观看本视频。