Tổng quan về Spring Data JPA

Trong bài viết trước, mình đã giới thiệu với các bạn tổng quan về JPA Query Language để thao tác với các loại database sử dụng các entity. Mỗi khi các bạn cần thông tin gì từ database, các bạn sẽ sử dụng các câu lệnh SELECT hoặc UPDATE hoặc DELETE cùng với tên entity để build thành câu query, sau đó sẽ lấy đối tượng Query từ Entity Manager sử dụng câu query này, và cuối cùng là gọi một phương thức thích hợp tuỳ theo nhu cầu của các bạn từ đối tượng Query này để lấy kết quả mà các bạn mong muốn. Rất nhiều bước cần phải làm phải không các bạn? Nếu các bạn sử dụng JPA cùng với Spring framework trong dự án của mình thì hãy thử sử dụng Spring Data JPA nhé! Nó sẽ giúp các bạn giảm thiểu các công việc phải làm trong một số trường hợp. Cụ thể như thế nào? Trong bài viết này, chúng ta hãy cùng nhau tìm hiểu về Spring Data JPA các bạn nhé!

Đầu tiên, mình sẽ tạo mới một Maven project để làm ví dụ:

Tổng quan về Spring Data JPA

Chúng ta sẽ sử dụng Java 17 cho ví dụ này:

Spring Data JPA dependency:

Ở đây, mình sẽ sử dụng JPA với implementation của Hibernate nên mình sẽ thêm Hibernate dependency như sau:

Project Lombok:

Trong bài viết này, mình sẽ sử dụng MySQL database:

Để đơn giản, mình chỉ định nghĩa 1 table chứa thông tin sinh viên với 2 cột như sau:

Entity của table này:

Để làm việc với JPA, chúng ta cần có một tập tin cấu hình persistence.xml cho nó. Các bạn hãy tạo mới tập tin persistence.xml nằm trong thư mục /src/main/resources/META-INF các bạn nhé!

Nội dung của tập tin này như sau:

Khai báo EntityManagerFactory trong Spring container:

với datasource:

OK, vậy là đã chuẩn bị mọi thứ xong rồi đó các bạn:

Tổng quan về Spring Data JPA

Các bạn có thể tham khảo thêm bài viết về JPA và Spring framework tại đây nhé!

Giờ chúng ta đi vào chủ đề chính của bài viết này thôi.

Điều đầu tiên, các bạn cần phải biết là Spring Data JPA là một module nhỏ trong một project lớn gọi là Spring Data project. Mục đích của Spring Data project là giảm thiểu các đoạn code lặp đi lặp lại liên quan đến phần thao tác với các hệ thống quản trị data khi phát triển các ứng dụng có sử dụng Spring framework. Ngoài Spring Data JPA hỗ trợ cho JPA giảm thiểu code để truy cập và thao tác với các hệ thống quản trị cơ cở dữ liệu, chúng ta còn có Spring Data JDBC (cũng giống như Spring Data JPA), Spring Data LDAP (hỗ trợ Spring LDAP), Spring Data MongoDB (hỗ trợ cho MongoDB),… Các bạn có thể tìm thấy đầy đủ các module của Spring Data tại đây.

Để đạt được mục đích giảm thiểu code như mình đã nói, Spring Data định nghĩa một interface chính tên là Repository nằm trong module Spring Data Common, module này sẽ được sử dụng cho tất cả các module còn lại trong Spring Data project. Nội dung của interface này đơn giản như sau:

Interface này sử dụng 2 generic type:

  • T là domain class mà repository sẽ quản lý
  • ID là kiểu dữ liệu của ID của domain class mà repository quản lý.

Vì interface này đơn giản như vậy nên chắc chắn nó phải có những interface khác extend nó để thể hiện Spring Data project làm được những gì phải không các bạn? 😀

Ở đây, chúng ta sẽ có nhiều interface khác extend từ interface repository tuỳ thuộc vào module mà chúng ta sử dụng nhưng do chúng ta đang thảo luận về Spring Data JPA nên mình sẽ chỉ liệt kê ở đây một interface duy nhất extend interface Repository mà Spring Data JPA đang sử dụng. Đó chính là interface CrudRepository.

Interface CrudRepository với ý nghĩa create, read, update, delete cho phép chúng ta thực hiện các thao tác cơ bản đến với các hệ thống data, hệ thống data ở đây các bạn phải hiểu theo nghĩa rộng nghĩa là nó không chỉ là database đâu nhé các bạn.

Để hỗ trợ việc phân trang và sắp xếp cho Spring Data JPA, chúng ta còn phải nói đến một interface khác là PagingAndSortingRepository.

Tất cả các interface mà mình vừa kể trên đều nằm trong module Spring Data Common nhé các bạn.

Trong Spring Data JPA, ở đây, chúng ta chỉ có duy nhất một interface là JpaRepository kế thừa interface PagingAndSortingRepository. Với việc extend từ interface PagingAndSortingRepository, các bạn cũng có thể hình dung là Spring Data JPA có thể giúp chúng ta giảm thiểu code cho các thao tác nào liên quan đến database rồi phải không các bạn? Có thể kể ra đây là: create, read, update, delete, paging và sort. 😀

