Mục lục
Trong bài viết này chúng ta sẽ cùng nhau tìm hiểu cách sử dụng H2 database trong ứng dụng Spring Boot. H2 cũng giống như những database khác có đầy đủ những dependency hỗ trợ nó hoạt động với một ứng dụng Spring Boot.
Dependency
Để tìm bắt đầu bài hướng dẫn này chúng ta cần 3 dependency sau để sử dụng H2 database trong project Spring Boot.
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency>
Cấu hình database
Cũng giống như những database khác, chúng ta cần cấu hình những thông số cần thiết cho H2 database. Mặc định Spring Boot sẽ cấu hình tự động cho H2 hoạt động trên memory với username là sa và một password rỗng.
Tuy nhiên chúng ta có thể thay đổi các cấu hình mặc định này bằng cách thêm các thuộc tính sau vào file application.properties.
spring.datasource.url=jdbc:h2:mem:bookdb spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password=password spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
H2 – in-memory với RestAPI
Mặc định Spring Boot sẽ cấu hình H2 database lưu trữ dữ liệu trên memory, đều này đồng nghĩa với việc nếu ứng dụng bị tắt đi và mở lại thì các dữ liệu trước đó sẽ bị mất hoàn toàn.
Sau khi hoàn thành các bước cấu hình cơ bản với H2 database, giờ đây chúng ta có thể viết một ứng dụng đơn giản với JPA và H2 để xem chúng hoạt động với nhau như thế nào.
Giả sử có cấu trúc dự án như sau:
- BookController – API nhận các request từ client
- BookService – Xử lý business logic.
- BookServiceImpl – Một trình triển khai của BookService.
- BookRepository – Thao tác với h2 database như Insert, update, find, delete.
- BookDTO – Object dùng để giao tiếp giữa client và server.
- Book – Entity mapping.
Đầu tiên chúng ta đến với Book class, ánh xạ một bảng trong database lên JPA.
package com.deft.entity; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import javax.persistence.*; @Entity @Table(name = "books") @Getter @Setter @NoArgsConstructor @AllArgsConstructor public class Book { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private Integer price; private String author; }
BookDTO tương ứng dùng để giao tiếp giữa client-server
package com.deft.dto; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import java.io.Serializable; @Getter @Setter @NoArgsConstructor public class BookDTO implements Serializable { private Long id; private String name; private Integer price; private String author; }
BookRepository thừa kế từ JpaRepository
package com.deft.repository; import com.deft.entity.Book; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface BookRepository extends JpaRepository<Book, Long> { }
BookService xử lý business
package com.deft.service; import com.deft.dto.BookDTO; import java.util.List; public interface BookService { void create(BookDTO dto); List<BookDTO> findAll(); }
BookServiceImpl trình triển khai của BookService
package com.deft.service; import com.deft.dto.BookDTO; import com.deft.entity.Book; import com.deft.repository.BookRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; import java.util.stream.Collectors; @Service public class BookServiceImpl implements BookService { @Autowired private BookRepository bookRepository; @Override public void create(BookDTO dto) { Book book = new Book(); book.setAuthor(dto.getAuthor()); book.setName(dto.getName()); book.setPrice(dto.getPrice()); bookRepository.save(book); } @Override public List<BookDTO> findAll() { return bookRepository.findAll().stream() .map(book -> { BookDTO bookDTO = new BookDTO(); bookDTO.setAuthor(book.getAuthor()); bookDTO.setId(book.getId()); bookDTO.setName(book.getName()); bookDTO.setPrice(book.getPrice()); return bookDTO; }).collect(Collectors.toList()); } }
Cuối cùng chúng ta cần định nghĩa controller nhận các request từ client
package com.deft.controller; import com.deft.dto.BookDTO; import com.deft.service.BookService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.List; @RestController @RequestMapping("/books") public class BookController { @Autowired private BookService bookService; @PostMapping public void create(@RequestBody BookDTO dto) { bookService.create(dto); } @GetMapping public List<BookDTO> findAll() { return bookService.findAll(); } }
Sử dụng Postman để gửi request lên server
Sau khi gửi thành công chúng ta sẽ kiểm tra lại bằng cách lấy danh sách các Book được lưu trong H2.
H2 – file-based storage
Như đã đề cập ở trên thì mặc định H2 sẽ lưu dữ liệu trên memory, nếu các bạn không muốn dữ liệu bị mất sau mỗi lần khởi động lại thì chúng ta có thể cấu hình thông qua thuộc tính spring.datasource.url.
spring.datasource.url=jdbc:h2:file:/data/demo
Nếu bạn đang dùng windows thì có thể cấu hình
spring.datasource.url = jdbc:h2:file:C:/data/sample
Với C:/data/sample là đường dẫn đến nói H2 sẽ lưu dữ liệu vào file.
Để tạo table books trong H2 database, chúng ta có thể sử dụng chức năng của hibernate với cấu hình spring.jpa.hibernate.ddl-auto. Với cấu hình này Spring boot sẽ tự động phân tích Book entity và khởi tạo table tương ứng trong database.
spring.jpa.hibernate.ddl-auto=create-drop
Lưu ý sau lần đầu khởi chạy, database đã được khởi tạo thì hãy tắt cấu hình này đi nhé. Nếu không ở lần sau khởi chạy nó sẽ tự động xóa và khởi tạo database mới đồng nghĩa với việc dữ liệu ở những lần trước của bạn sẽ bị biến mất.
Một cách khác các bạn có thể định nghĩa các file schema.sql và data.sql đặt trong src/main/resources/. Trong đó schema.sql được dùng để khởi tạo cấu trúc các bảng, data.sql dùng để thêm dữ liệu. Spring Boot sẽ tự động tìm kiếm và thực thi chúng.
Tuy nhiên để những file này chắc chắn được thực thi, chúng ta cần thêm các cấu hình sau vào file application.propertites.
spring.jpa.hibernate.ddl-auto=none spring.datasource.initialization-mode=always
Lưu ý sau lần đầu được khởi chạy, các bạn phải tắt cấu hình spring.datasource.initialization-mode=always nếu không thì dữ liệu cũ cũng sẽ bị xóa ở lần khởi chạy sau.
Sau đây mình sẽ định nghĩa 2 file schema.sql và data.sql để thêm dữ liệu ban đầu cho h2.
DROP TABLE IF EXISTS books; CREATE TABLE books ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(250) NOT NULL, price INTEGER NOT NULL, author VARCHAR(250) DEFAULT NULL );
data.sql
INSERT INTO books (name, price, author) VALUES ('Aliko', 12, 'Billionaire Industrialist'), ('Bill', 14, 'Billionaire Tech Entrepreneur'), ('Folrunsho', 42, 'Billionaire Oil Magnate');
Kết quả mình có dữ liệu như bên dưới.
H2 Console
H2 database cũng đã nhúng một bộ UI cho phép chúng ta quản lý, truy vấn dữ liệu thông qua giao diện. Tuy nhiên, mặc định H2 console bị tắt bởi Spring. Để mở tính năng H2 console chúng ta cần cấu hình thuộc tính sau thành TRUE.
spring.h2.console.enabled=true
Tiếp theo để sử dụng giao diện của h2 console chúng ta có thể truy cập vào địa chỉ http://localhost:8080/h2-console trên giao diện trình duyệt đang sử dụng.
Đầu tiên chúng ta sẽ phải login để sử dụng, điền đầy đủ thông tin đã cấu hình trong file application.properties như Driver class, JDBC URL, Username, Password.
Sau khi login thành công chúng ta sẽ có giao diện sau
Các bạn có thể thấy mình đã thực thi truy vấn và nhận được kết quả như hình. Giao diện này cũng tiện lợi và đáp ứng mọi nhu cầu cần sử dụng.
Ngoài ra cũng có một số cấu hình đươc khuyên nên sử dụng để tăng tính bảo mật cho h2 database
spring.h2.console.path=/h2-console spring.h2.console.settings.trace=false spring.h2.console.settings.web-allow-others=false
Trong đó spring.h2.console.path=/h2-console chỉ ra đường dẫn tương đối để kết nối đến UI của H2 console, Ví dụ nếu ứng dụng của bạn chạy trên http://localhost:9001 thì đường dẫn kết nối đến H2 console là http://localhost:9001/h2-console.
Ngoài ra, thuộc tính spring.h2.console.settings.trace=false để ngăn chặn các dấu vết của database xuất ra bên ngoài và spring.h2.console.settings.web-allow-other tắt tính năng kết nối từ xa đến database.
Kết bài
H2 database là một database mạnh mẽ có đầy đủ các chức năng như một SQL database. Trong Spring Boot H2 thường được sử dụng trong unit-test giúp tách bạch các dữ liệu test ra khởi dữ liệu thật trong một database khư mysql, mysqlserver, v.v. Ngoài ra các ứng dụng nhỏ gọn, không cần thiết phải sử dụng đến database server khác thì vẫn có thể sử dụng H2 như một nơi để lưu trữ và truy xuất dữ liệu.
Cuối cùng mã nguồn được mình công khai trên gitlab để các bạn có thể tiện theo dõi nếu có vấn đề gì trong quá trình thực hành: h2-database.
Nguồn tham khảo
https://www.baeldung.com/spring-boot-h2-database
https://dimitr.im/loading-initial-data-with-spring