[spring] spring jpa-hibernate CRUD

[spring] spring jpa – hibernate CRUD

Previous Notes [spring] spring jpa – hibernate terminology & configuration After passing through some conceptual things, this note will go through the practical operations

CRUD

This is implemented through EntityManager (Spring’s dependency injected through DI) and DAO (design pattern). The general implementation structure is to generate a DAO interface, and then generate a DAOImpl class to implement the code:

  • DAO

    public interface StudentDAO {<!-- -->}
    
  • DAOImpl

    Here we first need to define this as a bean of type Repository, and then obtain the entityManager automatically generated by Spring through DI:

    @Repository
    public class StudentDAOImpl implements StudentDAO {<!-- -->
      private EntityManager entityManager;
    
      @Autowired
      public StudentDAOImpl(EntityManager entityManager) {<!-- -->
          this.entityManager = entityManager;
      }
    }
    

Overall, CRUD operations using JPA are very simple and the code is not complicated.

Create

First define a saved method in the interface for the implementation class to overload:

public interface StudentDAO {<!-- -->
  void save(Student student);
}

In the implementation class, just call EntityManager to save, and hibernate will implement the remaining operations by itself:

import org.springframework.transaction.annotation.Transactional;

public class StudentDAOImpl implements StudentDAO {<!-- -->
    @Override
    @Transactional
    public void save(Student student) {<!-- -->
        entityManager.persist(student);
    }
}

This is completed, let’s test it next

Update the code in the CLI Runner:

public class HibernateJpaApplication {<!-- -->
@Bean
public CommandLineRunner commandLineRunner(StudentDAO studentDAO) {<!-- -->
return runner -> createStudent(studentDAO);
}

  private void createStudent(StudentDAO studentDAO) {<!-- -->
System.out.println("Creating new student object...");
Student s = new Student("Scooby", "Dudes", "[email protected]");
System.out.println("New student: " + s);

System.out.println("Saving the student ...");
studentDAO.save(s);

System.out.println("Saved student. Generated id: " + s.getId());
}
}

operation result:

Then the data displayed in the database:

Retrieve

Three functions are implemented here: findById, findAll and findByLastName

findById

Similarly, add methods to the interface first:

public interface StudentDAO {<!-- -->
  Student findById(Integer id);
}

Then implement:

public class StudentDAOImpl implements StudentDAO {<!-- -->
    @Override
    public Student findById(Integer id) {<!-- -->
        return entityManager.find(Student.class, id);
    }
}

Since there will not be any mutation on the data, there is no need to add @Transactional

Update the code in the CLI Runner:

public class HibernateJpaApplication {<!-- -->
@Bean
public CommandLineRunner commandLineRunner(StudentDAO studentDAO) {<!-- -->
return runner -> readStudent(studentDAO);
}

  private void readStudent(StudentDAO studentDAO) {<!-- -->
System.out.println(studentDAO.findById(3));
}
}

findAll

Similarly, add methods to the interface first:

public interface StudentDAO {<!-- -->
   List<Student> findAll();
}

Then implement:

public class StudentDAOImpl implements StudentDAO {<!-- -->
    @Override
    public List<Student> findAll() {<!-- -->
        TypedQuery<Student> query = entityManager.createQuery("From Student", Student.class);
        return query.getResultList();
    }
}

The abstract understanding of TypedQuery is the benchmark PreparedStatement. Of course, the abstraction layer and implementation of the two are different.

Update the code in the CLI Runner:

public class HibernateJpaApplication {<!-- -->
@Bean
public CommandLineRunner commandLineRunner(StudentDAO studentDAO) {<!-- -->
return runner -> readAllStudents(studentDAO);
}

  private void readAllStudents(StudentDAO studentDAO) {<!-- -->
List<Student> studentList = studentDAO.findAll();
studentList.forEach(student -> System.out.println(student));
}
}

The effect is as follows:

findByLastName

Here we will add a little bit of JPQL syntax. JPQL syntax is quite similar to the general SQL syntax. You can also use WHERE, LIKE, ORDER BY wait. For example, SQL corresponds to the table name and entity attributes in the database. Here it corresponds to the name and attributes of the java object.

Similarly, add methods to the interface first:

public interface StudentDAO {<!-- -->
  List<Student> findByLastName(String lastName);
}

Then implement:

