【SpringBoot DB 系列】h2databse 集成示例 demo

【SpringBoot DB 系列】h2databse 集成示例 demo

h2dabase 基於內存的數據庫,更常見於嵌入式數據庫的使用場景,依賴小,功能齊全;一般來講,正常的商業項目用到它的場景不多,但是在一些特殊的 case 中,還是比較有用的,比如用於單元測試,業務緩存,一些簡單的示例 demo 等;本文將手把手教你創建一個繼承 h2dabase 的項目,並支持從 sql 中導入預定好的 schema 和 data

I. 項目創建

本文對應的示例 demo,採用SpringBoot 2.2.1.RELEASE + maven 3.5.3 + IDEA進行開發

1. pom 配置

關於如何創建一個 springboot 項目本文就不介紹了,在我們創建好的項目中,pom.xml文件如下

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.1.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<dependencies>
    <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>
    </dependency>
</dependencies>

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </pluginManagement>
</build>

<repositories>
    <repository>
        <id>spring-snapshots</id>
        <name>Spring Snapshots</name>
        <url>https://repo.spring.io/libs-snapshot-local</url>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
    </repository>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/libs-milestone-local</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
    <repository>
        <id>spring-releases</id>
        <name>Spring Releases</name>
        <url>https://repo.spring.io/libs-release-local</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>

重點關注一下dependency中的com.h2database,另外兩個非必須,只是在後面的測試用例中會用到,推薦加上

從上面的引入也可以知道,我們將藉助 JPA 來操作數據庫

2. 屬性配置

既然是連接數據庫,當然少不了數據庫的相關配置,在項目的資源路徑下,新建配置文件application.properties

# 數據庫的相關配置
spring.datasource.url=jdbc:h2:~/h2-db
spring.datasource.username=test
spring.datasource.password=
spring.datasource.driverClassName=org.h2.Driver

上面的配置方式,和我們的 mysql 數據庫配置沒有什麼特別的,這裏的 url 請注意一下

  • jdbc:h2:~/h2-db: 嵌入式使用姿勢,會在用戶根目錄下生成一個名爲h2-db.mv.db的文件(數據庫的 schema 和 d column 就存在裏面)
  • jdbc:h2:mem:DBName;DB_CLOSE_DELAY=-1: 內存模式,應用重啓之後數據庫會清空,所以在測試用例中,可以考慮用這種

除了上面嵌入式的使用姿勢之外,h2-dabase 還支持通過 tcp 方式,指定一個遠程的目錄

  • jdbc:h2:tcp://localhost/~/test

上面是 h2dabase 的基本配置,爲了更友好的展示,我們開啓了 h2dabase 的 web console 控制檯

##h2 web console設置
spring.datasource.platform=h2
#進行該配置後,h2 web consloe就可以在遠程訪問了。否則只能在本機訪問。
spring.h2.console.settings.web-allow-others=true
#進行該配置,你就可以通過YOUR_URL/h2訪問h2 web consloe
spring.h2.console.path=/h2
#進行該配置,程序開啓時就會啓動h2 web consloe
spring.h2.console.enabled=true

最好開啓一下 jpa 的 sql 語句

spring.jpa.show-sql=true
spring.jpa.generate-ddl=true

II. 實例測試

上面配置搞完之後,基本上就可以說是完成了 h2dabase 的集成了

0. 入口

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }
}

SpringBoot 應用的啓動入口,上面執行之後,我們就可以通過http://localhost:8080/h2訪問 h2dabase 的控制檯,注意下面框處的內容,與前面的配置文件保持一致

登錄之後,就是一個建議的數據庫操作控制檯了

1. Entity 定義

下面這個屬於 JPA 的知識點,對於 jpa 有興趣的小夥伴,可以看一下前面的《JPA 系列教程》

@Entity
@Table(name = "test")
public class TestEntity {
    @Id
    private Integer id;
    @Column
    private String name;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

2. Repository 接口

數據庫操作接口,直接使用默認的 curd 即可,並沒有額外的添加方法

@Repository
public interface TestRepository extends CrudRepository<TestEntity, Integer> {
}

3. 測試 case

接下來給幾個 CURD 的測試 case,來演示一下我們的集成效果

@RestController
public class TestController {
    @Autowired
    private TestRepository testRepository;

    @GetMapping("/save")
    public TestEntity save(Integer id, String name) {
        TestEntity testEntity = new TestEntity();
        testEntity.setId(id);
        testEntity.setName(name);
        return testRepository.save(testEntity);
    }

    @GetMapping("/update")
    public TestEntity update(Integer id, String name) {
        Optional<TestEntity> entity = testRepository.findById(id);
        TestEntity testEntity = entity.get();
        testEntity.setName(name);
        return testRepository.save(testEntity);
    }

    @GetMapping("/list")
    public Iterable list() {
        return testRepository.findAll();
    }

    @GetMapping("/get")
    public TestEntity get(Integer id) {
        return testRepository.findById(id).get();
    }

    @GetMapping("/del")
    public boolean del(Integer id) {
        testRepository.deleteById(id);
        return true;
    }
}

實測 case 如下

# 新增一條記錄
curl 'http://localhost:8080/save?id=1&name=一灰灰'

# 查詢記錄
curl 'http://localhost:8080/get?id=1'

# 修改記錄
curl 'http://localhost:8080/update?id=1&name=一灰灰Blog'

# 查詢全部
curl 'http://localhost:8080/list'

# 刪除記錄
curl 'http://localhost:8080/del?id=1'

4. sql 文件導入

注意我們前面的所有步驟,沒有任何一個地方有說明需要主動去創建一個名爲test的表,這一點和我們熟悉的 mysql 是不一樣的;

某些時候我們可能希望將準備好的 sql 文件來初始化數據庫,這個時候可以如下操作

對應的 sql 文件

表結構 schema-h2.sql

DROP TABLE IF EXISTS book_to_book_store;
DROP TABLE IF EXISTS book_store;
DROP TABLE IF EXISTS book;
DROP TABLE IF EXISTS author;

DROP SEQUENCE IF EXISTS s_author_id;
CREATE SEQUENCE s_author_id START WITH 1;

CREATE TABLE author (
  id INT NOT NULL,
  first_name VARCHAR(50),
  last_name VARCHAR(50) NOT NULL,
  date_of_birth DATE,
  year_of_birth INT,
  address VARCHAR(50),

  CONSTRAINT pk_t_author PRIMARY KEY (ID)
);

CREATE TABLE book (
  id INT NOT NULL,
  author_id INT NOT NULL,
  co_author_id INT,
  details_id INT,
  title VARCHAR(400) NOT NULL,
  published_in INT,
  language_id INT,
  content_text CLOB,
  content_pdf BLOB,

  rec_version INT,
  rec_timestamp TIMESTAMP,

  CONSTRAINT pk_t_book PRIMARY KEY (id),
  CONSTRAINT fk_t_book_author_id FOREIGN KEY (author_id) REFERENCES author(id),
  CONSTRAINT fk_t_book_co_author_id FOREIGN KEY (co_author_id) REFERENCES author(id)
);

CREATE TABLE book_store (
  name VARCHAR(400) NOT NULL,

  CONSTRAINT uk_t_book_store_name PRIMARY KEY(name)
);

CREATE TABLE book_to_book_store (
  book_store_name VARCHAR(400) NOT NULL,
  book_id INTEGER NOT NULL,
  stock INTEGER,

  CONSTRAINT pk_b2bs PRIMARY KEY(book_store_name, book_id),
  CONSTRAINT fk_b2bs_bs_name FOREIGN KEY (book_store_name)
                             REFERENCES book_store (name)
                             ON DELETE CASCADE,
  CONSTRAINT fk_b2bs_b_id    FOREIGN KEY (book_id)
                             REFERENCES book (id)
                             ON DELETE CASCADE
);

數據文件 data-h2.sql

INSERT INTO author VALUES (next value for s_author_id, 'George', 'Orwell', '1903-06-25', 1903, null);
INSERT INTO author VALUES (next value for s_author_id, 'Paulo', 'Coelho', '1947-08-24', 1947, null);

INSERT INTO book VALUES (1, 1, null, null, '1984', 1948, 1, 'To know and not to know, to be conscious of complete truthfulness while telling carefully constructed lies, to hold simultaneously two opinions which cancelled out, knowing them to be contradictory and believing in both of them, to use logic against logic, to repudiate morality while laying claim to it, to believe that democracy was impossible and that the Party was the guardian of democracy, to forget, whatever it was necessary to forget, then to draw it back into memory again at the moment when it was needed, and then promptly to forget it again, and above all, to apply the same process to the process itself -- that was the ultimate subtlety; consciously to induce unconsciousness, and then, once again, to become unconscious of the act of hypnosis you had just performed. Even to understand the word ''doublethink'' involved the use of doublethink..', null, 1, '2010-01-01 00:00:00');
INSERT INTO book VALUES (2, 1, null, null, 'Animal Farm', 1945, 1, null, null, null, '2010-01-01 00:00:00');
INSERT INTO book VALUES (3, 2, null, null, 'O Alquimista', 1988, 4, null, null, 1, null);
INSERT INTO book VALUES (4, 2, null, null, 'Brida', 1990, 2, null, null, null, null);

INSERT INTO book_store (name) VALUES
	('Orell Füssli'),
	('Ex Libris'),
	('Buchhandlung im Volkshaus');

INSERT INTO book_to_book_store VALUES
	('Orell Füssli', 1, 10),
	('Orell Füssli', 2, 10),
	('Orell Füssli', 3, 10),
	('Ex Libris', 1, 1),
	('Ex Libris', 3, 2),
	('Buchhandlung im Volkshaus', 3, 1);

上面兩個文件準備好,接下來我們如何導入呢?

藉助sql-maven-plugin方式,在 pom 配置文件中,添加下面這段

<plugins>
    <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>sql-maven-plugin</artifactId>

        <executions>
            <execution>
                <id>create-database-h2</id>
                <phase>generate-sources</phase>
                <goals>
                    <goal>execute</goal>
                </goals>
            </execution>
        </executions>

        <configuration>
            <driver>org.h2.Driver</driver>
            <url>jdbc:h2:~/h2-db</url>
            <username>test</username>
            <password></password>
            <autocommit>true</autocommit>
            <srcFiles>
                <srcFile>src/main/resources/schema-h2.sql</srcFile>
                <srcFile>src/main/resources/data-h2.sql</srcFile>
            </srcFiles>
        </configuration>

        <dependencies>
            <dependency>
                <groupId>com.h2database</groupId>
                <artifactId>h2</artifactId>
                <version>1.4.200</version>
            </dependency>
        </dependencies>
    </plugin>
</plugins>

然後如下操作即可

導入成功之後,再到 h2 控制檯,就可以查看對應的數據

II. 其他

0. 項目

1. 一灰灰 Blog

盡信書則不如,以上內容,純屬一家之言,因個人能力有限,難免有疏漏和錯誤之處,如發現 bug 或者有更好的建議,歡迎批評指正,不吝感激

下面一灰灰的個人博客,記錄所有學習和工作中的博文,歡迎大家前去逛逛

一灰灰blog

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章