JavaRush /Java Blog /Random EN /Your first Hibernate application

Your first Hibernate application

Published in the Random EN group
In this article, you will be introduced to one of the most popular enterprise frameworks for Java and build your first Hibernate application. Never heard of Hibernate? Maybe you've heard of it but haven't used it? Or tried to start, but failed? In all three cases - welcome under the cut :) Your first Hibernate application - 1Hello everyone! In this article, I'll cover the main features of the Hibernate framework and help you write your first mini-application. For this we need:
  1. Intellij Idea Ultimate Edition;
    Download from the official site and activate the 30-day trial version.
  2. PostgeSQL is one of the most popular modern database management systems (DBMS);
  3. Maven (already wired into IDEA);
  4. A little patience.
The article is aimed primarily at those who have never worked with this technology, so the amount of code has been reduced as much as possible. Let's get started!

What is Hibernate?

This is one of the most popular ORM implementations. The object-relational model describes the relationship between software objects and database records. Of course, the functionality of Hibernate is very wide, but we will focus on the simplest functions. Our goal is to create a CRUD application (Create,Read,Update,Delete) that will be able to:
  1. Create users (User), as well as search for them in the database by ID, update their data in the database, and delete them from the database.
  2. Assign vehicle objects to users (Auto). Create, edit, find and delete vehicles from the database.
  3. In addition, the application should automatically remove "ownerless" cars from the database. Those. when deleting a user, all cars belonging to him must also be deleted from the database.