public class StudentDAOImpl implements StudentDAO {<!-- -->
    @Override
    public List<Student> findByLastName(String lastName) {<!-- -->
        TypedQuery<Student> query = entityManager.createQuery("From Student WHERE lastName=:latName", Student.class);
        query.setParameter("latName", lastName);

        return query.getResultList();
    }
}

The placeholder here uses the syntax of :varName, and uses setParameter to insert variables.

Update the code in the CLI Runner:

public class HibernateJpaApplication {<!-- -->
@Bean
public CommandLineRunner commandLineRunner(StudentDAO studentDAO) {<!-- -->
return runner -> readStudentsByLastName(studentDAO);
}

private void readStudentsByLastName(StudentDAO studentDAO) {<!-- -->
List<Student> studentList = studentDAO.findByLastName("Doe");
studentList.forEach(student -> System.out.println(student));
}
}

The effect is as follows:

Update

Only the update operation of one entity is implemented here. If it is not implemented carefully, it will indeed affect all associated query objects.

Similarly, add methods to the interface first:

public interface StudentDAO {<!-- -->
  List<Student> findByLastName(String lastName);
}

Then implement:

public class StudentDAOImpl implements StudentDAO {<!-- -->
    @Override
    @Transactional
    public void update(Student student) {<!-- -->
        entityManager.merge(student)
    }
}

This will mutate the objects in the database, so you need to add @Transactional

Update the code in the CLI Runner:

public class HibernateJpaApplication {<!-- -->
@Bean
public CommandLineRunner commandLineRunner(StudentDAO studentDAO) {<!-- -->
return runner -> updateStudent(studentDAO);
}

private void updateStudent(StudentDAO studentDAO) {<!-- -->
System.out.println("Getting student by id: 2");
Student s = studentDAO.findById(2);
System.out.println("Student found: " + s);
System.out.println("Update student first name to Mickey");
s.setFirstName("Mickey");
studentDAO.update(s);
System.out.println("Updated student: " + studentDAO.findById(2));
}
}

The effect is as follows:

Data in DB:

Delete

Now we have reached the final step of CRUD. We will write two cases here, one is to delete a single entity, and the other is to delete multiple entities. The main reason is that the syntax is different.

delete

Similarly, add methods to the interface first:

public interface StudentDAO {<!-- -->
  void delete(Integer id);
}

Then implement:

public class StudentDAOImpl implements StudentDAO {<!-- -->
    @Override
    @Transactional
    public void delete(Integer id) {<!-- -->
        Student s = this.findById(id);
        entityManager.remove(s);
    }
}

This will mutate the objects in the database, so you need to add @Transactional

Update the code in the CLI Runner:

public class HibernateJpaApplication {<!-- -->
@Bean
public CommandLineRunner commandLineRunner(StudentDAO studentDAO) {<!-- -->
return runner -> deleteStudent(studentDAO);
}

private void deleteStudent(StudentDAO studentDAO) {<!-- -->
System.out.println("Deleting student id: 2");
studentDAO.delete(2);
}
}

The effect is as follows:

Data in DB:

In fact, it is better to use deleteById

deleteAll

Similarly, add methods to the interface first:

public interface StudentDAO {<!-- -->
  void delete(Integer id);
}

Then implement:

public class StudentDAOImpl implements StudentDAO {<!-- -->
    @Override
    @Transactional
    public int deleteAll() {<!-- -->
        int numOfRowsDeleted = entityManager.createQuery("DELETE FROM Student").executeUpdate();
        return numOfRowsDeleted;
    }
}

This will mutate the objects in the database, so you need to add @Transactional

Update the code in the CLI Runner:

public class HibernateJpaApplication {<!-- -->
@Bean
public CommandLineRunner commandLineRunner(StudentDAO studentDAO) {<!-- -->
return runner -> deleteStudent(studentDAO);
}

private void deleteStudent(StudentDAO studentDAO) {<!-- -->
System.out.println("Deleting student id: 2");
studentDAO.delete(2);
}
}

The effect is as follows:

Data in DB:

java code creation table

This part mainly implements configuration in applications.properties:

spring.jpa.hibernate.ddl-auto=create

create This configuration will delete the table in the database and create a new table every time, so it is not necessary to use it in daily development environment

If possible, try to use sql scripts unless there are specific usage scenarios.

Summary

There is not much content in this note. The main thing is that there is a little more CRUD code, and the rest is okay: