Hibernate

Now, let's see how to implement the saveMessage() method using Hibernate. First of all, let's update the pom.xml file to add the following two required dependencies:

<dependencies>
...
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
</dependency>
</dependencies>

The spring-orm library is Spring's ORM support, based on ORM technologies such as Hibernate. And the hibernate-core library is the Hibernate ORM framework.

Now, let's provide some metadata to Hibernate so that it knows how to map a Message object to the records in the messages table. Here, we will use the JPA annotation to add these metadata to the Message class.

Here is the change to the Message class:

@Entity
@Table(name = "messages")
public class Message {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Integer id;

@Column(name = "text", nullable = false, length = 128)
private String text;

@Column(name = "created_date", nullable = false)
@Temporal(TemporalType.TIMESTAMP)
private Date createdDate;

public Message() {}
...
}

The @javax.persistence.Entity annotation is to mark the Message class as an Entity class. And the @javax.persistence.Table annotation is used to specify the messages table that the Message class is mapped to. 

And for the id field, we use the @javax.persistence.Id annotation to make it the primary key of this entity. And the @javax.persistence.GeneratedValue annotation is to specify how we want the value of id to be generated. In our case, we use the GenerationType.IDENTITY strategy, which means the database will generate the value for us. It is a perfect match for our id column's AUTO_INCREMENT setting. And the @javax.persistence.Column annotation is to map the id field to the id column of the messages table. And we specify it as not nullable.

For the text field, we map it to the text column and mark it as not nullable too, and set the column's length as 128.

For the createdDate field, we map it to the created_date column, also marking it as not nullable. And the @javax.persistence.Temporal annotation is required for annotating a field of the java.util.Date or java.util.Calendar type. Its value, TemporalType.TIMESTAMPis to map the createdDate field to a value of the java.sql.Timestamp type that the JDBC driver understands.

The default public Message(){} constructor is required by Hibernate. When Hibernate loads message records from the database and reconstitutes Message objects, it uses the default constructor to create those objects.

Hibernate won't perform a data validation based on the nullable setting and the length attribute of the @Column annotation. It uses this metadata in its hbm2ddl feature, which generates Data Definition Language (DDL) from the Hibernate mapping (hbm). You can use the DDL scripts to create/update/drop data structures in a database. The SQL provided earlier for creating the messages table is a DDL script. On the other hand, for data validation, we can use Bean Validation 2.0 (JSR 380), which we will talk about later in this book.

In Hibernate, org.hibernate.Session is the main interface for storing/retrieving entities. And you can create sessions from a Hibernate SessionFactory instance. To create an instance of SessionFactory with Spring ORM, we can use Spring's LocalSessionFactoryBean, which is Spring FactoryBeanwhich will produce an instance of SessionFactory.

Let's change the AppConfig class to define LocalSessionFactoryBean.

Here are the changes made to AppConfig:

...
@Configuration
@ComponentScan("app.messages")
public class AppConfig {

private DataSource dataSource;

public AppConfig(DataSource dataSource) {
this.dataSource = dataSource;
}
...
@Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactoryBean = new
LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource);
sessionFactoryBean.setPackagesToScan("app.messages");
return sessionFactoryBean;
}
}

The creation of LocalSessionFactoryBean requires an instance of javax.sql.DataSourcewhich we ask Spring to inject into the configuration class. And we also need to use the setPackagesToScan() method to specify the packages for Hibernate to scan in order to find entity classes.

Now, everything is ready. Let's change the MessageRepository class to implement the saving message objects with Hibernate. Here is what it looks like:

import org.hibernate.Session;
import org.hibernate.SessionFactory;
...
public class MessageRepository {
private SessionFactory sessionFactory;
public MessageRepository(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Message saveMessage(Message message) {
Session session = sessionFactory.openSession();
session.save(message);
return message;
}
}

As you can see, we ask Spring to inject an instance of SessionFactory and then, inside the saveMessage() method, we obtain an instance of Session by invoking the openSession() method of the sessionFactory instance and use the save() method of the session object to store the message object. With Hibernate, we don't have to worry about getting the generated id of the message object. Hibernate takes care of that. All we need to do now is simply return the message object after saving it.

As you can see, the Hibernate way of storing objects into a rational database is much simpler. It saves a lot of boilerplate code and helps us to focus on implementing the logic of the application itself.

Now, if you restart the application and run the test again, you can see that the messages are saved successfully.

In this section, we only introduced the basics of Hibernate. We will talk about advanced Hibernate topics when we implement our TaskAgile application.

So, among these three approaches, using JDBC API directly, using Spring JDBC, and using Hibernate—which way is better? First of all, do not use the JDBC API directly unless you really don't have a choice. Between Spring JDBC and Hibernate, the answer is that it depends. Sometimes, you might find that using Hibernate is more straightforward and quicker to get things done. Sometimes, you might find the overhead brought by Hibernate causes performance issues, so you might want to use Spring JDBC or another framework, such as MyBatis (http://www.mybatis.org), a SQL mapper framework for Java. Or, sometimes, you might end up with using both for different scenarios.

We won't cover the use of MyBatis in this book. If you're interested, you might want to check https://github.com/mybatis/spring-boot-starter, which is a Spring Boot starter module for MyBatis offered by the MyBatis team.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.128.198.59