美文网首页
内存数据库:H2

内存数据库:H2

作者: hemiao3000 | 来源:发表于2021-02-06 18:10 被阅读0次

    测试持久层(Dao 层)的难点在于:

    • 单元测试必须执行隔离的代码;而持久层的代码需要和数据库进行交互。
    • 单元测试必须快速运行;而访问数据库却相对较慢。

    以上两个难点决定了嵌入式数据库(H2、HSQLDB、Derby 和 Java DB)的使用价值。嵌入式数据库使用场景较少,但是是配合 JUnit 测试持久层的最佳选择。

    1. 基本使用

    pom.xml 中添加 h2 数据库的依赖。如果是在非 Maven 项目中使用,则下载该 h2 的 .jar 包并加入项目的 classpath 中。

    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <version>1.4.200</version>
        <scope>test</scope>
    </dependency>
    

    嵌入式数据库 H2 有多种使用模式,也可以将数据写入到磁盘上的文件中,但是大家更关注它的『内存模式』。即,将 database 和 table 建立在内存中。

    private static final String DRIVER = "org.h2.Driver";
    private static final String URL = "jdbc:h2:mem:scott;MODE=MYSQL;DB_CLOSE_DELAY=-1";
    private static final String USERNAME = "sa";
    private static final String PASSWORD = "";
    
    • <h3>jdbc:h2:mem:testdb</h3>

      • 这是数据库 URL 的核心部分,其中 mem 就表示使用内存模式的 H2。H2 的各种不同的使用/运行模式,主要就体现在这个部分。

      • 数据库名<small>(以及后续的用户名和密码)</small>并非重要部分,因为内存模式的数据库,在使用结束后会被清除,而且对它的使用无所谓用户名密码。

    • <h3>MODE=MYSQL</h3>

      • H2 并不是唯一的嵌入式数据库,也不是唯一具有内存模式的嵌入式数据库,但是它是与 MySQL 语法最兼容的具有内存模式的嵌入式数据库<small>(虽然仍有些许特殊区别)</small>,这也是 JUnit中 首选 H2 的原因。
    • <h3>DB_CLOSE_DELAY=-1</h3>

      • 默认情况下,H2 内存中的数据库是在最后一个<small>(或指定个数)</small>连接断开后关闭,这时就会删除数据库及其中数据。

      • 设置为 -1 表示并非以连接数作为判断标准,而是持续保持数据库(即便没有连接),直到程序运行结束。

    Class.forName(DRIVER);
    
    Connection conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
    
    Statement stmt = conn.createStatement();
    stmt.execute( "...");
    

    除了正常的使用获得数据库 Connection 对象之外,H2 自带了连接池功能。

    JdbcConnectionPool cp = JdbcConnectionPool.create(URL, USERNAME, PASSWORD);
    Connection conn = cp.getConnection();
    

    2. 初始化数据库

    虽然可以在 JUnit 的 Before 方法中通过执行 SQL 语句的方式在 @Test 之前去初始化数据库环境,但是 H2 有一个更好的特性能实现数据库的初始化操作:Execute SQL on connection

    H2 支持在连接上数据库的时候就执行 SQL 语句,相当于就初始化了数据库环境:

    jdbc:h2:mem:<database>;...;INIT=RUNSCRIPT FROM '~/create.sql'
    

    spring.datasource.url=jdbc:h2:mem:scott;MODE=MYSQL;DB_CLOSE_DELAY=-1;INIT=RUNSCRIPT FROM './src/test/resources/create.sql'

    H2 internally uses Unicode, and supports all character encoding systems and character sets supported by the virtual machine you use.

    可以为测试类编写父类,并实现 @Before 方法,以方便/确保于在每个 @Test 方法前执行统一的初始化数据库(初始化测试环境)的代码。

    public class DaoTestBase {
    
        private static final String DRIVER = "org.h2.Driver";
        private static final String URL = "jdbc:h2:mem:testdb;MODE=MYSQL;DB_CLOSE_DELAY=-1";
        private static final String USERNAME = "sa";
        private static final String PASSWORD = "";
    
        @Before
        public void setUp() throws URISyntaxException, ClassNotFoundException, SQLException {
            String sqlPathName = getClass().getResource("/conf/sql/xxx.sql" ).toURI().toString().substring(6);
    
            Class.forName(DRIVER);
            Connection conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
    
            Statement stmt = conn.createStatement();
            stmt.execute( "runscript from '" + sqlPathName + "'");
    
            stmt.close();
            conn.close();
        }
    
    
    }
    

    三、H2 和 MySQL 的语法兼容性

    所有的数据库都会有些小区别,即便是与 MySQL『最像』的数据库,H2 与 MySQL 仍有一些小区别:

    • 不支持表级别的 Comment(注释)
    • 插不支持入语句的出现'
    • H2 UNIQUE KEY是数据库级别的,而非表级别
    • 无法执行多个 Update 语句,即一次 update 只能插入一条数据。
    • 列别名无法用于子查询
    • 不支持@:语法

    相关文章

      网友评论

          本文标题:内存数据库:H2

          本文链接:https://www.haomeiwen.com/subject/yuuotltx.html