使用NCache实现Hibernate二级缓存

在本教程中,我们将探讨如何在Hibernate中使用NCache实现二级缓存。

我们将设置一个Java应用程序并配置NCache作为二级缓存。最后,我们将测试实现以了解缓存如何减少数据库负载并提高性能。

基础知识

在我们深入实现之前,让我们先了解Hibernate、NCache和Hibernate二级缓存的基础知识。

Hibernate

Hibernate是一个开源的对象关系映射(ORM)框架,用于Java应用程序。它通过将Java对象映射到数据库表以及反向映射来简化数据库交互。

为了提高性能,Hibernate提供了两级的缓存:

1. 一级缓存

一级缓存与Hibernate会话关联,默认启用。它存储在会话中检索的对象,并消除了多次访问数据库以获取相同对象的必要性。

一级缓存仅限于会话范围,并且不会在会话之间共享。

它也是非持久的,并在会话关闭或显式清除时清除。

2. 二级缓存

二级缓存跨会话共享,可以配置为在应用程序级别缓存数据。它通过存储对象更长时间来减少数据库的命中次数。

二级缓存需要显式配置,可以使用各种缓存提供程序,如NCache、Ehcache等实现。

NCache

NCache是为.NET和Java应用程序提供的分布式缓存解决方案。它提供了一个内存中的数据存储,可以用来缓存经常访问的数据并提高应用程序性能。

NCache支持各种缓存拓扑结构,如复制、分区化和客户端缓存。

在Hibernate中,可以使用NCache作为二级缓存来存储和检索对象,而不是访问数据库。

代码设置

首先,创建一个Java应用程序并设置Hibernate以与数据库交互。

我们将使用Maven来管理依赖关系和构建项目。应用程序将有一个实体类来定义数据和一个客户端类来与数据库交互。

首先,我们将测试没有缓存的应用程序以查看数据库交互。然后,我们将配置Hibernate中的NCache作为二级缓存来缓存实体对象并减少数据库命中次数。

依赖关系

我们将在pom.xml文件中添加Hibernate和NCache所需的相关依赖:

<dependencies> <!-- Hibernate dependencies --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>6.6.1.Final</version> </dependency> <!-- NCache dependencies --> <dependency> <groupId>com.alachisoft.ncache</groupId> <artifactId>ncache-hibernate</artifactId> <version>5.3.3</version> </dependency> </dependencies>

请注意,此处提到的版本可能基于最新发布版本有所变化。请确保为您的项目使用合适的版本。

实体类

接下来,我们将创建一个实体类来表示我们要缓存的数据。我们将定义一个简单的Customer类,包含idname字段:

