Spring Data JPA 和 H2数据库

Introduction

H2是一个轻量级数据库,有以下特点:

  • 纯Java编写
  • 没有任何依赖,只有一个jar包且不到2M
  • 提供了一个web控制台
  • 支持内存模式、内嵌模式、服务器模式和集群
  • 支持事务
  • 支持主键和索引

麻雀虽小,五脏俱全,在本地开发中如果不想费劲去安装一个MySQL,或在小型应用中需要一个内存数据库,H2都是不错的选择。

官网:http://www.h2database.com/html/main.htmlopen in new window

下面就结合H2写一个Spring JPA的入门教程,如果要换成MySQL或其他数据库,差别也不大。

Get Started

引入依赖

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

配置H2数据库

# 开启H2控制台
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console

# 配置数据源,使用H2数据源
spring.datasource.name=your-datasource-name
spring.datasource.driver-class-name=org.h2.Driver
# H2数据库默认的账号密码
spring.datasource.username=sa
spring.datasource.password=
# url 
spring.datasource.url=jdbc:h2:~/Documents/db/demo

# 开启ddl自动更新,应用启动时框架会根据实体类自动更新表结构
# 建议生产环境关闭此项配置,使用手动方式维护ddl
spring.jpa.hibernate.ddl-auto=update
# 开启sql日志,方便调试
spring.jpa.show-sql=true

H2数据库支持多种运行模式,由spring.datasource.url参数决定。

创建实体类

@Entity
@Table(name = "t_example")
@Data
public class ExampleEntity {

    @Id
    @GeneratedValue
    private Long id;
    
    private String message;

    /**
     * 字段在Java中是小驼峰方式命名,但是在建表时会自动转为使用下划线"_"分隔
     */
    private LocalDateTime createTime;
}

创建Repository

@Repository
public interface ExampleRepository extends JpaRepository<ExampleEntity, Long> {
}
  • 加@Repository注解是为了在IDEA里面使用@Autowired装配repository bean时不报错
  • 必须实现JpaRepository<Entity,ID>接口

测试

编写一个Unit Test:

@SpringBootTest
public class ExampleTest {

    @Autowired
    private ExampleRepository exampleRepository;

    @Test
    public void addExample() {
        ExampleEntity entity = new ExampleEntity();
        entity.setMessage("test add an example");
        entity.setCreateTime(LocalDateTime.now());
        exampleRepository.save(entity);
    }
}

执行后通过控制台查看结果:

Spring Data JPA的查询语法

你会发现在上述demo中没有写任何sql语句或使用自动化工具生成dao代码,这就是Spring Data JPA的神奇之处。

其实是父接口JpaRepository<T,ID>已经实现了默认的CRUD和分页查询功能,例如save()、getOne(ID id)、findAll()、count()等一系列见名知意的方法,这些都是开箱即用的!

那么如果想要根据其他条件查询信息呢?

根据条件定义查询方法

还是上述例子,要实现根据message字段来查询t_example表,只需要在Repository中增加一个方法:

@Repository
public interface ExampleRepository extends JpaRepository<ExampleEntity, Long> {
    
    List<ExampleEntity> findByMessage(String message);
}

Spring Data会自动根据方法签名来推测查询语句,例如上面的代码就会被翻译成:select * from t_example where message='<message>';

方法的命名遵循以下模式:readSomeThingByColumnNameEqualsOrderByColumnName。其中:

  • read是动词,表示查询,也可以使用get、find、count等
  • read后面紧跟的是主题,也就是EntityName,通常可以省略
  • By后面跟着的是条件,还可以指定比较操作符,默认是Equals,还可以是In/NotIn/Like/Between等
  • OrderBy即排序

因为篇幅原因,这里还有一些其他情况没有列举出来(例如distinct),好在我们并不需要逐个记忆,首先是这种语法比较贴近自然语言,并且IDEA有完整的自动化提示!
那么如果要创建时间查询t_example并排序可以这样写:

@Repository
public interface ExampleRepository extends JpaRepository<ExampleEntity, Long> {
    
    List<ExampleEntity> findByCreateTimeBetweenOrderByCreateTime(LocalDateTime from, LocalDateTime to);
}

自定义查询

上述方法确实很方便,但是在面对复杂场景时可能就不适用了,即便能用也可能导致方法名非常长!
这时候可以使用@Query注解来实现自定义查询,例如还是根据创建时间来查询并排序,可以写为:

@Repository
public interface ExampleRepository extends JpaRepository<ExampleEntity, Long> {
    
    @Query("select t from ExampleEntity t where t.createTime between :from and :to order by create_time desc")
    List<ExampleEntity> findByTime(@Param("from") LocalDateTime from, @Param("to") LocalDateTime to);
}

需要注意:

  • 不能使用select *,表名和字段名必须与Java中定义的一致,而不是数据库中的真实名称
  • sql可以使用命名参数:param,参数要和方法参数中的@Param一一对应

TIP

如果要使用原生的sql语句,需要在@Query标签中加上参数nativeQuery = true

H2数据库的运行模式

内存模式

spring.datasource.url=jdbc:h2:mem:[<db_name>]

内存模式下数据直接保存在内存中。

  • 如果db_name为空,则表示数据库是私有库,每个数据库连接将单独创建一个数据库。
  • 如果db_name不为空则所有连接共享一个数据库。
  • 当最后一个连接关闭时,数据库也会被关闭,内容丢失。如果希望数据库一直保留直到进程结束,需要设置url:jdbc:h2:mem:test;DB_CLOSE_DELAY=-1
  • 通常内存模式下,应用启动时数据库是空的,可以通过url的INIT参数来设置初始化脚本:jdbc:h2:mem:test;INIT=runscript from '~/init.sql'

内嵌模式

spring.datasource.url=jdbc:h2:[file:][<path>]<db_name>

内嵌模式下数据库与应用同时启停,H2控制台与应用共用同一个域名和端口,数据文件单独存放在文件系统中以db_name.mv.db命名。
默认使用 localhost:8080/h2-console 访问控制台。

本例即使用这种方式,使用方便且数据可以持久化。

DANGER

如果开启了Spring Security,会默认设置HTTP Header X-Frame-Options: DENY不允许页面在Frame中加载,因此H2控制台无法打开。
只需在Spring Security中加入.and().headers().frameOptions().sameOrigin()即可。

TIP

关于 Spring Security 可以查看Spring Security系列文章

独立运行模式

spring.datasource.url=jdbc:h2:tcp://<server>[:<port>]/[<path>]<db_name>

独立运行模式需要到官网下载运行程序,过程也是非常简单,这里不详述。

Last Updated 2024/11/25 02:50:15