Hey everyone, my name is Suleman and today we are going to go over how you can use NCache as a hibernate level 2 cache. Please note that NCache is a popular distributed cache that supports both Java and .NET applications.
So here is how NCache is typically deployed in an enterprise environment. Notice a separate caching tier consisting of your cache servers. You have your database layer right below here and your application layer which is also known as the cache clients.
So let's dive into using NCache with hibernate. As you know hibernate is an open-source ORM framework for Java that simplifies database interactions by mapping your Java objects to your database tables. It also provides a built-in L1 cache that is always enabled and a mechanism to plugin your own L2 cache. This is where you can use NCache and plug it in as your level 2 cache for hibernate.
So, this then becomes the NCache cache cluster where you can store your entities and within that optionally you can also set a query cache where you can store the results of your hibernate queries.
So, let's actually move on to the setup. But before we cover the steps, I want to show what my current project setup looks like. I have here a Java application with the Hibernate already set up as you can see but there is no level 2 cache configured as of now. We're going to cover that step by step. I have a MySQL database connected to this as well with some pre-loaded data. And we have these four entities we're going to use Customer, Order, Product and Supplier. So, let's actually move on with the setup.
The first step is to add this NCache hibernate maven dependency. Now I'm going to navigate to the download section to actually find this dependency. I'm going to go into developers from the Alachisoft website. Going to open the Java section here and we're going to go into hibernate.
So, this is just going to point us to the Maven central repository so we know what the latest version of the dependency is. As you can see here, it's 5.3.6. I'm just going to copy this in my pom.xml file. Going to reload our dependencies and I'm just going to double check it's been loaded by clicking on external libraries. Yeah, you can see it's been loaded.
We can move on to the next step now which is to configure the cache regions in ncache-hibernate.xml. Going to just create this file really quickly under resources ncache-hibernate.xml. So, we're just going to specify our cache and our cache regions in this file here.
Let me really quickly grab the layout for this XML file. Again, I'm just going to go into the Docs section and I'm going to look for the programmer's guide and we're going to look for the Hibernate Integration. I think it's going to be in this section here. So, I'm going to look for specify cache regions. Yeah, I'm just going to copy this. I'm going to paste that over here. I'm just going to move this section over here. And we're going to be left with cache regions only. So, there's multiple cache regions as you can see here. I'm just going to leave one. But of course, hibernate allows you to set multiple cache regions. And you can point each cache region to a separate cache.
<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>
And the purpose of that is that you can point a cache. You can point your entities to different cache regions. And ultimately what you end up with is a entity saved in a different cache altogether. We're just going to use one for now. You can see there's different options here as well such as the item priority level, the expiration type, which can be sliding or absolute or none, and the expiration period. So this is in Seconds but we're just going to leave this as it is and move on.
Before we do that, I want to open my NCache management center and just check and make sure that my cache is up and running. So, it's not running as of now. I'm going to start this. So, this is deployed on a Docker instance. You can see it says Linux over here. That's because we use Linux images and our Docker file. And I have a single server node configured over here with the name of demoCache. So, the cache is up and running.
Let's move on to the next step. Configure hibernate properties in the hibernate config file. So, we already do have some of the hibernate properties, but we need to set the level 2 cache. So, for that we're going to copy four properties. I'm just going to go back to the same Docs section over here, could go into configure application and we'll find these four properties here.
<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>
So, you can see here use a second level cache set to true. The region factory class is NCacheRegionFactory. I click on this. This is all NCache code responsible for the integration. The application ID "myapp". This needs to match the application ID you set in your NCache hibernate file, see this over here. And lastly is to use query cache which I've set to true. And I'm going to leave this at true for now. But in the demonstration, I'll show how this actually works.
The last step is to specify the cacheable objects so that we actually let NCache and hibernate know which entities we want to cache. This can be done in two ways. I'm going to use the annotations approach, but you can also do the XML mapping file. We'll quickly cover this method as well, but we're going to stick to the annotations for our example.
So, we need to add these annotations into our classes. The entity table, this is JPA annotations. The cache one over here is where you actually set the level 2 cache.
@Entity
@Table(name = "Products")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, region = "default")
public class Product implements Serializable {}
@Id
@Column(name = "ProductID")
Private Long productid;
So, if I go into customer, you can see we already have our JPA annotations here. I just need to add a single annotation cache and we need to provide in a cache concurrency strategy as well which I'll explain in a second. And optionally you can also give in a region. So, like I mentioned earlier we can provide different regions here. I'm just going to give in default for now.
This concurrency strategy means if there's a non-strict read-write, so if there's a change, if there's a database transaction that change will be reflected onto the cache as well but since it's non-strict it is not done immediately. So, this is a safe option. If I click into this, you'll see there's a Read_Write which is strict. Then you have Read_Only. So, there's different options you can use. We're just going to use a this one for now.
I'm going to copy this and rest to the classes over here. And that should be us done with the annotations. Of course we need to end up doing the mapping as well. So, in the main class you can see what I'm doing the configuration object to hibernate and we add annotated class and we add all the entities here just to notify hibernate that these are our entities and that's all you need to do.
We're just going to show what you do for the XML setup as well and it's a little bit different. So, you need to create a hbm.xml file for each of your entities and then you need to add the mapping onto our configuration file. So in the case we're doing orders I'm just going to create a order.hbm.xml file under resources and we need to add our XML layout over here. We can also find this under the Docs section. If I click on this section here, you can see there's a hibernate mapping.
<hibernate-mapping package="nhibernatesample.entities.Order">
<class name="Orders" table="Orders">
<cache usage="nonstrict-read-write" region="default"/>
<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>
So, like the annotations, this gives in the table name. You give in the ID, the rows, and this is where you set the level 2 cache. And since ours are set at "default" I'm going to change this. I'm just going to fix the package as well. And everything else is pretty much the same as we did in our annotations. Of course, you want to do this for each and every one of your entities. And once we're done with that, we go into the config file and we add our mapping over here which is mapping resource. And we're going to point this to our newly created file.
<mapping resource="order.hbm.xml"/>
And that's it. We do this for each and every one of the entities, of course. And that will be our XML setup done. I'm just going to comment this out for now since we're sticking to the annotations. And we should be ready to start our application. So, I'm going to start this. And while that's happening, I'm going to open my management center. We're just going to open the statistics over here. So our cache count is currently empty. You can see. We try minimizing this. And I'm also going to minimize this just so we can see the operations in real time. Okay. So, the first thing I'm going to do is get all products. So, what I expect to happen now is that the data is loaded from the tables in our database and it is then saved into the cache. So, you can see here we load in 31 products and the count has also gone up by 31.
If I try to add a product individually, example 987, this should insert the product and also save it onto the cache as an additional item. Now, if I try to get all my products again, it should be loaded from the cache and not from the database. As you can see, the count remains the same because we loaded from the cache. Okay, so that's our demonstration done for now.
One thing I want to finally show you is how to actually use query caching. So, I'm going to stop my application and to enable query caching. There's two things we need to do. One is to declare this property in the configuration file which you'll remember we already did. And lastly we need to call the .setCacheable(true) method. This is a hibernate method. We need to call this in our Java code. That will actually enable query caching.
Declare this property in the hibernate.cfg.xml
<property name="hibernate.cache.use_query_cache">true</property>
Call the setCacheable(true) function when creating the query (in Java)
products = session.createQuery(query)
.setCacheable(true)
.getResultList();
So once this is done, let me quickly show you this first how it's done. And we're going to go back into our config file. So, this is set to true. And we're just going to go into our main application. I'm going to look for the get operations because that's where query caching will be used. I go in here, you can see we do a session.createQuery(cq). So, this is the hibernate session, just to clarify, I'm going to do a setCacheable(true) and then set this to true. Now, what this mean is the query results that we obtain will be saved onto the cache. I'm going to do this for all of the get methods. And lastly over here.
So, what I expect to see now in this example is my query being saved as a separate cache item in the cache. I'm going to start my application now. But before I do that, let me just let me just restart my cache cluster to make sure there's no data in here. So, I'm going to restart this. So, it's been emptied now. It's going to start. Okay. So, let's start the application now. Let me just open this side by side again. This time we're going to do get all products. So, what that looks like in query is select all from products table. That's the query we're going to use.
We get back 32 items and the count has also gone up here. So, you'll notice account has gone up by 33. So, the extra item that was added here was the query or more specifically the query result. And if we try to do a get customer by ID. I'm going to just really quickly grab a ID over here. Let's do cactu. So that's I expect to see this being saved into the cache along with the query result. So, you can see here this is the query select from what it looks like is select from customers where customer ID is equal to XYZ and you'll see the count has gone up by two over here.
So that is our demonstration complete. Please contact us to Schedule a Demo to learn more about NCache architecture, its features and strategy about how you can incorporate NCache into your application. Thank you for watching this video.
© Copyright Alachisoft 2002 - . All rights reserved. NCache is a registered trademark of Diyatech Corp.