Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Implementing DAO Pattern for our Program | Fundamentals of Hibernate
Java Data Manipulation with Hibernate

Implementing DAO Pattern for our ProgramImplementing DAO Pattern for our Program

Any theory needs to be reinforced with practice. In the previous chapter, we learned about Hibernate's workflow, life cycles, and looked at the basic code that is used almost always. In this chapter, I suggest starting to implement the interaction between the database and the code, at least with the two entity classes we currently have. We will use the DAO pattern, meaning the logic of interacting with the database will be separated from the business logic of the application.

HibernateUtil

As you may recall from the previous chapter, creating a SessionFactory object consumes a lot of resources. Therefore, we need to optimize the code so that this object is created only once during the program execution. We'll do this in the HibernateUtil.java file.

We need to ensure that an instance of the SessionFactory object is created and stored in a static constant, and not modified by other files. To do this, we will create a private method, initSessionFactory(), in this class, which will configure and build the SessionFactory object. Then, assign this object to the instance. Additionally, there should be a public static getter so that we only access this object through it.

Ultimately, this class will look like this:

This way, the SessionFactory object will be created only once, and we will use it to create different sessions for manipulating objects. Later, we'll see how to use this utility correctly.

Note

Such utilities are often used in programming to ease code writing and optimize resources. We, as future programmers, will also use them. It's a very good practice.

DAO layer

Let's start with implementing the DAO layer. Just a reminder, this is the layer where the code interacts with the database, fetching and storing data. Here, we should split the code into an interface and an implementation class. The interface will serve as a template, defining all the methods we need to implement. The implementation class will implement them.

Let's start with the Employee entity:

As you can see, we plan to implement just 2 methods for now: getById() and add(). Later, when we need other methods for the program, we can easily expand this code by adding new methods to this interface.

Next, we need to implement the implementation. It will be located in the EmployeeDaoImpl class.

Now, we need to apply the theory from the previous chapter and use it to implement these 2 methods.

First, we need to create and use an instance of the SessionFactory object. We'll do this using the HibernateUtil utility we implemented before:

Great, now, with this sessionFactory, we'll be able to open sessions in this class.

Note

Note that the variable is private, meaning it can only be used within this class. Also, this variable isn't a new SessionFactory; it's an instance of SessionFactory created in the HibernateUtil class.

Let's start implementing the add() method.

We'll follow the template from the previous chapter:

Initially, in the method, we create variables session and transaction, initializing them as null. This is done to better track the state of these variables, in case of any issues, to close the session or rollback the transaction. Then we follow the familiar algorithm:

In the catch block, we catch potential errors, and if the transaction was modified, we roll it back. Also, we throw a new exception, notifying that we cannot add a new employee.

In the finally block, we also check if the session object was modified, and then we close the session within which we are working.

Now let's move on to the implementation of the getById method, which takes an id as a parameter and returns an element from the database:

Here, the algorithm is also similar and straightforward. The difference is that we do not create a transaction object.

Note

A transaction is used when our changes affect the state of the table in the database. Most queries from the READ group do not affect the database, so we do not use a transaction object when implementing this method.

Next is the familiar algorithm. In case we catch an exception, we throw a new exception notifying the user that we failed to retrieve an employee by ID. In the finally block, we close the current session.

Note

Note that we use the same sessionFactory instance created in this file. We do not create a new instance for each method.

Service Layer

We have separated the code's interaction with the database into a separate layer. It's time to write the service layer, which will contain all the business logic of the application. At the moment, our application is very simple because we are just learning. Therefore, the service layer should mimic the methods of the DAO layer. Later, as the application develops and more complex logic is added, we will enhance the service layer.

The service layer should also have the structure of Interface - Implementation.

Let's implement the EmployeeService interface:

I don't think there's much to comment on here; we simply replicated the methods from the DAO layer in this code. Right now, these are the methods we need.

Now let's write the implementation:

We use the instance of the EmployeeDao object through composition.

  • In the add() method, we simply use a method from the DAO layer;
  • In the getById() method, we check if we managed to retrieve an employee by ID, and if so, we return that object. If not, we throw a NoSuchElementException, indicating that we couldn't retrieve an employee by ID.

At the moment, the implementation of the service layer looks simple, but let's add some additional logic to the application. For example, a method that retrieves the name of an employee by their ID. We should implement this method in the service layer because it's business logic and shouldn't directly affect the interaction with the database.

To start, let's add the method to the interface:

Now let's implement this method:

  • First, we retrieve the Employee as an object using the previously implemented getById method;
  • Then, we create a variable to store the employee's name, fetching the name using a getter;
  • Standard null check and return the employee's name from the method.

It's very important to add additional logic, specifically at the service layer. Yes, we could involve the DAO layer, but why add extra interaction with the database if we can avoid it?

Testing the Correctness of the Methods.

Now that everything is set up, we can finally use these methods.

We'll do this in the following algorithm:

  1. Instantiate the EmployeeService;
  2. Create a new employee object and initialize its fields using setters;
  3. Add the employee to the database;
  4. Retrieve the employee by ID and print it to the console;
  5. Retrieve the employee's name by ID and print it to the console.

Let's take a look at the implementation in the code:

As you can see, it's all quite straightforward. Next, all we need to do is run this code and thereby verify its functionality.

Great, we have fully implemented the database connection for one of our entities. In the next chapter, you will independently implement the same connection for the Department entity. It will be excellent practice!

1. What is the purpose of the `HibernateUtil` class in a Hibernate project?
2. In the DAO pattern, what is the primary role of the DAO interface?
3. How does the service layer interact with the DAO layer in the given implementation?

What is the purpose of the HibernateUtil class in a Hibernate project?

Виберіть правильну відповідь

In the DAO pattern, what is the primary role of the DAO interface?

Виберіть правильну відповідь

How does the service layer interact with the DAO layer in the given implementation?

Виберіть правильну відповідь

Все було зрозуміло?

Секція 2. Розділ 5
course content

Зміст курсу

Java Data Manipulation with Hibernate

Implementing DAO Pattern for our ProgramImplementing DAO Pattern for our Program

Any theory needs to be reinforced with practice. In the previous chapter, we learned about Hibernate's workflow, life cycles, and looked at the basic code that is used almost always. In this chapter, I suggest starting to implement the interaction between the database and the code, at least with the two entity classes we currently have. We will use the DAO pattern, meaning the logic of interacting with the database will be separated from the business logic of the application.

HibernateUtil

As you may recall from the previous chapter, creating a SessionFactory object consumes a lot of resources. Therefore, we need to optimize the code so that this object is created only once during the program execution. We'll do this in the HibernateUtil.java file.

We need to ensure that an instance of the SessionFactory object is created and stored in a static constant, and not modified by other files. To do this, we will create a private method, initSessionFactory(), in this class, which will configure and build the SessionFactory object. Then, assign this object to the instance. Additionally, there should be a public static getter so that we only access this object through it.

Ultimately, this class will look like this:

This way, the SessionFactory object will be created only once, and we will use it to create different sessions for manipulating objects. Later, we'll see how to use this utility correctly.

Note

Such utilities are often used in programming to ease code writing and optimize resources. We, as future programmers, will also use them. It's a very good practice.

DAO layer

Let's start with implementing the DAO layer. Just a reminder, this is the layer where the code interacts with the database, fetching and storing data. Here, we should split the code into an interface and an implementation class. The interface will serve as a template, defining all the methods we need to implement. The implementation class will implement them.

Let's start with the Employee entity:

As you can see, we plan to implement just 2 methods for now: getById() and add(). Later, when we need other methods for the program, we can easily expand this code by adding new methods to this interface.

Next, we need to implement the implementation. It will be located in the EmployeeDaoImpl class.

Now, we need to apply the theory from the previous chapter and use it to implement these 2 methods.

First, we need to create and use an instance of the SessionFactory object. We'll do this using the HibernateUtil utility we implemented before:

