Hey guys, my name is Suleman and in this video we're going to see how you can use NCache as a hibernate level two cache for your Java application.
Now this is typically how NCache is deployed in an enterprise environment. We have the application layer above which is where our client application will run, this is also known as the cache client. Then notice a separate caching tier consisting of our cache servers and finally below we have a database layer. Okay, so my setup is very similar to this structure over here.
Now this is typically how hibernate is configured. If you have hibernate set up by default it's always going to use the level one cache. What we're going to do is, we're going to plug in a level two cache in the setup and using NCache. Optionally you can also add a query cache that is used to store your hibernate query results, and we're going to cover that in this video as well.
So, the benefit of having a level two cache, I'll explain as well. Your level one cache only persists to a single session. So, if you open a new session, your level one cache data is lost. The benefit of a level two cache is your cache data will be shared amongst multiple hibernate sessions, so that's what we're trying to achieve here.
All right, let's actually take a look at the project setup I have. So this is a simple console application as you can see here. We have a hibernate configuration and I add these entities the customer order product and supplier. I add these entities into my hibernate configuration. I build a session factory and then I open a session. Afterwards we have a menu popup and you can choose amongst these options as well. So you can you can add objects, you can get objects, and you can also open a new session.
So we're going to be experimenting with all of these operations. You'll see this is my current hibernate config file. So you can notice I do not have a level two cache, I just have the basic options over here.
So, let's move on to the setup now. The first thing you want to do is to add the NCache hibernate maven dependency. Now, if you want to know where you can find this dependency, you can go on the NCache website. We're going to go to the developers Java integration section. And this is just going to point me to the Maven central repository so I know what the latest artifact ID and version is. As you can see here, cache Hibernate 5.3.6. So, I'm just going to copy this in my pom.xml file.
<dependency>
<groupId>com.alachisoft.ncache</groupId>
<artifactId>ncache-hibernate</artifactId>
<version>5.3.6</version>
</dependency>
Let's reload and synchronize our Maven changes. Double check our libraries. I've got NCache client, NCache hibernate and cache runtime loaded, perfect.
The next step is to configure the cache regions in the ncache-hibernate.xml file. This is simply where we specify our cache regions, our cache servers and configuration options as well. I'm going to create this file under resources.
Now for the XML layout of this file, I'm going to navigate to the NCache website where we have a great guide for the setup. I'm just going to go into the doc section, open up the programmers guide, and we can look for the hibernate integration over here. I believe it's in this section over here, so this is how to configure using the XML mapping file. This is how to annotate the entities. And below we should have the configure cache regions. I'm just going to copy this in my XML file.
<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>
We are going to remove the database dependencies tag here for now because we don't need that. But you can see here there's multiple regions set up. So Hibernate allows you to do that. We're just going to stick to one region here, but the purpose of that is - I'm going to name this to default. The purpose of multiple regions is so you can associate your hibernate entities to different regions and you can associate your different regions to different cache servers. So ultimately what you end up with is an entity saved in a different cache altogether. You have options over here such as the item priority level, the expiration type it is currently set to none but of course you can configure that as well.
All right. So let's leave this as it is and move on to the next step which is to configure the hibernate properties in the hibernate config file. So I mentioned earlier we do not have level two caching setup as of now. We need to copy four properties over here and I'm just going to navigate back to the end cache website, go into configure application and you'll see these properties over here. So I'm just going to copy this into my project.
<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>
You can see we use a second level cache set that to true. We set the NCache region factory as a region factory class. So this is important for the level two cache setup. You can see this is all NCache code over here. We set up the application ID which in this case is 'myapp'. This application ID has to match the application config in your XML file here. Finally, we enable the use query cache tag. I'm going to leave this as true for now, but query caching is not enabled as of now. We need to do one more step for that. I'll cover that later in the video.
Now, before we move on, let's take a look at the at our NCache management center. So you can see here I have a cache configured already with the name of demoCache. It is using a single server node but of course in your own setup you can have multiple servers. What I'm going to do is I'm just going to check my stats and make sure there's no data, perfect. We're starting empty.
The final step for this is to specify the cacheable objects. Now you can do this using the annotations or you can do this in an XML mapping file. But quite simply, we're just going to let Hibernate know which entities we want to enable caching for.
Hibernate / JPA Annotations
So, for the annotations we're going to go into our entity classes. You can see I already have JPA set up. So these entity table this is part of the Jakarta persistence. I'm just going to add the cache annotation here, which I'll show you in the slide as well. We just need to add this cache annotation and we mentioned the cache concurrency strategy and a region as well. So this is what we need to write down.
@Entity
@Table(name = "Products")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, region = "default")
public class Product implements Serializable {}
@Id
@Column(name = "ProductID")
Private Long productid;
This should be the hibernate annotation and I'm going to pass in the cache concurrency strategy. In my case, I'm going to do non-strict read-write. And, I'm also going to give in a region of default. So this concurrency strategy, this is just to ensure consistency between your database transactions and your cache. So, non-strict specifically means that this consistency does not have to be done immediately after the transaction. It is a safe option prevents database locks. But of course, you can see there's multiple different options here, read-write which is strict, transactional read-only. So, we're going to stick to this one for now.
I'm just going to copy this and paste it into the rest of my entities. Okay, perfect. So that should be us done with annotating our entities.
If you want to do this in an XML, if you do not want to modify your source code, you can also specify these this in XML and achieve the exact same behavior. You're going to need to define a separate XML file for each of your entities and you're going to need to add these XML tags on those. So I'll just show you really quickly what it looks like. For example, in the case of orders, I would define an order.hbm.xml and I would paste the XML layout over here. So I'm just going to navigate to the NCache website because I believe we do have the XML setup here. And this is what it would look like. So, this already utilizes the order object. I'm just going to copy this as it is.
<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>
You can see here it takes in the class name. It takes in your concurrency strategy option, your region, it takes in your columns, exactly as we were doing before but just in XML. So again, you need to do this for each of your entities. And then finally, you need to declare within your hibernate config file the mapping resource. So this specific line over here, mapping resource you need to declare this as well.
<mapping resource="order.hbm.xml"/>
I'm just going to double check what it looks like. So yeah, order.hbm.xml. So again, you need to do this for each of your entity files as well. I'm going to remove this for now and comment out this file here just because we're going to stick to the annotations.
That should be us pretty much set up. Before I start the application, I want to show you my database. So, I have pre-existing data in all of my tables. Again, we're going to be playing around with these with this data. Let me just start my application at this point.
While that's loading up, I'm going to try and open my NCache statistics side by side. So, we can see the operations in real time. So, you can see here the client application has connected and our menu is ready. So, what I'm going to do is the first thing is I'm going to load in all of the products from the database and save it onto the cache. Now, saving onto the cache means it's going to be saved onto your level one cache and your level two cache. So, if I click on 3 here, you can see I get back 32 objects and the cache count over here has also increased by 32.
If I get back my products again, the exact same way, I expect to get this from the cache and not the database. So, I'm going to do that. I get back all of my products, but the important thing to note is that this data was retrieved from the level one cache, not the level two cache.
If I want to retrieve it from the level two cache, I'm going to open a new session and I'm going to do the exact same thing. So, if I click on 7 here, I'll show you in the code as well what that looks like. You can see here case number seven. It closes the current session, opens a new session. So that's what we're going to do.
I believe this should clear the data from our level one cache. But you'll notice in my level two cache, I still have all the data existing. So now if I get back all of my products in a new session, I expect for it to come from the level two cache. You can see here request per second was being triggered so, we retrieved our data from the level two cache. So, we've covered that.
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();
Let's move on to one more thing which I want to cover and that is to use query caching. So, query caching - the benefit of it is you can store the results of your hibernate queries for faster lookups upon the next request. Now we already have this property declared, we just need to add one more thing which is to call this .set cacheable method true within our Java code. So, I'm going to double check my config file and you can see I have query caching set to true. I just need to add a single line in my Java code. So, query caching of course is going to be used in your get operations in my get available products. I'm going to - you can see here we create a query within the session object. This is the hibernate session. I'm just going to call .setCacheable(true) over here. And this should enable query caching.
So, I'm going to do this in all of my getOperations(), getSuppliers() as well. Perfect. So that's us, we've enabled query caching as of now. Before I start the application, I do want to restart. I want to clear the contents of my cache just so we can start from fresh. So, on the management center I'm going to click on clear contents of demo cache. Perfect. Now when I click on stats you can see my count is back to zero. So, let's start the application now.
So, the application seems to be running and yeah, the client is now connected. So, the first thing of course I'm going to get all my products. We're going to load this from the database since we deleted the data from our cache. So, option number 3 get all products. And as expected I've retrieved all my products. There's 32 objects and that's been loaded into the cache as well.
What you'll notice is that the cache count is at 33 and not 32. So, the extra item that was added is the hibernate query. So that's been cached now as well. And, in SQL obviously what that looks like is select all from products table. And if I get all my products again, you can see here, I expect for it to get the data from the cache this time. So, you can see here request per second was being triggered. We just retrieved our data from the cache using the hibernate query. And one more thing we're going to do is I'm going to get a customer by ID. Let's click on option number four. It asked me for a customer ID. So, let's just look up a random one as example. We'll use BLAUS. And now I expect to retrieve the customer ID, cache that result, and then cache the hibernate query. So, you can see here customer fetched and the customer data was saved along with the hibernate query. So, everything is working as expected.
That's it for our demonstration. If you want to learn more about NCache, its architecture, features, and how you can incorporate it into your application, please contact us to schedule a demo. Thank you very much for watching this video.
© Copyright Alachisoft 2002 - . All rights reserved. NCache is a registered trademark of Diyatech Corp.