SpringBoot集成H2数据库
前言
1、场景
在写DAO层的单元测试时,我们往往会遇到一个问题,测试用例所依赖的数据库数据被修改或删除了,或者在一个新的环境下所依赖的数据库不存在,导致单元测试无法通过。在这种情况下,使用H2内存数据库来模拟数据库环境是一个很好的解决方案。
2、H2 特点
- 只有一个jar文件,适合作为嵌入式数据库使用
- 支持标准SQL和JDBC
- 可以用于单元测试,启动很快,每一个用例执行完会自动删除内存中的数据
上代码
使用maven工程来搭建测试环境,工程目录如下:
1、核心依赖
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.0.RELEASE</version> </parent> <dependencies> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <scope>provided</scope> </dependency> </dependencies>
2、配置文件 application.yml
server: port: 18095 spring: application: name: service-h2 jpa: show-sql: true #打印sql datasource: url: jdbc:h2:mem:xwj_db;MODE=MySQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE #mem:连接到内存 driver-class-name: org.h2.Driver username: root password: 123456 data: classpath:db/data.sql #初始化表数据
参数说明:
- jdbc:h2:mem 使用h2的内存数据库,还有file等其它方式
- xwj_db 数据库名称
- MODE=MySQL 以 MySQL 的模式运行
3、实体类
@Entity @Getter @Setter @ToString @NoArgsConstructor public class XwjUser implements Serializable { private static final long serialVersionUID = -2169427939264532306L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; /** 名称 */ public String name; /** 年龄 */ private Integer age; private Date createDate; }
4、Repository
public interface UserRepository extends JpaRepository<XwjUser, Long>{ }
5、Service
@Service public class UserService { @Autowired private UserRepository userRepository; @Autowired private JdbcTemplate jdbcTemplate; public List<XwjUser> findAll() { return userRepository.findAll(); } public XwjUser save(XwjUser user) { return userRepository.save(user); } /** * 通过主键id查询 */ public XwjUser findById(Long id) { Optional<XwjUser> optional = userRepository.findById(id); if (optional.isPresent()) { return optional.get(); } return null; } /** * 通过名称查询 */ public List<XwjUser> findByName(String name) { String sql = "select * from xwj_user where name like ?"; Object[] paramArr = new Object[1]; paramArr[0] = name + "%"; return jdbcTemplate.query(sql, paramArr, new BeanPropertyRowMapper<>(XwjUser.class)); } }
测试
1、在 src/main/resources 目录下,创建一个目录 /db 和脚本文件 data.sql :
insert into xwj_user (id, name, age, create_date) values(11,'张三','12','2020-04-17 00:00:00'); insert into xwj_user (id, name, age, create_date) values(12,'李四','13','2020-04-17 00:00:00'); insert into xwj_user (id, name, age, create_date) values(13,'王五','25','2020-04-17 00:00:00'); insert into xwj_user (id, name, age, create_date) values(14,'赵六','17','2020-04-17 00:00:00'); insert into xwj_user (id, name, age, create_date) values(15,'吉米','30','2020-04-17 00:00:00');
2、在 src/test/java 目录下,创建一个测试类:
@RunWith(SpringRunner.class) @SpringBootTest public class H2Test { @Autowired private UserService userService; /** * 测试查询所有 */ @Test public void testFind() { List<XwjUser> list = userService.findAll(); System.out.println("list: " + list); } /** * 测试新增+查询 */ @Test public void testInsertAndFind() { // 1、新增 XwjUser user = new XwjUser(); user.setAge(19); user.setName("张三"); user.setCreateDate(new Date()); XwjUser newUser = userService.save(user); // 2、通过id查询 Long id = newUser.getId(); System.out.println("findById: " + userService.findById(id)); // 3、模糊查询(自定义sql) String name = "张"; System.out.println("findByName: " + userService.findByName(name)); } }
3、测试 H2Test#testFind 方法,日志如下:
4、测试 H2Test#testInsertAndFind 方法,日志如下:
踩坑
1、在配置文件不要配置 schema,也不要直接将 schema.sql 脚本直接放在 src/main/resources 目录下,否则初始化数据脚本(即上面的data.sql)不会生效。
问题现象:执行方法的过程中没有任何报错,schema 和 data 脚本都会被执行(故意写错脚本会抛出异常)
问题原因:待进一步分析
知识改变世界