Great, now, with this sessionFactory, we'll be able to open sessions in this class.

Note

Note that the variable is private, meaning it can only be used within this class. Also, this variable isn't a new SessionFactory; it's an instance of SessionFactory created in the HibernateUtil class.

Let's start implementing the add() method.

We'll follow the template from the previous chapter:

Initially, in the method, we create variables session and transaction, initializing them as null. This is done to better track the state of these variables, in case of any issues, to close the session or rollback the transaction. Then we follow the familiar algorithm:

In the catch block, we catch potential errors, and if the transaction was modified, we roll it back. Also, we throw a new exception, notifying that we cannot add a new employee.

In the finally block, we also check if the session object was modified, and then we close the session within which we are working.

Now let's move on to the implementation of the getById method, which takes an id as a parameter and returns an element from the database:

Here, the algorithm is also similar and straightforward. The difference is that we do not create a transaction object.

Note

A transaction is used when our changes affect the state of the table in the database. Most queries from the READ group do not affect the database, so we do not use a transaction object when implementing this method.

Next is the familiar algorithm. In case we catch an exception, we throw a new exception notifying the user that we failed to retrieve an employee by ID. In the finally block, we close the current session.

Note

Note that we use the same sessionFactory instance created in this file. We do not create a new instance for each method.

Service Layer

We have separated the code's interaction with the database into a separate layer. It's time to write the service layer, which will contain all the business logic of the application. At the moment, our application is very simple because we are just learning. Therefore, the service layer should mimic the methods of the DAO layer. Later, as the application develops and more complex logic is added, we will enhance the service layer.

The service layer should also have the structure of Interface - Implementation.

Let's implement the EmployeeService interface:

I don't think there's much to comment on here; we simply replicated the methods from the DAO layer in this code. Right now, these are the methods we need.

Now let's write the implementation:

We use the instance of the EmployeeDao object through composition.

  • In the add() method, we simply use a method from the DAO layer;
  • In the getById() method, we check if we managed to retrieve an employee by ID, and if so, we return that object. If not, we throw a NoSuchElementException, indicating that we couldn't retrieve an employee by ID.

At the moment, the implementation of the service layer looks simple, but let's add some additional logic to the application. For example, a method that retrieves the name of an employee by their ID. We should implement this method in the service layer because it's business logic and shouldn't directly affect the interaction with the database.

To start, let's add the method to the interface:

Now let's implement this method:

  • First, we retrieve the Employee as an object using the previously implemented getById method;
  • Then, we create a variable to store the employee's name, fetching the name using a getter;
  • Standard null check and return the employee's name from the method.

It's very important to add additional logic, specifically at the service layer. Yes, we could involve the DAO layer, but why add extra interaction with the database if we can avoid it?

Testing the Correctness of the Methods.

Now that everything is set up, we can finally use these methods.

We'll do this in the following algorithm:

  1. Instantiate the EmployeeService;
  2. Create a new employee object and initialize its fields using setters;
  3. Add the employee to the database;
  4. Retrieve the employee by ID and print it to the console;
  5. Retrieve the employee's name by ID and print it to the console.

Let's take a look at the implementation in the code:

As you can see, it's all quite straightforward. Next, all we need to do is run this code and thereby verify its functionality.

Great, we have fully implemented the database connection for one of our entities. In the next chapter, you will independently implement the same connection for the Department entity. It will be excellent practice!

1. What is the purpose of the `HibernateUtil` class in a Hibernate project?
2. In the DAO pattern, what is the primary role of the DAO interface?
3. How does the service layer interact with the DAO layer in the given implementation?

What is the purpose of the HibernateUtil class in a Hibernate project?

Виберіть правильну відповідь

In the DAO pattern, what is the primary role of the DAO interface?

Виберіть правильну відповідь

How does the service layer interact with the DAO layer in the given implementation?

Виберіть правильну відповідь

Все було зрозуміло?

Секція 2. Розділ 5
some-alt