{"id":6149,"date":"2022-07-19T13:07:04","date_gmt":"2022-07-19T13:07:04","guid":{"rendered":"https:\/\/atmecs.com\/?p=6149"},"modified":"2022-08-02T10:43:11","modified_gmt":"2022-08-02T05:13:11","slug":"improve-performance-by-simple-cache-mechanism-in-springboot-application","status":"publish","type":"post","link":"https:\/\/atmecs.com\/improve-performance-by-simple-cache-mechanism-in-springboot-application\/","title":{"rendered":"Improve Performance by Simple Cache Mechanism in SpringBoot Application"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"6149\" class=\"elementor elementor-6149\" data-elementor-settings=\"{&quot;ha_cmc_init_switcher&quot;:&quot;no&quot;}\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-c20906d elementor-section-height-min-height elementor-section-boxed elementor-section-height-default elementor-section-items-middle wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no\" data-id=\"c20906d\" data-element_type=\"section\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;,&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-1d829e3\" data-id=\"1d829e3\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-edced7c elementor-widget elementor-widget-heading\" data-id=\"edced7c\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h1 class=\"elementor-heading-title elementor-size-default\">Mobile Cloud Computing \u2013 Overview, Challenges and the Future<\/h1>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-65409f4 elementor-icon-list--layout-traditional elementor-list-item-link-full_width elementor-widget elementor-widget-icon-list\" data-id=\"65409f4\" data-element_type=\"widget\" data-widget_type=\"icon-list.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<ul class=\"elementor-icon-list-items\">\n\t\t\t\t\t\t\t<li class=\"elementor-icon-list-item\">\n\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-icon\">\n\t\t\t\t\t\t\t<i aria-hidden=\"true\" class=\"fas fa-user\"><\/i>\t\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-text\">Harish Nankani<\/span>\n\t\t\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t<\/ul>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-1b7737c elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no\" data-id=\"1b7737c\" data-element_type=\"section\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;,&quot;_ha_eqh_enable&quot;:false}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-50 elementor-top-column elementor-element elementor-element-d551519\" data-id=\"d551519\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-cc97b70 elementor-widget elementor-widget-heading\" data-id=\"cc97b70\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h3 class=\"elementor-heading-title elementor-size-default\">Introduction \u2013 The Problem<\/h3>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8a179ff elementor-widget elementor-widget-text-editor\" data-id=\"8a179ff\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><br \/>For any project, there are database calls. Sometimes the database calls are done from the loops due to the requirements in responding to UI. Such loops can be repetitive, causing a performance hit by calling a database multiple times.<\/p><p>This blog can help solve this performance issue by using simple Cache implementation without using any additional libraries or frameworks.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-333bf9d elementor-widget elementor-widget-heading\" data-id=\"333bf9d\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h3 class=\"elementor-heading-title elementor-size-default\">Problem with Code<\/h3>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b21a015 elementor-widget elementor-widget-text-editor\" data-id=\"b21a015\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Consider DB calls are to find the object by Id, and if such call is made within for loop, then the code looks like this:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6f1ad74 ha-has-bg-overlay elementor-widget elementor-widget-text-editor\" data-id=\"6f1ad74\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>List productsList = productRepo.search(keyword, pageable);<br \/>ResponseDto response = new ResponseDto();<br \/>for (Product product : productsList) {<br \/>dto.setProduct(product);<br \/>Company company = companyRepo.getById(product.getCompanyID());<br \/>dto.setCompanyName(company.getName());<br \/>}<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e5108bb elementor-widget elementor-widget-text-editor\" data-id=\"e5108bb\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>This illustration code is only to understand the concept and not the real code. It shows the result in UI \u2013 for the company name of each product, the DB call is made to get the company details within the for loop. If the products are huge, it will definitely impact the performance.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ef7fdde elementor-widget elementor-widget-heading\" data-id=\"ef7fdde\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h3 class=\"elementor-heading-title elementor-size-default\">Basic Cache Implementation<\/h3>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4249bba elementor-widget elementor-widget-text-editor\" data-id=\"4249bba\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Consider a simple cache class as CacheUtil.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-486d4e4 ha-has-bg-overlay elementor-widget elementor-widget-text-editor\" data-id=\"486d4e4\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>public class CacheUtil {<br \/>private static Map&lt;String, Company&gt; companyMap = new HashMap&lt;String, Company&gt;();<br \/>public static void setCompanyMap(String id, Company company) {<br \/>this.companyMap.put(id, company);<br \/>}<br \/>public static Company getCompanyById(String id) {<br \/>this.companyMap.get(id);<br \/>}<br \/>public static void clear() {<br \/>this.companyMap.clear();<br \/>}<br \/>}<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-08ec979 elementor-widget elementor-widget-text-editor\" data-id=\"08ec979\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>The above code uses a static map to ensure that the cache is available for all requests. It provides the company object by reference id.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-44c9b81 elementor-widget elementor-widget-heading\" data-id=\"44c9b81\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h3 class=\"elementor-heading-title elementor-size-default\">How to use CacheUtil?<\/h3>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-7ffa87c elementor-widget elementor-widget-text-editor\" data-id=\"7ffa87c\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>There is a small twist in using this cache. The strategy is to make repo implementation custom.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-72964e3 ha-has-bg-overlay elementor-widget elementor-widget-text-editor\" data-id=\"72964e3\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>public interface CompanyRepoBasic extends JPARepository&lt;String, Company&gt; {<br \/>}<br \/><br \/>public interface CompanyRepoCustom {<br \/>public Company getCompanyById(String id);<br \/>}<br \/><br \/>public interface CompanyRepo extends CompanyRepoBasic, CompanyRepoCustom {<br \/>}<\/p><p>public class CompanyRepoImpl implements CompanyRepoCustom {<br \/>@Autowired<br \/>private CompanyRepoBasic companyRepoBasic;<br \/><br \/>public Company getCompanyById(String id) {<br \/>Company company = CacheUtil.getCompanyById(id);<br \/>if (company == null) {<br \/>company = companyRepoBasic.getById(id);<br \/>CacheUtil.put(id, company);<br \/>}<br \/>return company;<br \/>}<br \/>}<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e0321bf elementor-widget elementor-widget-heading\" data-id=\"e0321bf\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h3 class=\"elementor-heading-title elementor-size-default\">Final Call<\/h3>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-fe56d85 elementor-widget elementor-widget-text-editor\" data-id=\"fe56d85\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>A slight modification is to be made in the for loop to make it work. As a custom repo is created with a different method name getCompanyById, the method call companyRepo.getById used in the for loop should be changed to companyRepo.getCompanyById, and that\u2019s it.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ca68066 ha-has-bg-overlay elementor-widget elementor-widget-text-editor\" data-id=\"ca68066\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>for(Product product : productsList) {<br \/>dto.setProduct(product);<br \/>Company company = companyRepo.getCompanyById(product.getCompanyID());<br \/>dto.setCompanyName(company.getName());<br \/>}<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-a5ad0ba elementor-widget elementor-widget-heading\" data-id=\"a5ad0ba\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h3 class=\"elementor-heading-title elementor-size-default\">How it works<\/h3>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-a2797f2 elementor-widget elementor-widget-text-editor\" data-id=\"a2797f2\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>CompanyRepo implementation includes both basic repo calls and custom repo calls. getCompanyById is the custom method that checks for the company from the cache. If the cache does not include the company of such id, then it calls the DB using basic repo and puts it into the cache.<\/p><p>So considering there are 100 products of the same company, then the for loop will not hit the DB 100 times with this cache implementation. It will hit DB once and then all the other 99 times; it will get the company object from the cache.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8bd7db8 elementor-widget elementor-widget-heading\" data-id=\"8bd7db8\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h3 class=\"elementor-heading-title elementor-size-default\">Enhancements<\/h3>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b2dce83 elementor-widget elementor-widget-text-editor\" data-id=\"b2dce83\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<ul><li>\u00a0Whenever the company object is saved or updated, the cache should be updated with the latest company object. This will always provide the latest company data for any request.<\/li><li>Keep an expiry or clear the cache after some duration. Add one scheduler that runs every such configured duration to clear the cache.<\/li><li>Multiple objects can be cached, and such implementation needs the modification of the above code (example shows only the company object). Use the map of maps or different maps for different objects.<\/li><li>Make some property in application.properties or environment variables to set the number of objects that can be cached. For example, 1000 companies can be cached. If more than 1000 is being stored, keep the strategy to remove the oldest company.<\/li><\/ul>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6a192fe elementor-widget elementor-widget-heading\" data-id=\"6a192fe\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h3 class=\"elementor-heading-title elementor-size-default\">The bottom line<\/h3>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-00f152c elementor-widget elementor-widget-text-editor\" data-id=\"00f152c\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>We generally know that when it comes to offering the best experience to end-users, application performance is critical. Caching aids in this by acting as a bridge between the server and the end-user, delivering data on-demand real-time. So the more features added to the cache implementation, it becomes a custom cache library. Although caching may appear to be an afterthought in small applications, it is critical in complex ones.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t<div class=\"elementor-column elementor-col-50 elementor-top-column elementor-element elementor-element-58cfecf\" data-id=\"58cfecf\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap\">\n\t\t\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Mobile Cloud Computing \u2013 Overview, Challenges and the Future Harish Nankani Introduction \u2013 The Problem For any project, there are database calls. Sometimes the database calls are done from the loops due to the requirements in responding to UI. Such loops can be repetitive, causing a performance hit by calling a database multiple times. This blog can help solve this performance issue by using simple Cache implementation without using any additional libraries or frameworks. Problem with Code Consider DB calls are to find the object by Id, and if such call is made within for loop, then the code looks like this: List productsList = productRepo.search(keyword, pageable);ResponseDto response = new ResponseDto();for (Product product : productsList) {dto.setProduct(product);Company company = companyRepo.getById(product.getCompanyID());dto.setCompanyName(company.getName());} This illustration code is only to understand the concept and not the real code. It shows the result in UI \u2013 for the company name of each product, the DB call is made to get the company details within the for loop. If the products are huge, it will definitely impact the performance. Basic Cache Implementation Consider a simple cache class as CacheUtil. public class CacheUtil {private static Map&lt;String, Company&gt; companyMap = new HashMap&lt;String, Company&gt;();public static void setCompanyMap(String id, Company company) {this.companyMap.put(id, company);}public static Company getCompanyById(String id) {this.companyMap.get(id);}public static void clear() {this.companyMap.clear();}} The above code uses a static map to ensure that the cache is available for all requests. It provides the company object by reference id. How to use CacheUtil? There is a small twist in using this cache. The strategy is to make repo implementation custom. public interface CompanyRepoBasic extends JPARepository&lt;String, Company&gt; {} public interface CompanyRepoCustom {public Company getCompanyById(String id);} public interface CompanyRepo extends CompanyRepoBasic, CompanyRepoCustom {} public class CompanyRepoImpl implements CompanyRepoCustom {@Autowiredprivate CompanyRepoBasic companyRepoBasic; public Company getCompanyById(String id) {Company company = CacheUtil.getCompanyById(id);if (company == null) {company = companyRepoBasic.getById(id);CacheUtil.put(id, company);}return company;}} Final Call A slight modification is to be made in the for loop to make it work. As a custom repo is created with a different method name getCompanyById, the method call companyRepo.getById used in the for loop should be changed to companyRepo.getCompanyById, and that\u2019s it. for(Product product : productsList) {dto.setProduct(product);Company company = companyRepo.getCompanyById(product.getCompanyID());dto.setCompanyName(company.getName());} How it works CompanyRepo implementation includes both basic repo calls and custom repo calls. getCompanyById is the custom method that checks for the company from the cache. If the cache does not include the company of such id, then it calls the DB using basic repo and puts it into the cache. So considering there are 100 products of the same company, then the for loop will not hit the DB 100 times with this cache implementation. It will hit DB once and then all the other 99 times; it will get the company object from the cache. Enhancements \u00a0Whenever the company object is saved or updated, the cache should be updated with the latest company object. This will always provide the latest company data for any request. Keep an expiry or clear the cache after some duration. Add one scheduler that runs every such configured duration to clear the cache. Multiple objects can be cached, and such implementation needs the modification of the above code (example shows only the company object). Use the map of maps or different maps for different objects. Make some property in application.properties or environment variables to set the number of objects that can be cached. For example, 1000 companies can be cached. If more than 1000 is being stored, keep the strategy to remove the oldest company. The bottom line We generally know that when it comes to offering the best experience to end-users, application performance is critical. Caching aids in this by acting as a bridge between the server and the end-user, delivering data on-demand real-time. So the more features added to the cache implementation, it becomes a custom cache library. Although caching may appear to be an afterthought in small applications, it is critical in complex ones.<\/p>\n","protected":false},"author":1,"featured_media":6757,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"no-sidebar","site-content-layout":"page-builder","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"disabled","ast-breadcrumbs-content":"","ast-featured-img":"disabled","footer-sml-layout":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[102],"tags":[133,134,135,136,137,138],"class_list":["post-6149","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-atmecs-blog","tag-application-performance","tag-cache","tag-jpa-cache","tag-performance","tag-simple-cache","tag-spring-boot-performance"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.0 (Yoast SEO v26.0) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Improve Performance by Simple Cache Mechanism in SpringBoot Application - ATMECS<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/atmecs.com\/improve-performance-by-simple-cache-mechanism-in-springboot-application\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Improve Performance by Simple Cache Mechanism in SpringBoot Application\" \/>\n<meta property=\"og:description\" content=\"Mobile Cloud Computing \u2013 Overview, Challenges and the Future Harish Nankani Introduction \u2013 The Problem For any project, there are database calls. Sometimes the database calls are done from the loops due to the requirements in responding to UI. Such loops can be repetitive, causing a performance hit by calling a database multiple times. This blog can help solve this performance issue by using simple Cache implementation without using any additional libraries or frameworks. Problem with Code Consider DB calls are to find the object by Id, and if such call is made within for loop, then the code looks like this: List productsList = productRepo.search(keyword, pageable);ResponseDto response = new ResponseDto();for (Product product : productsList) {dto.setProduct(product);Company company = companyRepo.getById(product.getCompanyID());dto.setCompanyName(company.getName());} This illustration code is only to understand the concept and not the real code. It shows the result in UI \u2013 for the company name of each product, the DB call is made to get the company details within the for loop. If the products are huge, it will definitely impact the performance. Basic Cache Implementation Consider a simple cache class as CacheUtil. public class CacheUtil {private static Map&lt;String, Company&gt; companyMap = new HashMap&lt;String, Company&gt;();public static void setCompanyMap(String id, Company company) {this.companyMap.put(id, company);}public static Company getCompanyById(String id) {this.companyMap.get(id);}public static void clear() {this.companyMap.clear();}} The above code uses a static map to ensure that the cache is available for all requests. It provides the company object by reference id. How to use CacheUtil? There is a small twist in using this cache. The strategy is to make repo implementation custom. public interface CompanyRepoBasic extends JPARepository&lt;String, Company&gt; {} public interface CompanyRepoCustom {public Company getCompanyById(String id);} public interface CompanyRepo extends CompanyRepoBasic, CompanyRepoCustom {} public class CompanyRepoImpl implements CompanyRepoCustom {@Autowiredprivate CompanyRepoBasic companyRepoBasic; public Company getCompanyById(String id) {Company company = CacheUtil.getCompanyById(id);if (company == null) {company = companyRepoBasic.getById(id);CacheUtil.put(id, company);}return company;}} Final Call A slight modification is to be made in the for loop to make it work. As a custom repo is created with a different method name getCompanyById, the method call companyRepo.getById used in the for loop should be changed to companyRepo.getCompanyById, and that\u2019s it. for(Product product : productsList) {dto.setProduct(product);Company company = companyRepo.getCompanyById(product.getCompanyID());dto.setCompanyName(company.getName());} How it works CompanyRepo implementation includes both basic repo calls and custom repo calls. getCompanyById is the custom method that checks for the company from the cache. If the cache does not include the company of such id, then it calls the DB using basic repo and puts it into the cache. So considering there are 100 products of the same company, then the for loop will not hit the DB 100 times with this cache implementation. It will hit DB once and then all the other 99 times; it will get the company object from the cache. Enhancements \u00a0Whenever the company object is saved or updated, the cache should be updated with the latest company object. This will always provide the latest company data for any request. Keep an expiry or clear the cache after some duration. Add one scheduler that runs every such configured duration to clear the cache. Multiple objects can be cached, and such implementation needs the modification of the above code (example shows only the company object). Use the map of maps or different maps for different objects. Make some property in application.properties or environment variables to set the number of objects that can be cached. For example, 1000 companies can be cached. If more than 1000 is being stored, keep the strategy to remove the oldest company. The bottom line We generally know that when it comes to offering the best experience to end-users, application performance is critical. Caching aids in this by acting as a bridge between the server and the end-user, delivering data on-demand real-time. So the more features added to the cache implementation, it becomes a custom cache library. Although caching may appear to be an afterthought in small applications, it is critical in complex ones.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/atmecs.com\/improve-performance-by-simple-cache-mechanism-in-springboot-application\/\" \/>\n<meta property=\"og:site_name\" content=\"ATMECS\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/ATMECS\" \/>\n<meta property=\"article:published_time\" content=\"2022-07-19T13:07:04+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-08-02T05:13:11+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/atmecs.com\/wp-content\/uploads\/2022\/07\/improve-scaled-e1658313673569.jpeg\" \/>\n\t<meta property=\"og:image:width\" content=\"729\" \/>\n\t<meta property=\"og:image:height\" content=\"600\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Team Atmecs\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@atmecs\" \/>\n<meta name=\"twitter:site\" content=\"@atmecs\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Team Atmecs\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"3 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/atmecs.com\/improve-performance-by-simple-cache-mechanism-in-springboot-application\/\",\"url\":\"https:\/\/atmecs.com\/improve-performance-by-simple-cache-mechanism-in-springboot-application\/\",\"name\":\"Improve Performance by Simple Cache Mechanism in SpringBoot Application - ATMECS\",\"isPartOf\":{\"@id\":\"https:\/\/atmecs.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/atmecs.com\/improve-performance-by-simple-cache-mechanism-in-springboot-application\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/atmecs.com\/improve-performance-by-simple-cache-mechanism-in-springboot-application\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/atmecs.com\/wp-content\/uploads\/2022\/07\/improve-scaled-e1658313673569.jpeg\",\"datePublished\":\"2022-07-19T13:07:04+00:00\",\"dateModified\":\"2022-08-02T05:13:11+00:00\",\"author\":{\"@id\":\"https:\/\/atmecs.com\/#\/schema\/person\/1033d72581d5f10351657dfd8d267318\"},\"breadcrumb\":{\"@id\":\"https:\/\/atmecs.com\/improve-performance-by-simple-cache-mechanism-in-springboot-application\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/atmecs.com\/improve-performance-by-simple-cache-mechanism-in-springboot-application\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/atmecs.com\/improve-performance-by-simple-cache-mechanism-in-springboot-application\/#primaryimage\",\"url\":\"https:\/\/atmecs.com\/wp-content\/uploads\/2022\/07\/improve-scaled-e1658313673569.jpeg\",\"contentUrl\":\"https:\/\/atmecs.com\/wp-content\/uploads\/2022\/07\/improve-scaled-e1658313673569.jpeg\",\"width\":729,\"height\":600,\"caption\":\"Browser Cache Webpage Offline Memory 2d Illustration Shows Geocaching Of Computer Content And Documents\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/atmecs.com\/improve-performance-by-simple-cache-mechanism-in-springboot-application\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/atmecs.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Improve Performance by Simple Cache Mechanism in SpringBoot Application\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/atmecs.com\/#website\",\"url\":\"https:\/\/atmecs.com\/\",\"name\":\"ATMECS\",\"description\":\":: A True R&amp;D Services Company\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/atmecs.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/atmecs.com\/#\/schema\/person\/1033d72581d5f10351657dfd8d267318\",\"name\":\"Team Atmecs\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/atmecs.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/59823930fdf2c4fc577109b8c928f57ee469a527be5b3882973d26a06d497874?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/59823930fdf2c4fc577109b8c928f57ee469a527be5b3882973d26a06d497874?s=96&d=mm&r=g\",\"caption\":\"Team Atmecs\"},\"sameAs\":[\"https:\/\/atmecs.com\"],\"url\":\"https:\/\/atmecs.com\/author\/admin\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Improve Performance by Simple Cache Mechanism in SpringBoot Application - ATMECS","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/atmecs.com\/improve-performance-by-simple-cache-mechanism-in-springboot-application\/","og_locale":"en_US","og_type":"article","og_title":"Improve Performance by Simple Cache Mechanism in SpringBoot Application","og_description":"Mobile Cloud Computing \u2013 Overview, Challenges and the Future Harish Nankani Introduction \u2013 The Problem For any project, there are database calls. Sometimes the database calls are done from the loops due to the requirements in responding to UI. Such loops can be repetitive, causing a performance hit by calling a database multiple times. This blog can help solve this performance issue by using simple Cache implementation without using any additional libraries or frameworks. Problem with Code Consider DB calls are to find the object by Id, and if such call is made within for loop, then the code looks like this: List productsList = productRepo.search(keyword, pageable);ResponseDto response = new ResponseDto();for (Product product : productsList) {dto.setProduct(product);Company company = companyRepo.getById(product.getCompanyID());dto.setCompanyName(company.getName());} This illustration code is only to understand the concept and not the real code. It shows the result in UI \u2013 for the company name of each product, the DB call is made to get the company details within the for loop. If the products are huge, it will definitely impact the performance. Basic Cache Implementation Consider a simple cache class as CacheUtil. public class CacheUtil {private static Map&lt;String, Company&gt; companyMap = new HashMap&lt;String, Company&gt;();public static void setCompanyMap(String id, Company company) {this.companyMap.put(id, company);}public static Company getCompanyById(String id) {this.companyMap.get(id);}public static void clear() {this.companyMap.clear();}} The above code uses a static map to ensure that the cache is available for all requests. It provides the company object by reference id. How to use CacheUtil? There is a small twist in using this cache. The strategy is to make repo implementation custom. public interface CompanyRepoBasic extends JPARepository&lt;String, Company&gt; {} public interface CompanyRepoCustom {public Company getCompanyById(String id);} public interface CompanyRepo extends CompanyRepoBasic, CompanyRepoCustom {} public class CompanyRepoImpl implements CompanyRepoCustom {@Autowiredprivate CompanyRepoBasic companyRepoBasic; public Company getCompanyById(String id) {Company company = CacheUtil.getCompanyById(id);if (company == null) {company = companyRepoBasic.getById(id);CacheUtil.put(id, company);}return company;}} Final Call A slight modification is to be made in the for loop to make it work. As a custom repo is created with a different method name getCompanyById, the method call companyRepo.getById used in the for loop should be changed to companyRepo.getCompanyById, and that\u2019s it. for(Product product : productsList) {dto.setProduct(product);Company company = companyRepo.getCompanyById(product.getCompanyID());dto.setCompanyName(company.getName());} How it works CompanyRepo implementation includes both basic repo calls and custom repo calls. getCompanyById is the custom method that checks for the company from the cache. If the cache does not include the company of such id, then it calls the DB using basic repo and puts it into the cache. So considering there are 100 products of the same company, then the for loop will not hit the DB 100 times with this cache implementation. It will hit DB once and then all the other 99 times; it will get the company object from the cache. Enhancements \u00a0Whenever the company object is saved or updated, the cache should be updated with the latest company object. This will always provide the latest company data for any request. Keep an expiry or clear the cache after some duration. Add one scheduler that runs every such configured duration to clear the cache. Multiple objects can be cached, and such implementation needs the modification of the above code (example shows only the company object). Use the map of maps or different maps for different objects. Make some property in application.properties or environment variables to set the number of objects that can be cached. For example, 1000 companies can be cached. If more than 1000 is being stored, keep the strategy to remove the oldest company. The bottom line We generally know that when it comes to offering the best experience to end-users, application performance is critical. Caching aids in this by acting as a bridge between the server and the end-user, delivering data on-demand real-time. So the more features added to the cache implementation, it becomes a custom cache library. Although caching may appear to be an afterthought in small applications, it is critical in complex ones.","og_url":"https:\/\/atmecs.com\/improve-performance-by-simple-cache-mechanism-in-springboot-application\/","og_site_name":"ATMECS","article_publisher":"https:\/\/www.facebook.com\/ATMECS","article_published_time":"2022-07-19T13:07:04+00:00","article_modified_time":"2022-08-02T05:13:11+00:00","og_image":[{"width":729,"height":600,"url":"https:\/\/atmecs.com\/wp-content\/uploads\/2022\/07\/improve-scaled-e1658313673569.jpeg","type":"image\/jpeg"}],"author":"Team Atmecs","twitter_card":"summary_large_image","twitter_creator":"@atmecs","twitter_site":"@atmecs","twitter_misc":{"Written by":"Team Atmecs","Est. reading time":"3 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/atmecs.com\/improve-performance-by-simple-cache-mechanism-in-springboot-application\/","url":"https:\/\/atmecs.com\/improve-performance-by-simple-cache-mechanism-in-springboot-application\/","name":"Improve Performance by Simple Cache Mechanism in SpringBoot Application - ATMECS","isPartOf":{"@id":"https:\/\/atmecs.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/atmecs.com\/improve-performance-by-simple-cache-mechanism-in-springboot-application\/#primaryimage"},"image":{"@id":"https:\/\/atmecs.com\/improve-performance-by-simple-cache-mechanism-in-springboot-application\/#primaryimage"},"thumbnailUrl":"https:\/\/atmecs.com\/wp-content\/uploads\/2022\/07\/improve-scaled-e1658313673569.jpeg","datePublished":"2022-07-19T13:07:04+00:00","dateModified":"2022-08-02T05:13:11+00:00","author":{"@id":"https:\/\/atmecs.com\/#\/schema\/person\/1033d72581d5f10351657dfd8d267318"},"breadcrumb":{"@id":"https:\/\/atmecs.com\/improve-performance-by-simple-cache-mechanism-in-springboot-application\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/atmecs.com\/improve-performance-by-simple-cache-mechanism-in-springboot-application\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/atmecs.com\/improve-performance-by-simple-cache-mechanism-in-springboot-application\/#primaryimage","url":"https:\/\/atmecs.com\/wp-content\/uploads\/2022\/07\/improve-scaled-e1658313673569.jpeg","contentUrl":"https:\/\/atmecs.com\/wp-content\/uploads\/2022\/07\/improve-scaled-e1658313673569.jpeg","width":729,"height":600,"caption":"Browser Cache Webpage Offline Memory 2d Illustration Shows Geocaching Of Computer Content And Documents"},{"@type":"BreadcrumbList","@id":"https:\/\/atmecs.com\/improve-performance-by-simple-cache-mechanism-in-springboot-application\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/atmecs.com\/"},{"@type":"ListItem","position":2,"name":"Improve Performance by Simple Cache Mechanism in SpringBoot Application"}]},{"@type":"WebSite","@id":"https:\/\/atmecs.com\/#website","url":"https:\/\/atmecs.com\/","name":"ATMECS","description":":: A True R&amp;D Services Company","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/atmecs.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/atmecs.com\/#\/schema\/person\/1033d72581d5f10351657dfd8d267318","name":"Team Atmecs","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/atmecs.com\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/59823930fdf2c4fc577109b8c928f57ee469a527be5b3882973d26a06d497874?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/59823930fdf2c4fc577109b8c928f57ee469a527be5b3882973d26a06d497874?s=96&d=mm&r=g","caption":"Team Atmecs"},"sameAs":["https:\/\/atmecs.com"],"url":"https:\/\/atmecs.com\/author\/admin\/"}]}},"_links":{"self":[{"href":"https:\/\/atmecs.com\/wp-json\/wp\/v2\/posts\/6149","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/atmecs.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/atmecs.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/atmecs.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/atmecs.com\/wp-json\/wp\/v2\/comments?post=6149"}],"version-history":[{"count":0,"href":"https:\/\/atmecs.com\/wp-json\/wp\/v2\/posts\/6149\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/atmecs.com\/wp-json\/wp\/v2\/media\/6757"}],"wp:attachment":[{"href":"https:\/\/atmecs.com\/wp-json\/wp\/v2\/media?parent=6149"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/atmecs.com\/wp-json\/wp\/v2\/categories?post=6149"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/atmecs.com\/wp-json\/wp\/v2\/tags?post=6149"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}