The structure of our project will be as follows: Your first Hibernate application - 2As you can see, nothing complicated. 6 classes + 1 config file. First, let's create a new maven project in Intellij Idea. File -> New Project. From the proposed project types, choose Maven and move on. Your first Hibernate application - 3Apache Maven is a framework for automating the assembly of projects based on the description of their structure in files in the POM language. The entire structure of your project will be described in the pom.xml file, which IDEA itself will create at the root of your project. In the project settings, you will need to specify the Maven parameters - groupId and artifactId. Usually in projects, groupId is the name of an organization or department; the domain name of the organization or project site is written there. In turn, artifactId is the name of the project. For groupdId you can specifycom.вашНикнейм.codegym, it will not affect the operation of the application in any way. For artifactId, choose any project name you like. Version can also be left unchanged. Your first Hibernate application - 4On the last screen, simply confirm the previously entered data. Your first Hibernate application - 5So, we have created the project, there is nothing left to do - write the code and make it work :) First of all, if we want to create an application that works with a database - we definitely cannot do without a database! Download PostgreSQL from here(I'm using version 9). PostgreSQL has a default user 'postgres', which you will need to create a password during installation. Don't forget the password, we'll need it later! (In general, using the default database in applications is a bad practice, but in order to reduce the amount of hemorrhoids with the creation of our own database, we will get by with it). If you are not friends with the command line and SQL queries, there is good news. Intellij IDEA provides a very good user interface for working with the database. It looks like this:Your first Hibernate application - 6(located on the right sidebar of IDEA, Database tab) To create a connection, click "+", select our provider (PostgeSQL). Fill in the fields with the user, the name of the database (both are postgres) and enter the password that was set during the installation of PostgreSQL. If necessary, download the Postgres driver, this can be done on the same page. Click "Test Connection" to check that the database connection is established. If you see the inscription "Successful" - we go further. Now let's create the tables we need. There will be two of them - users and autos. Parameters for the users table: Your first Hibernate application - 7Note that id is the Primary Key. If you don’t know what a primary key is in SQL - Google, this is important. Setting for autos table: Your first Hibernate application - 8For autos, you need to configure Foreign Key - a foreign key. It will link our tables. I advise you to read more about it; to put it quite simply - it refers to an external table, in our case to users. If the car belongs to a user with id=1, then it will have 1 in the user_id field of the autos table. This is how we associate users with their cars in our application. In our autos table, the user_id field will play the role of a foreign key. It will refer to the id field of the users table. Your first Hibernate application - 9Thus, we have created a database with two tables. It remains to understand how to manage it from Java code. We will start with the pom.xml file, in which we need to include the necessary libraries (in the Maven language they are called dependencies - "dependencies"). All libraries are stored in the central Maven repository. Those that you specify in pom.xml, you can use in the project. Your pom.xml should look like this: Your first Hibernate application - 10Nothing complicated, as you can see. We have added only 2 dependencies - for using PostgreSQL and Hibernate. Now let's move on to the Java code. Create all the required packages and classes for the project. First, we need data models - classes Userand Auto.
package models;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
@Table (name = "users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    @Column(name = "name")
    private String name;
    //you can not specify Column name if it matches the name of the column in the table
    private int age;

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Auto> autos;

    public User() {
    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
        autos = new ArrayList<>();
    }

    public void addAuto(Auto auto) {
        auto.setUser(this);
        autos.add(auto);
    }

    public void removeAuto(Auto auto) {
        autos.remove(auto);
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public List<Auto> getAutos() {
        return autos;
    }

    public void setAutos(List<Auto> autos) {
        this.autos = autos;
    }

    @Override
    public String toString() {
        return "models.User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
package models;

import javax.persistence.*;

@Entity
@Table(name = "autos")
public class Auto {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @Column (name = "model")
    private String model;

    //you can not specify Column name if it matches the name of the column in the table
    private String color;


    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;

    public Auto() {
    }

    public Auto(String model, String color) {
        this.model = model;
        this.color = color;
    }

    public int getId() {
        return id;
    }

    public String getModel() {
        return model;
    }

    public void setModel(String model) {
        this.model = model;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Override
    public String toString() {
        return color + " " + model;
    }
}
As you can see, the classes are equipped with a bunch of as yet incomprehensible annotations. Let's start dealing with them. The main annotation for us is @Entity (entity). Read about it on Wikipedia and remember everything, this is the basis of the basics. This annotation allows the Java objects of your class to be associated with the database. For a class to be an entity, it must meet the following requirements:
  • Must have an empty constructor ( publicor protected);
  • Cannot be nested, interface or enum;
  • It cannot finaland cannot contain final-fields/properties;
  • Must contain at least one @Id field.
Check your entity classes, these points are a very popular place to shoot yourself in the foot. It's very easy to forget something. In this case, the entity can:
  • Contain non-empty constructors;
  • To be inherited and to be inherited;
  • Contain other methods and implement interfaces.
As you can see, the class Useris a lot like the users table. There idare fieldsnameage. The annotations above them do not need much explanation: it is clear that @Id is an indication that the field is an identifier for objects of this class. The @Table annotation above the class specifies the name of the table in which the objects are written. Pay attention to the comment above the age field: if the field name in the class and table is the same, you can not add the @Column annotation, it will work like that. Regarding the "strategy = GenerationType.IDENTITY" in brackets: there are several ID generation strategies. You can google, but within the framework of our application, you don’t have to bother. The main thing is that the id for our objects will be generated automatically, so there is no setter for id, and we do not set it in the constructor either. However, something classUserstill stands out. He has a list of cars! The @OneToMany annotation hangs above the list. It means that several machines can correspond to one object of the user class. The "mappedBY" setting points to the user field of the class Auto. Thus, machines and users are connected to each other. The orphanRemoval setting translates quite well from English - "remove orphans". If we delete a user from the database, all cars associated with him will also be deleted. In turn in classAutoyou will see a user field with @ManyToOne annotation (many Autos can match one User) and @JoinColumn annotation. It indicates through which column in the autos table there is a connection with the users table (the same foreign key that we talked about earlier). After creating the data model, it's time to teach our program to perform database operations with this data. Let's start with the HibernateSessionFactoryUtil utility class. It has only one task - to create a session factory for our application to work with the database (hello, the "Factory!" pattern). He can't do anything else.
package utils;

import models.Auto;
import models.User;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;

public class HibernateSessionFactoryUtil {
    private static SessionFactory sessionFactory;

    private HibernateSessionFactoryUtil() {}

    public static SessionFactory getSessionFactory() {
        if (sessionFactory == null) {
            try {
                Configuration configuration = new Configuration().configure();
                configuration.addAnnotatedClass(User.class);
                configuration.addAnnotatedClass(Auto.class);
                StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties());
                sessionFactory = configuration.buildSessionFactory(builder.build());

            } catch (Exception e) {
                System.out.println("Exception!" + e);
            }
        }
        return sessionFactory;
    }
}
In this class, we create a new configuration object Configuration, and pass it the classes that it should perceive as entities - Userand Auto. Pay attention to the method configuration.getProperties(). What other properties? Where? Properties are parameters for hibernate operation, specified in a special hibernate.cfg.xml file. Your first Hibernate application - 11Hibernate.cfg.xml is read here: new Configuration().configure(); As you can see, there is nothing special in it - database connection parameters, and a special show_sql parameter. It is needed so that all sql queries that hibernate will execute against our database are displayed in the console. This way you will see exactly what Hibernate is doing at any given time and get rid of the "magic" effect. Next we need a classUserDAO. (In a good way, you need to program through interfaces - create an interface UserDAOand separately implement it UserDAOImpl, but to reduce the amount of code, I will omit this. Do not do this in real projects!). DAO (data access object) is one of the most common design patterns, "Data Access". Its meaning is simple - to create a layer in the application that is responsible only for accessing data, and nothing else. Get the data from the database, update the data, delete the data - and that's it. Read more about DAO, you will use them all the time in your work. What can our class do UserDao? Actually, like all DAOs, it only knows how to work with data. Finding a user by id, updating his data, deleting him, pulling out a list of all users from the database or saving a new user to the database - that's all its functionality.
package dao;

import models.Auto;
import models.User;
import org.hibernate.Session;
import org.hibernate.Transaction;
import utils.HibernateSessionFactoryUtil;
import java.util.List;

public class UserDao {

    public User findById(int id) {
        return HibernateSessionFactoryUtil.getSessionFactory().openSession().get(User.class, id);
    }

    public void save(User user) {
        Session session = HibernateSessionFactoryUtil.getSessionFactory().openSession();
        Transaction tx1 = session.beginTransaction();
        session.save(user);
        tx1.commit();
        session.close();
    }

    public void update(User user) {
        Session session = HibernateSessionFactoryUtil.getSessionFactory().openSession();
        Transaction tx1 = session.beginTransaction();
        session.update(user);
        tx1.commit();
        session.close();
    }

    public void delete(User user) {
        Session session = HibernateSessionFactoryUtil.getSessionFactory().openSession();
        Transaction tx1 = session.beginTransaction();
        session.delete(user);
        tx1.commit();
        session.close();
    }

    public Auto findAutoById(int id) {
        return HibernateSessionFactoryUtil.getSessionFactory().openSession().get(Auto.class, id);
    }

    public List<User> findAll() {
        List<User> users = (List<User>)  HibernateSessionFactoryUtil.getSessionFactory().openSession().createQuery("From User").list();
        return users;
    }
}
The methods UserDaoare similar to each other. In most of them, we get a Session object (a connection session with our database) using our Session Factory, create a single transaction within this session, perform the necessary data transformations, save the result of the transaction to the database and close the session. The methods themselves, too, as you can see, are quite simple. It is DAO that is the "heart" of our application. However, we will not create a DAO directly and call its methods in our main(). All logic will be moved to the UserService.
package services;

import dao.UserDao;
import models.Auto;
import models.User;

import java.util.List;

public class UserService {

    private UserDao usersDao = new UserDao();

    public UserService() {
    }

    public User findUser(int id) {
        return usersDao.findById(id);
    }

    public void saveUser(User user) {
        usersDao.save(user);
    }

    public void deleteUser(User user) {
        usersDao.delete(user);
    }

    public void updateUser(User user) {
        usersDao.update(user);
    }

    public List<User> findAllUsers() {
        return usersDao.findAll();
    }

    public Auto findAutoById(int id) {
        return usersDao.findAutoById(id);
    }


}
Service is the data layer in the application responsible for executing the business logic. If your program needs to execute some kind of business logic, it does it through services. The service contains UserDao, and calls DAO methods in its methods. This may seem like a duplication of functions to you (why not just call methods from a dao object), but with a large number of objects and complex logic, splitting the application into layers has huge advantages (this is a good practice, remember this information for the future and read about "application layers "). In our service, the logic is simple, but in real projects, service methods will contain much more than one line of code :) Now we have everything we need for the application to work! Your first Hibernate application - 12Let's create in a methodmain()the user, the machine for him, we will connect them with each other and save them in the database.
import models.Auto;
import models.User;
import services.UserService;

import java.sql.SQLException;

public class Main {
    public static void main(String[] args) throws SQLException {

        UserService userService = new UserService();
        User user = new User("Masha",26);
        userService.saveUser(user);
        Auto ferrari = new Auto("Ferrari", "red");
        ferrari.setUser(user);
        user.addAuto(ferrari);
        Auto ford = new Auto("Ford", "black");
        ford.setUser(user);
        user.addAuto(ford);
        userService.updateUser(user);
    }
}
As you can see, the users table has its own record, and the autos table has its own. Your first Hibernate application - 13Your first Hibernate application - 14Let's try to rename our user. Clear the users table and execute the code
import models.Auto;
import models.User;
import services.UserService;

import java.sql.SQLException;

public class Main {
    public static void main(String[] args) throws SQLException {

        UserService userService = new UserService();
        User user = new User("Masha",26);
        userService.saveUser(user);
        Auto ferrari = new Auto("Ferrari", "red");
        user.addAuto(ferrari);
        Auto ford = new Auto("Ford", "black");
        ford.setUser(user);
        user.addAuto(ford);
        userService.updateUser(user);
        user.setName("Sasha");
        userService.updateUser(user);
    }
}
Works! Your first Hibernate application - 15What if the user is deleted? Clear the users table (autos will clear itself) and execute the code
import models.Auto;
import models.User;
import services.UserService;

import java.sql.SQLException;

public class Main {
    public static void main(String[] args) throws SQLException {

        UserService userService = new UserService();
        User user = new User("Masha",26);
        userService.saveUser(user);
        Auto ferrari = new Auto("Ferrari", "red");
        user.addAuto(ferrari);
        Auto ford = new Auto("Ford", "black");
        ford.setUser(user);
        user.addAuto(ford);
        userService.updateUser(user);
        user.setName("Sasha");
        userService.updateUser(user);
        userService.deleteUser(user);
    }
}
And our tables are completely empty (pay attention to the console, all the queries that Hibernate has executed will be displayed there). You can "play around" with the application and try all its features. For example, create a user with machines, save it to the database, see what ID is assigned to it, and try to main()"pull" the user from the database by this id in the method and display a list of his machines in the console. Of course, we have only seen a small part of Hibernate's functionality. Its capabilities are very wide, and it has long been one of the industry standards for Java development. If you want to study it in detail, I can recommend the book "Java Persistence API and Hibernate", an overviewwhich I did in one of the previous articles. I hope this article was helpful to readers. If you have any questions - ask them in the comments, I will be happy to answer :) Also, do not forget to support the author in the contest by putting "Like". And better - "I like it very much" :) Successes in your studies!
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION