Hướng dẫn sử dụng H2 database trong Spring Boot

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.

spring-boot-h2

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.sqldata.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

https://docs.spring.io/spring-boot/docs/2.1.18.RELEASE/reference/html/howto-database-initialization.html

 

5 1 vote
Article Rating
Subscribe
Notify of
guest
2 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
2
0
Would love your thoughts, please comment.x
()
x