Spring Persistence with Hibernate

Hibernate and Spring are open-source Java frameworks that simplify developing Java/JEE applications from basic, stand-alone applications operating on a single JVM, to complex enterprise applications operating on full-blown application servers. Hibernate and Spring enable developers to produce scalable, reputable, and reliable code. Both frameworks support declarative setup and work with a POJO (Plain Old Java Object) programming design (discussed later in this article), minimizing the reliance of application code on the frameworks, and making development more productive and portable.

Although the objective of these frameworks partly overlap, for the most part, each is made use of for a different purpose. The Hibernate framework intends to fix the problems of handling data in Java: those issues which are not totally solved by the Java perseverance API, JDBC (Java Database Connectivity), persistence suppliers, DBMS (Database Management Systems), and their mediator language, SQL (Structured Query Language).

In contrast, Spring is a multitier framework that is not committed to a particular location of application architecture. Nevertheless, Spring does not supply its own solution for issues such as persistence, for which there are already good solutions. Rather, Spring unifies preexisting options under its constant API and makes them easier to use. As pointed out, one of these locations is determination. Spring can be incorporated with a persistence solution, such as Hibernate, to provide an abstraction layer over the persistence technology, and produce more portable, manageable, and effective code.

In addition, Spring provides other services spread over the application architecture, such as inversion of control and aspect-oriented programming (described later in this post), decoupling the application’s parts, and modularizing common behaviors.

This short article takes a look at the inspiration and objectives for Hibernate and Spring. The post begins with an explanation of why Hibernate is needed, where it can be used, and what it can do. We’ll take a peek at Hibernates alternatives, exploring their advantages and drawbacks. I’ll outline the valuable functions that Hibernate offers and describe how it can resolve the problems of the standard technique to Java persistence. The conversation continues with Spring. I’ll describe what Spring is, what services it offers, and how it can assist to develop a top quality data-access layer with Hibernate.

Persistence management in Java

Determination has long been a challenge in the enterprise community. Lots of determination solutions from primitive, file-based techniques, to contemporary, object-oriented databases have existed. For any of these approaches, the goal is to provide reliable, effective, flexible, and scalable determination.

Among these contending options, relational databases (because of certain benefits) have actually been most extensively allowed in the IT world. Today, almost all enterprise applications use relational databases. A relational database is an application that provides the perseverance service. It provides numerous persistence features, such as indexing data to supply rapid searches; solves the relevant issues, such as securing data from unauthorized access; and handles many problems, such as protecting relationships among data. Producing, customizing, and accessing relational databases is fairly basic. All such databases present data in two-dimensional tables and support SQL, which is fairly simple to learn and understand. Furthermore, they provide other services, such as transactions and replication. These advantages suffice to guarantee the appeal of relational databases.

To supply support for relational databases in Java, the JDBC API was developed. JDBC allows Java applications to link to relational databases, reveal their perseverance purpose as SQL expressions, and send data to and from databases. The following screenshot demonstrates how this works:

Using this API, SQL statements can be passed to the database, and the outcomes can be returned to the application, all through a motorist.

The mismatch problem

JDBC manages lots of perseverance problems and problems in interacting with relational databases. It also provides the required capability for this purpose. However, there continues to be an unsolved problem in Java applications: Java applications are basically object-oriented programs, whereas relational databases store data in a relational form. While applications use object-oriented kinds of data, databases represent data in two-dimensional table forms. This scenario causes the so-called object-relational paradigm mismatch, which (as we will see later) triggers many issues in communication in between object-oriented and relational environments.

For many reasons, consisting of ease of understanding, simplicity of use, efficiency, robustness, and even popularity, we may not discard relational databases. Nevertheless, the mismatch can not be eliminated in an uncomplicated and uncomplicated manner.

Identity and equality mismatch

The very first and most substantial mismatch includes the ideas of data equality. Java provides two meanings for object identity and equality. According to Java, two items are called identical when they indicate the very same reference in memory. In contrast, 2 things are considered equal when they contain comparable data, as determined by the developer, despite the memory areas to which the objects point.

Java offers the equates to() technique and == operator to support equality and identity, respectively. For instance, the == operator can be used as follows to check whether object1 and object2 equal: object1==object2
The equals() approach, made use of as follows, figures out whether two things are equivalent: object1.equals(object2).
When 2 things equal, they refer to the very same memory location. Therefore, they have the very same value and are definitely equal. However, 2 items that are equivalent might not equal given that they might point to various locations in memory.

The hashCode() method have to be overridden in every class which overrides the equals() method. The hashCode() method returns an integer as the hash code value for the object on which this method is conjured up. This code is supported for the advantage of hashing based collection classes such as Hashtable, HashMap, HashSet, and so on. Equal things have to produce the very same hash code, as long as they are equivalent. Nevertheless, unequal objects do not need to produce distinct hash codes. See the JDK documentation for more information.

While Java provides 2 distinct definitions for object identity and equality, databases do not have any corresponding definitions for these terms. In a database, the data is represented as table rows, and each table row is identified based upon the content it holds. A significant mismatch takes place when we map from the object-oriented world to the relational world. Although two things are not identical since they describe various areas in memory, in the database, they might be considered similar since they hold the very same content.

