Skip to content
AL

Asmir Ljumić

2 articles

June 7, 2022

Hibernate Caching

Software Development

Hibernate Caching

Introduction to Hibernate Caching When you think about Hibernate, the first thing that comes to mind is Hibernate’s ORM which enables you to use your OOP structured classes as database entities. Furthermore, Hibernate provides a multilevel caching mechanism, which is the actual topic of this blog post.  If this blog post was a tutorial, we could name it “How to speed up your application?” Levels of cache First level cache First level cache is a session cache, which comes configured out of the box and can’t be disabled. All SQL statements must go through the first level cache. When you make multiple SQL UPDATE statements in one session, the first level cache will try to postpone making the updates in the database until you close the session or commit the transaction manually. This way cache reduces the number of SQL statements by a huge amount. Once the session is closed, all the cached data is lost and can’t be reused by other sessions. For example, after running this chunk of code: User user = entityManager .createQuery("select u from users u where u.username ='johndoe'", User.class) .getSingleResult(); user.setFirstName("John"); entityManager.persist(user); user.setLastName("Doe"); entityManager.persist(user); return user; Hibernate will combine all the changes made in this session and create only one SQL UPDATE statement when the session is closed, as shown below. Hibernate: select user0_.id as id1_0_, user0_.created_at as created_2_0_, user0_.updated_at as updated_3_0_, user0_.email as email4_0_, user0_.first_name as first_name5_0_, user0_.last_name as last_name6_0_ from users user0_ where user0_.username=? Hibernate: update users set created_at=?, updated_at=?, email=?, first_name=?, last_name=? where id=? After the session is closed, the cache is invalidated and cleared. Second level cache Since the first level cache is a session cache, its cached data can be used in that session only. If at the same time another client requires the same data, he will need to fetch the data from the database. This is where second level cache comes in handy. Second level Cache is an optional caching mechanism which allows caching objects across sessions and in order to work, some configuration is needed. Query level cache Query level cache is a key-value in memory storage which for keys uses SELECT queries and for values it uses identifiers of each row that is returned for the specified SELECT query. The main goal of this cache is not to speed up the retrieval of entities from cache but to speed up the querying time, that is why Hibernate does not cache the actual results of the query, but the indexes of rows which will be returned when the query is run.  Query level cache is especially helpful when you have some queries which take long to complete and are run often. In order for query level cache to work, queries must be identical. The slightest change of the SELECT query will result in results not found in cache and Hibernate will need to query the database for the results. For query level cache to work, slight configuration is needed. Configuration The first part of configuration is selecting a cache provider. You can choose the provider which suits your project the best from the list of six providers which Hibernate supports. We are going to use EhCache, since it meets the expectations of most applications. To configure the provider, you should add the following line to your persistence.xml. <property name="hibernate.cache.provider_class"> org.hibernate.cache.EhCacheProvider </property> After choosing the provider, we are only one step away from having a fully functional Hibernate query cache implemented. The last step is adding annotations to our entity to make it cacheable. When adding annotations to the entity, we have to specify which concurrency strategy we are going to use. Choosing the concurrency strategy depends a lot from the type of entity you are caching. Is the data going to be changed a lot and is it going to be a problem if sometimes you get stale data from the cache? If stale data is not going to be a problem, you should go with the NONSTRICT_READ_WRITE strategy, and if you can’t tolerate stale data, the best choice for you is the READ_WRITE strategy, which guarantees consistency. Annotations are added to the entity class definition, like this: package models.entities; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; import javax.persistence.Cacheable; import javax.persistence.Entity; @Entity @Cacheable @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) public class Employee extends BaseModel { private String username; private String email; private String firstName; private String lastName; } And just like that, your cache is ready.  May your queries be quick and your data safe. Good luck! "Hibernate Caching" Tech Bite was brought to you by Asmir Ljumić, Software Engineer at Atlantbh. (more…)

May 27, 2021

Builder Pattern in Java

Software Development

Builder Pattern in Java

Builder Pattern in Java Design patterns are very important in the world of software development, as they represent well proven and tested solutions for some specific problems and tasks. Builder pattern is one of the most popular and used design patterns in Java. It is used to create instances of very complex objects, for which the usage of constructors would result in very messy and difficult to maintain code.  The problem For this example we use a class named Person. This class has 2 fields and a constructor for both fields. public class Person {   private String firstName;   private String lastName;   public Person(String firstName, String lastName) {       this.firstName = firstName;       this.lastName = lastName;   }   // Getters and setters } For this example, the usage is very simple: Person person = new Person("John", "Doe"); Problems occur when our product gets a new feature which requires you to add more fields to the same class.  Now the Person class will look like this: public class Person {   private String firstName;   private String lastName;   private String nickname;   private int age;   private double height;   // other fields hidden for readability } Then you will have parts of code where you only need the first and last name, but somewhere you need the whole object, and somewhere else you will need some other fields.  There are only two ways to solve this problem using conventional methods: create multiple constructors for the same object or have one big constructor and pass null values for the fields you don’t need. If you decide to create multiple constructors, eventually you will end up having 15 constructors for the same object. This becomes an ideal environment for creating bugs when some changes happen, as you will have to make the same changes for every constructor. On the other hand, if you decide to go with passing null values to the constructor, as such: Person person = new Person("John", "Doe", null, 0, 0, 0, BodyType.FIT, null, null); Not only does this look very unaesthetic, but it’s a recipe for NullPointerExceptions, as you may want to do some calculations in the constructor (e.g. length of nickname). The solution When implementing the Builder Pattern, the constructor should be private so the object can only be created from the builder, also there should be no setter methods on the class itself, but this is not a strict rule. First, we create a nested static class Builder inside the Person class. This class will have the same fields as the original class. The next step is to create setter methods for each field in the Builder class, but instead of returning void, these setter methods will return the instance of the Builder object. The last part is the implementation of the build() method, which takes all the fields from the Builder class and uses them as parameters for the construction of the Person object. public static class Builder {       private String firstName;       private String lastName;       private String nickname;       // other fields hidden for readability       public Builder setFirstName(String firstName) {           this.firstName = firstName;           return this;       }       // other setter methods hidden for readability       public Person build() {           return new Person(firstName, lastName, nickname, age, height, weight, bodyType, gender, phoneNumber);       }   } Now the initialization of objects would be done like this: Person person1 = new Person.Builder()       .setFirstName("John")       .setLastName("Doe")       .setAge(20)       .build(); Person person2 = new Person.Builder()       .setFirstName("John")       .setLastName("Doe")       .setNickname("Johnny")       .setAge(20)       .setGender(Gender.MALE)       .setBodyType(BodyType.FIT)       .build(); Not only is the Builder Pattern the easier solution, but it also makes your code readable, more stable and easier to maintain.  "Builder Pattern in Java" Tech Bite was brought to you by Asmir Ljumić, Software Developer at Atlantbh. (more…)

Ready to Achieve More?

We’ll help you reach your goals quickly with an easy and straightforward process to kick off our collaboration. Here’s what happens next.

STEP 1

Discovery Call

Let’s chat to understand your company, project needs, and answer any questions along the way.

STEP 2

Free Consultation

Work closely with our experts to explore the right solutions for your business.

STEP 3

Collaboration Proposal

We'll recommend the best strategy for your goals, ensuring you get the most from our expertise.

STEP 4

30-Day Cancellation
Policy Contract

Spoiler: It’s Never Been Used

Enjoy peace of mind while we deliver excellence from day one—our track record speaks for itself.

Services you're interested in (Optional)