隔离数据库环境
使用 H2 内存数据库提高数据库操作速度
在 spring-test
中使用 spring-tx
进行事务回滚,以保证测试代码的隔离之后,我们的测试环境还有一处可改进的地方:提高测试环境中数据库的执行速度。
单元测试必须快速执行。因为一个方法不仅会有一个 TestCase ,一个业务方法的背后,需要有大量的测试代码对其进行测试。理论上测试代码要远多于业务代码。所以,执行测试用例时,会有更频繁的数据库操作。
为了不让 MySQL 的磁盘操作影响到测试代码的执行,我们可以使用内存数据库。通过内存操作,以替代磁盘操作。
相较于它的竞争者而言,它最大的特点在于,它兼容 MySQL,虽然仍有些不完全一致的地方,但相较而言那都是些细枝末节,无关紧要之处。
它支持多种运行模式:将数据库数据存储于内存中( 内存运行模式
),或存储于磁盘上。H2 数据库不需要专门的去启动/运行它,直接连接即可!
H2 是一个由 Java 代码实现的内嵌式数据库,它支持三种运行模式:
运行模式 | 说明 |
---|---|
Embedded 嵌入式 |
无需配置本地(或远程)数据库 ; 数据库连接关闭时,数据与表结构依然存在; |
In-Memory 内存模式 |
同上,区别:数据库连接关闭时,数据与表结构删除; |
ServerMode 传统模式 |
需要配置本地(或远程)数据库; |
pom.xml 引入:
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.197</version> <!-- spring-boot-dependencies 中有版本号 -->
<scope>test</scope> <!-- 由于我们仅用它来进行 JUnit 测试,
因此只在测试环境中使用它。
项目发布时,项目的包中不需要包含它 -->
</dependency>
-
四大数据库连接属性
String DRIVER = "org.h2.Driver"; String URL = "jdbc:h2:mem:scott;MODE=MYSQL;DB_CLOSE_DELAY=-1"; String USERNAME = "sa"; String PASSWORD = "";
-
jdbc:h2:mem:scott
这是数据库 URL 的核心部分,其中
mem
就表示使用内存模式的 H2。H2 的各种不同的使用/运行模式,主要体现在这个部分。此处指令连接 scott 数据库,h2 就会自动帮我们创建名为
scott
的 database,因此后续的 sql 语句中无须再指定创建scott
,也不用再使用use scott
切换到它。 -
MODE=MYSQL
H2 并不是唯一的嵌入式数据库,也不是唯一具有内存模式的嵌入式数据库,但是它是与 MySQL 语法最兼容的具有内存模式的嵌入式数据库,这也是 JUnit中 首选 H2 的原因。
-
DB_CLOSE_DELAY=-1
默认情况下,H2 内存中的数据库是在最后一个连接断开后关闭数据库,即删除数据库及其中所有数据。
设置为 -1 表示不以连接数作为判断标准,而是持续保持数据库的存在,直到程序运行结束。
-
用户名和密码
由于使用的是 h2 的内存模式,所以这里并不存在实际上的连接校验身份的功能。因此用户名密码并没有实际的作用。按惯例写成
"sa"
和""
既可。
在 spring-dao.xml
其实很简单,只需要修改数据库连接池的四大连接属性即可。
<!-- 数据库连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<property name="driverClassName" value="org.h2.Driver"/>
<property name="url" value="jdbc:h2:mem:scott;MODE=MYSQL;DB_CLOSE_DELAY=-1"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
初始化数据库有 2 种方式: <jdbc:initialize-database>
配置文件配置,和 @Sql 注解配置。推荐使用 @Sql 注解配置。
@Slf4j
@SpringJUnitConfig(H2Config.class)
class DepartmentDaoTest {
@Resource
private DepartmentDao dao;
@Test
@Sql({ "/sql/department.sql"})
void selectByPrimaryKey() {
assertNotNull(dao);
System.out.println(dao.selectByPrimaryKey(1L));
}
}
h2 与 mysql 的语法区别:
- h2 不支持 engine 关键字;
- h2 不支持以 alter table add constraint 的方式为表添加外键
- h2 的 insert sql 语句只支持标准的 values 关键字,mysql 还额外支持 value 。
其它区别还有待于发掘。
网友评论