Các bạn có thể thấy rõ cấu trúc extend cho những interface trên bằng hình ảnh sau:

Tổng quan về Spring Data JPA

OK, vậy giờ hãy cùng mình làm một ví dụ với interface JpaRepository xem nó hoạt động như thế nào nhé các bạn.

Bây giờ mình sẽ tạo mới một interface tên là HelloRepository extend từ Jpa Repository với nội dung như sau:

Domain class ở đây chính là tên entity Student còn Long chính là kiểu dữ liệu của properties trong entity Student mapping với column primary key trong table student nha các bạn.

Giờ chúng ta sẽ khai báo interface này trong Spring container như sau:

Ở đây, mình sử dụng namespace jpa:repositories với base package là com.huongdanjava.springdatajpa để scan HelloRepository interface. Với khai báo như trên, Spring Data JPA sẽ tự động lấy đối tượng implement cho interface HelloRepository là SimpleJpaRepository như các bạn thấy trong hình ảnh ở trên để khởi tạo trong Spring container.

Một điểm mà các bạn lưu ý là chúng ta cần khai báo tag <context:annotation-config/> như mình đã làm ở trên để Spring cấu hình đối tượng của class EntityPathResolver khi khởi tạo bean cho class JpaRepositoryFactoryBean nhé! Nếu không thì sẽ bị lỗi “EntityPathResolver must not be null”. Các bạn có thể xem phương thức setEntityPathResolver() với annotation @Autowired trong class JpaRepositoryFactoryBean để hiểu rõ thêm chỗ này.

Vì đối tượng implement SimpleJpaRepository sử dụng transaction nên các bạn cần phải khai báo thêm bean transactionManager vào Spring container các bạn nhé.

OK, đến đây là chúng ta đã hoàn thành những phần cấu hình cần thiết. Giờ chạy ví dụ thử nhé các bạn.

Giả sử trong database mình đang có những dữ liệu sau đây:

Tổng quan về Spring Data JPA

thì khi chạy ví dụ sau đây:

Kết quả sẽ là:

Tổng quan về Spring Data JPA

Giả sử giờ chúng ta thêm một phương thức trong interface HelloRepository có nội dung như sau:

thì khi chạy ví dụ sau:

kết quả sẽ là:

Tổng quan về Spring Data JPA

Như các bạn thấy, mặc dù không có bất kỳ class nào implement interface HelloRepository nhưng chúng ta vẫn truy vấn table student theo column name được. Giảm được rất nhiều code mà chúng ta cần phải làm phải không các bạn?

4/5 - (4 bình chọn)

19 thoughts on “Tổng quan về Spring Data JPA

  1. Em chào Anh !
    1. Theo như e hiểu thì JPA là một 1 đặc tả của ORM. Nó bảo gồm các Interface không triển khai. Hay nói cách khác JPA định nghĩa các đặc tả cần thiết và không có code thực thi những đặc tả đó. Còn Hibernate sẽ thực hiện chi tiết các đặc tả của JPA. Nếu coi JPA là 1 Interface thì Hibernate sẽ Implement nó. Em hiểu như vậy có đúng không ạ ?
    2. Spring Data JPA là gì ? A có thể giải thích giúp e được không ạ ? E đọc mà vẫn thấy mơ hồ về nó !

    1. 1. Đúng rồi đó em. Bổ sung thêm là Hibernate còn có một implementation riêng của nó để thao tác với database.
      2. Spring Data JPA là một framework giúp chúng ta dễ dàng, nhanh chóng cấu hình các thông tin cần thiết để kết nối và thao tác với database, như các query method chẳng hạn,…

      1. trong jpa có sẵn các crud, còn hibernate sẽ có thêm nhiều phương thức hơn. Như vậy nói chỉ gồm các interface không có code thực thi hình như là sai!
        hibernate là thể hiện mở rộng hơn của JPA

  2. anh ơi. các column thì có phải khai báo tên tương ứng vs database ko a. Ví dụ như sau @Id em thêm @column(name=”id”) có đc ko a.

  3. anh cho em hỏi trong JpaRepository có phương thức getOne() nhưng em dùng thì nó báo lỗi, còn findById() thì dùng bình thường, thế khi nào thì dùng getOne() ạ ?

    1. getOne() chỉ nên được sử dụng nếu em chỉ cần check xem record với thông tin em đang truyền có tồn tại trong database hay không? Nó ko query xuống database mà chỉ check trong EntityManager có entity với thông tin mà em đang truyền hay không? Sử dụng getOne() khi em ko cần đọc thông tin của entity nhé!

  4. hi a,
    e lam theo huong dan cua anh, cai entity cua no bao loi nhu vay
    Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not a managed type: class com.pdhau.springdatajpa.Shape
    khong biet fix nhu the nao mong a giup

  5. hi anh public interface BookRepository extends CrudRepository{
    }
    public interface BookRepository extends jpaRepository{
    }
    hai interface trên đều cho kết quả giống nhau vậy nó có khác nhau ko anh

    1. Khác chứ em 😀
      Cái CrudRepository là interface dùng chung cho các Spring Data project, còn JpaRepository là cho Spring Data JPA. Em xem nội dung của những interface này để thấy rõ nhé.

Add Comment