使用 Hibernate 连接 KaiwuDB 数据库
Hibernate 是一个广泛使用的 ORM 框架,简化了 Java 应用程序中的数据库持久化操作。开发者可以使用 Java 对象与数据库交互,而不需要编写大量的 SQL 代码。
KaiwuDB 开发了适用于 KaiwuDB 的Dialect
,定义了 KaiwuDB 数据库特有的 SQL 方言,使 Hibernate 能够生成与 KaiwuDB 兼容的 SQL 查询。
KaiwuDB 支持开发人员通过在 SpringBoot 项目中集成 JPA、KaiwuDB JDBC 和 Lombok 等工具,使用 Hibernate 框架协议来连接 KaiwuDB 数据库,执行数据查询、写入和删除操作。
前提条件
- 安装 openJDK(1.8 及以上版本)。
- 安装 Maven(3.6 及以上版本)。
- 安装 KaiwuDB 2.0.4 及以上版本、配置数据库认证方式、创建数据库。
- 创建具有表级别及以上操作权限的用户。
- 获取 KaiwuDB JDBC 驱动包。
- 获取 KaiwuDB 开发适配的 Hibernate Core 5.6.16 安装包。
配置连接
步骤:
在 Hibernate 安装包所在目录,创建
pom.xml
文件,引入 JPA、Hibernate 和 KaiwuDB JDBC 依赖信息。示例:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.2.RELEASE</version> <relativePath/> </parent> <groupId>com.kaiwudb.hibernate</groupId> <artifactId>kwdb-hibernate</artifactId> <version>1.0</version> <name>kwdb-hibernate</name> <packaging>pom</packaging> <description>This program is use kaiwudb jdbc test hibernate framework example.</description> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <maven.compiler.encoding>UTF-8</maven.compiler.encoding> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> <maven.compiler.version>3.8.1</maven.compiler.version> <java.version>1.8</java.version> </properties> <modules> <module>relational</module> <module>time-series</module> </modules> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- jpa --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> <exclusions> <exclusion> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> </exclusion> </exclusions> </dependency> <!-- hibernate-core --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.6.16.RELEASE</version> </dependency> <!-- kaiwudb-jdbc--> <dependency> <groupId>com.kaiwudb</groupId> <artifactId>kaiwudb-jdbc</artifactId> <version>2.2.0</version> </dependency> <!-- mockito-core --> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>2.19.1</version> <scope>test</scope> </dependency> </dependencies> </project>
如果 KaiwuDB JDBC 无法正常加载使用,运行以下命令,将 KaiwuDB JDBC 驱动安装到本地 Maven 仓库中。
mvn install:install-file "-Dfile=../kaiwudb-jdbc-2.2.0.jar" "-DgroupId=com.kaiwudb" "-DartifactId=kaiwudb-jdbc" "-Dversion=2.2.0" "-Dpackaging=jar"
将 Hibernate 安装到本地 Maven 仓库中。
示例:
mvn install:install-file "-Dfile=../hibernate-core-5.6.16.RELEASE.jar" "-DpomFile=../hibernate-core-5.6.16.RELEASE.pom" "-DgroupId=org.hibernate -DartifactId=hibernate-core" "-Dversion=5.6.16.RELEASE" "-Dpackaging=jar"
配置示例
配置数据库连接和使用涉及以下步骤:
- 配置数据源:指定数据库方言和其他连接属性。时序库中还需要禁用事务管理。
- 定义实体类:用于映射数据库中的表结构和数据类型。实体类通常使用 JPA 注解来指定表名和字段映射。
- 定义数据访问接口:定义与数据库的交互,包括查询、更新等操作。
- 定义 Service 接口及实现:Service 层封装了数据访问操作,为上层应用提供统一的业务逻辑接口和处理方法。
- 定义 Controller 层:Controller 层负责接收用户的请求,并调用相应的 Service 方法处理业务逻辑。处理完的结果将会被返回给用户。
KaiwuDB 时序库和关系库在配置和使用上有所不同,以下章节分别提供了时序库和关系库的配置示例。
时序库
在
resources
目录下的application.yml
文件中配置数据源,指定方言包并禁用事务管理。提示
KaiwuDB 只支持显式事务内执行时序数据的查询以及写入,不支持显式事务内执行时序数据的 DDL 操作。如果未关闭事务管理就对时序数据引擎进行操作,数据库可能报不支持事务的错误。
示例:
spring: datasource: driver-class-name: com.kaiwudb.Driver url: jdbc:kaiwudb://127.0.0.1:26257/test_tsdb username: <user_name> password: <password> jpa: properties: # 禁用事务管理 javax.persistence.transactionType: RESOURCE_LOCAL open-in-view: false hibernate: ddl-auto: update show-sql: true database-platform: org.hibernate.dialect.KaiwuDBDialect server: port: 9001
在
entity
目录下定义映射表结构的实体类,例如TsdbEntity.java
。示例:
示例中,@Table 标签中的 name 名称
tsdb_table
为对应的时序表名称,每列字段对应目前 KaiwuDB 支持的各种数据类型;t1
列作为 KaiwuDB 时序表的主标签列使用。@Data @Entity @Table(name = "tsdb_table") public class TsdbEntity { @Id @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss.SSS", timezone = "GMT+8") private Timestamp ts; private Short c1; private Integer c2; private Long c3; private Float c4; private Double c5; private Boolean c6; private String c7; private String c8; private String c9; private String c10; private String c11; @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss.SSS", timezone = "GMT+8") private Timestamp c12; private Integer t1; }
在
repository
目录下定义数据访问层。示例:
@Repository public interface TsdbEntityRepository extends JpaRepository<TsdbEntity, Timestamp> { TsdbEntity findByT1AndTs(@Param("t1") int t1, @Param("ts") Timestamp ts); List<TsdbEntity> findAll(); }
定义 Service 接口及实现。
在
service
目录下定义 Service 层接口。示例:
public interface TsdbService { int insert(TsdbEntity entity); int delete(int t1, String ts); TsdbEntity findByT1AndTs(int t1, String ts) throws Exception; List<TsdbEntity> findList(); }
在
service/impl
目录下定义 Service 实现类。说明
KaiwuDB 只支持显式事务内执行时序数据的查询以及写入,但不保证时序引擎的事务性,也不保证跨模查询结果的一致性。而 JPA 要求对事务的管理,对于 DML 语法的
INSERT
和DELETE
操作,需通过使用 JdbcTemplate 来实现。示例:
@Service class TsdbServiceImpl implements TsdbService { @Autowired private JdbcTemplate jdbcTemplate; @Autowired private TsdbEntityRepository repository; @Override public int insert(TsdbEntity entity) { String sql = "INSERT INTO tsdb_table (ts, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, t1) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; return jdbcTemplate.update(sql, entity.getTs(), entity.getC1(), entity.getC2(), entity.getC3(), entity.getC4(), entity.getC5(), entity.getC6(), entity.getC7(), entity.getC8(), entity.getC9(), entity.getC10(), entity.getC11(), entity.getC12(), entity.getT1()); } @Override public int delete(int t1, String ts) { String sql = "DELETE FROM tsdb_table WHERE t1 = ? AND ts = ?"; return jdbcTemplate.update(sql, t1, ts); } @Override public TsdbEntity findByT1AndTs(int t1, String ts) throws Exception { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); return repository.findByT1AndTs(t1, new Timestamp(sdf.parse(ts).getTime())); } @Override public List<TsdbEntity> findList() { return repository.findAll(); } }
在
controller
目录下定义 Controller 层。示例:
@RestController @RequestMapping("tsdb") public class TsdbController { @Autowired private TsdbService service; @PostMapping("add") public String add(@RequestBody TsdbEntity entity) { try { if (entity == null) { return "获取时序数据失败!"; } if (entity.getTs() == null || entity.getT1() == null) { return "时间列和Tag列不允许为空!"; } int rows = service.insert(entity); if (rows < 1) { return "添加时序数据失败!"; } return "添加时序数据成功, 影响行数: " + rows; } catch (Exception e) { return e.getMessage(); } } @DeleteMapping("delete") public String delete(@RequestParam(value = "t1") Integer t1, @RequestParam(value = "ts") String ts) { try { int rows = service.delete(t1, ts); if (rows < 1) { return "删除时序数据失败!"; } return "删除时序数据成功, 影响行数: " + rows; } catch (Exception e) { return e.getMessage(); } } @GetMapping("get") public TsdbEntity get(@RequestParam(value = "t1") Integer t1, @RequestParam(value = "ts") String ts) throws Exception { return service.findByT1AndTs(t1, ts); } @GetMapping("list") public List<TsdbEntity> list() { return service.findList(); } }
验证操作
- 添加数据
- 删除数据
- 查询指定主标签和时间的数据详情
- 查询全部数据集合
- 添加数据
关系库
在
application.yml
文件配置数据源,指定使用的方言包。示例:
spring: datasource: driver-class-name: com.kaiwudb.Driver url: jdbc:kaiwudb://127.0.0.1:26257/test_rdb username: <user_name> password: <password> jpa: open-in-view: false hibernate: ddl-auto: update show-sql: true database-platform: org.hibernate.dialect.KaiwuDBDialect server: port: 9002
在
entity
目录下定义映射表结构的实体类,例如RdbEntity.java
。示例:
示例中,@Table 标签中的
name
指定了对应的关系表名称rdb_table
,表内字段对应了目前 KaiwuDB 支持的大部分数据类型。其中id
字段使用 SEQUENCE 自动生成,因此需要添加以下两个注解来指定使用的 SEQUENCE:@SequenceGenerator(name = "sequence", sequenceName = "rdb_table_id", allocationSize = 1) @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence")
@Data @Entity @Table(name = "rdb_table") @SequenceGenerator(name = "sequence", sequenceName = "rdb_table_id", allocationSize = 1) public class RdbEntity { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence") private Integer id; private Short c1; private Integer c2; private Long c3; private Float c4; private Double c5; private Boolean c6; private String c7; private String c8; private String c9; private String c10; private String c11; @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss.SSS", timezone = "GMT+8") private Timestamp c12; }
其中创建示例中的关系表和 SEQUENCE 的语法如下:
CREATE SEQUENCE rdb_table_id START 1 INCREMENT 1; CREATE TABLE test_rdb.rdb_table ( id int PRIMARY KEY DEFAULT nextval('rdb_table_id'), c1 smallint, c2 int, c3 bigint, c4 float4, c5 float8, c6 bool, c7 char(1), c8 nchar(10), c9 varchar(10), c10 nvarchar(10), c11 bytes, c12 timestamp );
在
repository
目录下定义数据访问层。示例:
@Repository public interface RdbEntityRepository extends JpaRepository<RdbEntity, Integer> { @Override <S extends RdbEntity> S saveAndFlush(S entity); @Override void deleteInBatch(Iterable<RdbEntity> list); RdbEntity getById(@Param("id") Integer id); List<RdbEntity> findAll(); }
定义 Service 接口及实现。
在
service
目录下定义 Service 层接口。示例:
public interface RdbService { RdbEntity save(RdbEntity entity); void delete(List<RdbEntity> list); RdbEntity findById(Integer id); List<RdbEntity> findList(); }
在
service/impl
目录下定义 Service 实现类。示例:
@Service class RdbServiceImpl implements RdbService { @Autowired private RdbEntityRepository repository; @Override public RdbEntity save(RdbEntity entity) { return repository.saveAndFlush(entity); } @Override public void delete(List<RdbEntity> list) { repository.deleteInBatch(list); } @Override public RdbEntity findById(Integer id) { return repository.getById(id); } @Override public List<RdbEntity> findList() { return repository.findAll(); } }
在
controller
目录下定义 Controller 层。示例:
@RestController @RequestMapping("rdb") public class RdbController { @Autowired private RdbService service; @PostMapping("add") public String add(@RequestBody RdbEntity entity) { try { if (entity == null) { return "获取关系数据失败!"; } return "添加关系数据成功:\n " + Json.pretty(service.save(entity)); } catch (Exception e) { return e.getMessage(); } } @DeleteMapping("delete") public String delete(@RequestParam(value = "id") Integer id) { try { RdbEntity entity = service.findById(id); if (entity == null) { return "关系数据不存在."; } service.delete(Collections.singletonList(entity)); return "删除关系数据成功."; } catch (Exception e) { return e.getMessage(); } } @GetMapping("get") public RdbEntity get(@RequestParam(value = "id") Integer id) throws Exception { return service.findById(id); } @GetMapping("list") public List<RdbEntity> list() { return service.findList(); } }
验证操作
- 添加数据
- 删除数据
- 查询指定时间的数据
- 查询全部数据集合
- 添加数据