@Entity @Cacheable @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, region = "CustomerRegion") public class Customer { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; // getters 和 setters }

Customer类用@Entity@Cacheable注解标记,定义为一个可缓存的实体。它有一个id字段,用@Id@GeneratedValue注解标记,以自动生成唯一标识符。

我们还使用@Cache注解来指定实体的缓存策略和区域。

NONSTRICT_READ_WRITE告诉Hibernate在数据被读取或写入时更新缓存,以实现最终的 consistency。

region属性指定了数据将被存储的缓存区域。

我们将配置NCache使用此区域来存储缓存数据。

Hibernate配置

我们需要配置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://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property> <property name="hibernate.connection.url">jdbc:oracle:thin:@localhost:1521:xe</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">password</property> <property name="hibernate.dialect">org.hibernate.dialect.Oracle12cDialect</property> <property name="hibernate.hbm2ddl.auto">update</property> <property name="hibernate.show_sql">true</property> </session-factory> </hibernate-configuration>

在此配置文件中,我们指定了数据库连接详情、方言和缓存设置。我们使用Oracle作为数据库,并配置Hibernate自动更新架构。

客户端类

我们来创建一个客户端类来与数据库交互并测试缓存机制。我们可以编写一个main类,使用Hibernate保存和检索Customer对象:

public class HibernateClient { public static void main(String[] args) { SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Customer customer = new Customer(); customer.setName("John Doe"); session.save(customer); transaction.commit(); session.close(); session = sessionFactory.openSession(); transaction = session.beginTransaction(); Customer retrievedCustomer = session.get(Customer.class, customer.getId()); System.out.println("Retrieved Customer: " + retrievedCustomer.getName()); transaction.commit(); session.close(); session = sessionFactory.openSession(); transaction = session.beginTransaction(); retrievedCustomer = session.get(Customer.class, customer.getId()); System.out.println("Retrieved Customer: " + retrievedCustomer.getName()); transaction.commit(); session.close(); } }

在这个客户端类中,我们使用Hibernate配置创建一个SessionFactory,并打开一个会话以与数据库交互。我们将Customer对象保存到数据库中,并使用id检索它。

然后,我们在两个不同的会话中两次调用retrieveCustomer方法,以查看没有缓存时的数据库交互。

我们会观察到,为了获取相同的对象,数据库被击中了两次:

正如我们所看到的,Hibernate查询被执行了两次。

设置NCache服务器

要在Hibernate中使用NCache作为二级缓存,我们需要设置一个NCache服务器并配置它以存储缓存数据。

NCache提供了一个分布式缓存解决方案,可以在Windows和Linux服务器上安装。我们将使用NCache创建一个缓存集群并配置它。一旦缓存集群设置完毕,我们就可以从我们的Java应用程序中连接到它。在Hibernate中启用NCache作为二级缓存

一旦NCache服务器设置完成,我们可以配置Hibernate以使用NCache作为二级缓存提供者。我们将更新Hibernate配置文件,并指定缓存设置以启用缓存。

启用缓存区域

让我们在hibernate.cfg.xml文件中更新缓存设置,以启用NCache作为二级缓存提供者:

<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> ... </session-factory> </hibernate-configuration>

在这里,我们将hibernate.cache.use_second_level_cache属性设置为true以启用二级缓存。我们还指定了hibernate.cache.region.factory_class属性,使用NCacheRegionFactory作为缓存提供者,它是JCacheRegionFactory的一个实现。

配置NCache属性

NCache为Hibernate提供了一套属性,用于配置缓存设置。我们可以在ncache-hibernate.xml文件中指定这些属性:

<configuration> <application-config application-id="myapp" enable-cache-exception="true" default-region-name="DefaultRegion" key-case-sensitivity="false"> <cache-regions> <region name="CustomerRegion" cache-name="demoCache" priority="AboveNormal" expiration-type="Sliding" expiration-period="8"/> <region name="DefaultRegion" cache-name="demoCache" priority="default" expiration-type="None" expiration-period="0"/> </cache-regions> <database-dependencies> <dependency entity-name="hibernator.BLL.Customer" type="oledb" sql-statement="SELECT CustomerID FROM Customers WHERE CustomerID ='?';" cache-key-format="Customers#[pk]" connection-string="Provider=SQLOLEDB;Data Source=20.200.20.40,1433;Initial Catalog=Northwind;User ID=john;Password=1234;"/> </database-dependencies> </application-config> </configuration>

在这个配置文件中,我们定义了名为CustomerRegion的缓存区域,包括缓存名称、优先级、过期类型和过期期限。我们将expiration-type设置为Sliding,过期期限为8秒。这意味着在8秒的无活动后,缓存数据将过期并被从缓存中移除。

此外,我们定义了一个DefaultRegion,用于其他没有特定缓存区域的实体的默认设置,这对于没有明确配置的实体用作回退区域。

拥有多个缓存区域允许我们根据实体的要求为不同的实体定义不同的缓存设置。

接下来,我们为Customers实体定义了一个数据库依赖。这用于保持缓存与数据库的同步,并在数据库中进行更改时更新/删除缓存数据。

我们指定了从Customers表中检索CustomerID的SQL语句以及连接到数据库的连接字符串。

缓存键格式指定了基于实体的主键如何生成缓存键。

测试

现在我们已经将NCache配置为Hibernate的二级缓存,让我们测试应用程序以查看缓存如何提高性能。我们将再次运行客户端类,并观察在启用缓存时数据库交互的情况。

当我们运行客户端类时,我们会发现第一次调用检索Customer对象时会击中数据库以获取数据。然而,第二次调用检索同一对象将从中缓存获取数据,而不是再次击中数据库。这展示了缓存如何通过从缓存中提供数据来减少数据库负载并提高性能。

使用NCache与Hibernate的好处

使用NCache作为Hibernate的二级缓存提供了许多好处:

  • 性能提升:NCache为缓存数据提供快速内存存储,减少了延迟并提高了吞吐量。它还提供异步操作,以在后台更新缓存,减少对应用程序性能的影响。
  • 可扩展性:随着应用程序的扩展,NCache可以水平扩展以处理大量数据和用户请求。它可以部署在集群中,并支持缓存复制和分区等特性来分布负载。
  • 灵活性:NCache提供各种缓存拓扑和配置以满足不同的应用程序需求。此外,由于使用了缓存区域,不同的实体可以根据需要有不同的缓存设置。这使得可以对缓存行为进行细粒度控制。
  • 同步:NCache提供数据库同步选项,以保持缓存与数据库的同步。这确保了缓存数据是最新的,并反映了在数据库中做出的最新更改。

总结

在本教程中,我们探讨了使用NCache为Java应用程序实现二级缓存的方法。

我们首先了解了Hibernate、NCache和Hibernate二级缓存的基本知识。然后,我们在Java应用程序中设置了Hibernate,并配置了NCache作为二级缓存。最后,我们测试了实现,看看缓存如何通过减少数据库访问和从缓存中提供数据来提高性能。

通过使用NCache与Hibernate,开发者可以利用分布式缓存的强大功能,提高应用程序的性能、可扩展性和可靠性。NCache提供了一个健壮的缓存解决方案,它与Hibernate和其他Java框架无缝集成,使其成为Java应用程序中缓存数据的理想选择。

Source:
https://dzone.com/articles/implement-hibernate-second-level-cache-with-ncache