#Hibernate
Hibernate是一个开源的对象映射关系(ORM)框架,适配Java程序,该框架使得开发者可以采用面向对象的方式操作数据库,且无需编写JDBC代码。本文将以构建一个Maven项目为例,介绍如何实现YashanDB与Hibernate的对接,从而实现利用Hibernate框架进行基于YashanDB的Java应用开发。
# 对接前准备
在进行对接操作前,您需要先准备好如下事项:
已安装Jdk8的Java应用环境。
已安装Springboot 1.x。
已安装Maven 3.8。
已安装Hibernate-core-5.x。
已在YashanDB官网下载中心 (opens new window)下载YashanDB JDBC驱动包。
已向我们的技术支持人员获取YashanDialect-for-hibernate5方言包。
已存在一个可正常访问的YashanDB服务端。
# 对接配置
请参照如下步骤进行YashanDB与Hibernate的对接配置:
检查Maven核心配置文件pom.xml中是否指定了如下依赖项,没有则加上:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- spring jpa,里面包含了hibernate核心类 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!-- lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies>以IDEA编辑器为例,从IDEA的菜单中,选择【 File > Project Structure > Libraries】。
单击【+】,并选择【Java】,从本地选择已准备的YashanDB JDBC驱动包完成库添加;如为多模块项目,只需要选择相应的模块执行本操作。
用上述相同的方式添加YashanDialect-for-hibernate5方言包。
编辑application.properties文件进行参数配置(请将下例中的host_ip、port、username和password修改为实际值):
spring.datasource.url=jdbc:yasdb://host_ip:port/yasdb spring.datasource.username=username spring.datasource.password=password spring.datasource.driver-class-name=com.yashandb.jdbc.Driver # 方言必须设置为崖山方言YasDialect spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.YasDialect # 是否自动建表 spring.jpa.properties.hibernate.hbm2ddl.auto=create # 字段名和数据库中对象名的映射关系:驼峰转下划线 spring.jpa.properties.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy
# 简单使用示例
上述对接配置完成后,开发者即可开始定义Java对象与YashanDB对象进行映射,以下为一个简单的实现示例:
在YashanDB中创建如下表对象:
-- 建表语句 CREATE TABLE user1 ( id INT PRIMARY KEY, name VARCHAR(30) NULL ); -- 预置5条数据 INSERT INTO USER1 (id, name) VALUES (1, 'Jone'), (2, 'Jack',), (3, 'Tom',), (4, 'Sandy'), (5, 'Billie');创建User实体类,并使其与YashanDB的user1表对应。
import lombok.Data; import org.hibernate.annotations.ColumnDefault; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.SequenceGenerator; import javax.persistence.Table; import java.time.LocalTime; @Data @Entity @Table(name = "user1") public class User { @Id // hibernate要求实体类中必须定义一个id属性,否则会报错。该属性被作为业务表的自增主键列 @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ID_GENERATOR") @SequenceGenerator(name = "ID_GENERATOR", sequenceName = "user_sequence") //user_sequence为序列名,可自定义命名 @ColumnDefault("user_sequence.nextval") //序列名称需与@SequenceGenerator中的sequenceName一致 private int id; @Column(name = "name") private String name; public User() { } public User(String name) { this.name = name; } public User(int id, String name) { this.id = id; this.name = name; } }实现Repository接口,可自由选择继承JpaRepository,或者继承CrudRepository。
import com.example.pojo.User; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface UserRepository extends JpaRepository<User,Integer> { // 注意JpaRepository<User,Integer>这里传入的泛型类型,第一个是上面定义的Entity,第二个是Entity的主键的类型 // JpaRepository中可以不实现任何接口,其默认接口已足够使用。 }创建单元测试类。
package com.example; import com.example.dao.UserRepository; import com.example.pojo.User; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.List; import static org.junit.Assert.assertEquals; @RunWith(SpringRunner.class) @SpringBootTest public class UserTest { @Autowired private UserRepository repository; @Before public void deleteAllUser(){ repository.deleteAll(); } @Test public void testAddUser() { User user = new User("sasa"); repository.save(user); List<User> list = repository.findAll(); assertEquals(1, list.size()); } }
# 常见问题
# 序列器名称不一致导致启动时建表失败
在定义实体类的Id属性时,@SequenceGenerator和@ColumnDefault中均指定了序列器名称,但Hibernate存在如下机制:
@SequenceGenerator中的sequenceName指定的序列名是驼峰格式时,Hibernate会将其转为下划线格式。
@ColumnDefault注解的value是驼峰格式时,Hibernate不做处理。
因此,如开发者使用驼峰格式命名一个序列器时,上述机制会导致两个注解使用了不一致的序列器名称。
解决办法:对序列器统一采用下划线风格命名;或者不指定@ColumnDefault和@SequenceGenerator,此时Hibernate使用默认序列hibernate_sequence进行Id自增,但同时需修改@GeneratedValue为如下value:
@GeneratedValue(strategy= GenerationType.AUTO)
# 数据类型校验失败导致服务启动失败
在Hibernate的hbm2ddl.auto配置项被定义为validate的情况下(如下),启动服务时会进行数据库表结构数据类型与Java实体类数据类型的一致性校验;不一致时,会由于Schema-validation校验失败,从而导致容器初始化Hibernate SessionFactory时失败。
spring.jpa.properties.hibernate.hbm2ddl.auto=validate
出现这个问题时,解决方案如下:
方案一:需要修改数据库表结构或Java实体类数据类型,保持数据库表结构与Java实体类数据类型一致。
方案二:将hbm2ddl.auto配置设置为none,服务启动时不进行校验。
# YashanDB中不存在的数据类型报错
通常不同品牌的数据库在数据类型定义上存在差异,例如MySQL中存在TEXT数据类型而YashanDB无此类型。因此,当复制了其他数据库类型定义到YashanDB的映射中时,可能会因为YashanDB中不存在该数据类型而报错。
解决办法:在YashanDB中找一个虽定义不同但规格相近的数据类型进行替代。
例如,对于MySQL中的TEXT类型,YashanDB中存在CLOB类型同样可用于保存大量字符数据,因此可使用CLOB类型代替MySQL中的TEXT数据类型,如下:
//将columnDefinition = "TEXT"改为columnDefinition = "CLOB"
@Column(name = "file_types", columnDefinition = "CLOB")
private String fileTypes;
# 特殊字符乱码
在服务端的字符集被指定为GBK时,YashanDB通常会使用NCHAR、NVARCHAR或NCLOB类型来存储那些解析时可能出现乱码的特殊字符文本值,但在通过Hibernate插入数据时,由于绑定参数的String类型默认为setString,导致无法避免乱码现象。
此类场景下,可以按需选择以下解决方案:
方案一:在对应字段上加@Nationalized注解。
方案二:在对应字段上加@Type(type = "org.hibernate.type.StringNVarcharType")注解。