The common method to eliminating this mismatch is to use an additional field in the object’s class, and an extra identifier column in the particular table of the object. This method determines objects based on the identifier values they keep in either object or relational type, instead of recognizing them based upon their references in memory (in the object-oriented world) and based upon the content they hold (and in the relational world).

Let’s take a look at an easy example. Suppose that our application has a Student class. We might usually use a STUDENT table in the database to store Student things. We might also use an extra field in the class, called an object identifier, and a matching column in the table, called main secret, to allow objects to be recognized when they are kept, recovered, or upgraded.

As you can see, to store a Student object, we have to obtain a PreparedStatement object with an appropriate SQL query. We then need to put the buildings of the Student object in the PreparedStatement, and lastly carry out the upgrade query by calling the executeUpdate() method of PreparedStatement. With all of these, we need to handle exceptions when there is any issue in interacting to the database or carrying out the query.

To load an object from the database, we need to get a PreparedStatment with an appropriate SQL query, set the required values, perform the query, repeat over the outcome, and produce the Student object. We need to also handle the exceptions correspondingly.

The most difficult and important parts of the above codes are the SQL statements. These statements are revealed in a various language than the language that object-oriented languages such as Java use. Besides, their syntax cannot be checked in the put together time considering that they are expressed in the raw String.

As it can be concluded from both the previous examples, transforming the object-oriented and relational forms of data to one another can not be achieved in a simple and easy and straightforward way. After all, any modification in the object design or the database schema can influence the transforming code.

This example shows a main trouble in mapping goal and relational types of data. Nevertheless, this basic case needs just very little effort to map a common entity object. The mapping of items might quickly be more complex than in the example, particularly when an entity object is inherited from or related to another object.

Mapping object inheritance mismatch

Another point where a mismatch occurs remains in the mapping of object inheritance. While Java lets an object be acquired by another object, relational databases do not support the idea of inheritance. This means we need to define our own strategy to translate class hierarchy to database schema.

Let’s elaborate inheritance by extending our simple example using a general class, Person, as a superclass of Student. The class diagram shown in the following screenshot reveals the Student class, which is now a subclass of Person:.

The concern right here is, how can the object inheritance be continued? Can it be continued one table? If not, how should we establish the relationship in between tables?

One solution would be to use individual tables for individual classes in the hierarchy. According to this solution, the items of type superclass are saved directly in the superclass’s table, but the subclass items are continued both superclass and subclass tables. If we chose this strategy for our example, we would have two tables, PERSON and STUDENT, as displayed in the following figure:.

Since items of the subclass are spread over 2 tables, we need a mechanism to recognize the association between rows when an object is recovered, upgraded, or gotten rid of. Luckily, many databases support foreign secrets which are used to develop a relationship in between database tables. This is what I have actually utilized in our example. As you can see, the STUDENT table takes the ID column as its primary vital and a foreign vital onto the PERSON table, suggesting it holds the identifier of the associated row in the STUDENT table. When a Student object is saved, upgraded, or eliminated, the appropriate student’s data need to be placed in, updated in, or eliminated from the two tables.

As you can see, using SQL joins makes the query expressions more complex, and as a result harder to develop, test, and preserve.

Mapping more complex items

Many Java things are associated with other things. The associated things may be values or entities. Entities are items that have their own consistent identity and are stored as discussed previously. On the other hand, values are items that do not specify some kind of persistent identity. If an entity object is connected with a value object, no actual problem arises because the value object can be stored with the entity object in the very same table. Nevertheless, this is not real in the case of associations between 2 entity things. Unfortunately, databases do not offer a method to continue object associations by default.

The next mismatch occurs when a graph of entity items should be continued the database. In this case, the persistence should be accomplished in such a way that enables the object graph to be recovered to its original form at a later time. As a common strategy, for each entity class a database table is utilized and when an object is saved, each object is persisted in its own database table. The next concern right here is, how can object associations be continued? Similar to inheritance, international keys can be brought to develop inter-table relationships and supply table associations.

When we work with Hibernate, we constantly use basic classes which do not have any special habits. It is suggested that these classes be revealed with private properties and with setter and getter techniques to access the properties.

Note that, we have actually developed our classes as simple to be as possible to keep our example simple, also. In this case, the COURSE table requires a foreign key column referring to the associated row in the STUDENT table. This sort of relationship indicates that when a Student object is persisted, the associated Course things must be continued also. Nevertheless, we might use a different strategy for upgrading or removing associated things when the object is updated or gotten rid of. For example, we may choose that the associated things are not to be updated when the object is updated, but they need to be erased from the database when the object is gotten rid of. This is what we call a waterfall operation, suggesting whether the operation, or operations, should be propagated to associated entities.

To pack an entity object, we need to query the suitable table and other related to it. It is really challenging, tiresome, and mistake vulnerable to use only pure JDBC and SQL to store the object graph in multiple tables, restore the object-oriented kind of data, search object associations, and deal with object inheritance. The SQL statements you use may not be optimized, and might be extremely challenging to test and preserve.

This is the main reason to use a determination framework such as Hibernate.

Source:  Spring Persistence with Hibernate

Post a comment