3. KES与hibernate

3.1 Hibernate简介

Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的ORM框架,Hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以熟练地使用对象编程思维来操纵数据库。

3.2 Hibernate支持的KES形态

框架名称

方言包

驱动形态

Hibernate

提供

KES、PG形态

3.3 Hibernate驱动包和方言包

KES提供了 Hibernate 的方言类 Kingbase8Dialect,目前KES共提供了以下几个方言包来支持Hibernate:

方言包

适用范围(hibernate版本)

hibernate-2.0.dialect.jar

2.0<=适用范围<2.1

hibernate-2.1.dialect.jar

2.1<=适用范围<3.0

hibernate-3.0.dialect.jar

3.0<=适用范围<3.0.3

hibernate-3.0.3.dialect.jar

3.0.3<=适用范围<3.6.0

hibernate-3.6.dialect.jar

3.6.0<=适用范围<4.0

hibernate-4.dialect.jar

4.0<=适用范围<5.0

hibernate-5.dialect.jar

5.0<=适用范围<6.0

hibernate-6.0.dialect.jar

6.0<=适用范围

Kingbase8Dialect位于 $KINGBASE_HOME/Interface/hibernate/ 目录中。 使用时将hibernatexxxdialect.jar导入到项目的Libraries中并定义相关配置项即可。

3.4 Hibernate开发流程

hibernate首先通过配置文件cfg.xml初始化数据库,创建SessionFactory,进而得到session也就是一个数据库连接。 cfg文件中包括数据库驱动、URL、数据库名称以及密码等等参数,最重要的是将表或者视图的hbm文件写入cfg文件,否则是无法使用Hibernate服务的。 当用户操作数据库表或视图的时候,hibernate加载此表的hibernate mapping文件,也就是hbm.xml文件。hbm文件主要是映射数据库表与持久化类POJO。 通过hbm文件可以将实体对象与数据库表或者视图对应,从而间接的操作数据库表或者视图。

上图是Hibernate 使用原理图 

3.5 Hibernate 环境配置

本章描述如何配置Hibernate的开发环境,包括工程搭建、配置文件、配置方法和参数。

3.5.1 Hibernate工程搭建

要使用Hibernate进行开发,需要先搭建环境。以下两种方法均可完成搭建环境:

创建好项目之后,在/lib 目录下导入hibernate的核心jar包以及hibernatexxxdialect.jar方言包。

使用Maven工具来管理jar包,修改pom.xml配置来导入hibernate核心jar包以及hibernatexxxdialect.jar方言包。

修改pom.xml配置内容如下:

<dependency>

<groupId>cn.com.kingbase</groupId>

<artifactId>KesDialect-for-hibernate2.0</artifactId>

<version>1.0.0</version>

</dependency>

<dependency>

<groupId>cn.com.kingbase</groupId>

<artifactId>KesDialect-for-hibernate2.1</artifactId>

<version>1.0.0</version>

</dependency>

<dependency>

<groupId>cn.com.kingbase</groupId>

<artifactId>KesDialect-for-hibernate3.0</artifactId>

<version>1.0.0</version>

</dependency>

<dependency>

<groupId>cn.com.kingbase</groupId>

<artifactId>KesDialect-for-hibernate3.0.3</artifactId>

<version>1.0.0</version>

</dependency>

<dependency>

<groupId>cn.com.kingbase</groupId>

<artifactId>KesDialect-for-hibernate3.6.0</artifactId>

<version>1.0.0</version>

</dependency>

<dependency>

<groupId>cn.com.kingbase</groupId>

<artifactId>KesDialect-for-hibernate4</artifactId>

<version>1.0.0</version>

</dependency>

3.5.2 Hibernate单独配置方式

定义 hibernate 配置文件,根据用户选择更改以下配置文件。

在hibernate.properties 中增加如下声明:

hibernate.dialect = org.hibernate.dialect.Kingbase8Dialect

在hibernate.cfg.xml 中增加如下声明:

<property name="dialect">org.hibernate.dialect.

Kingbase8Dialect</property>

在persistence.xml 中增加如下声明:

<property name="hibernate.dialect"

value="org.hibernate.dialect.Kingbase8Dialect" />

注意:hibernatexxxdialect.jar 方言包全部依赖于1.6以上版本JDK生成。

3.5.3 Hibernate和Spring集成配置方式

Spring配置Hibernate方言包:

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">

<property name="hibernateProperties">

<props>

<prop key="hibernate.dialect">org.hibernate.dialect.Kingbase8Dialect</prop>

<prop key="hibernate.hbm2ddl.auto">update</prop>

<prop key="hibernate.show_sql">true</prop>

<prop key="hibernate.format_sql">true</prop>

</props>

</property>

</bean>

Spring-Boot配置Hibernate方言包:

spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.Kingbase8Dialect

spring.jpa.hibernate.ddl-auto = update

spring.jpa.show-sql = true

3.5.4 服务的配置方法和参数说明

Hibernate配置文件示例:

<?xml version='1.0' encoding='UTF-8'?>

<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate

Configuration DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

<session-factory>

<property name="hbm2ddl.auto">create-drop</property>

<property name="show_sql">true</property>

<property name="use_sql_comments">false</property>

<property name="dialect">org.hibernate.dialect.Kingbase8Dialect

</property>

<property name="connection.driver_class">com.kingbase8.Driver

</property>

<property name="connection.url">jdbc:kingbase8://localhost:54321/

test</property>

<property name="connection.username">test</property>

<property name="connection.password">test</property>

<mapping resource="hibernate_test.hbm.xml"/>

</session-factory>

</hibernate-configuration>

配置时按照实际使用情况修改 "dialect" 、 "connection.driver_class" 等参数。

3.6 Hibernate编程指南

本章节列举了部分使用Hibernate进行的开发程序示例。

3.6.1Hibernate映射文件示例

下例程序为Hibernate的映射文件配置:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping

DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

<class name="hibernate_test.TestDb" table="hibernate_test">

<id name="id" column="id">

<generator class="increment"/>

</id>

<property name="username" column="username" />

<property name="btest" column="btest" />

</class>

</hibernate-mapping>

3.6.2 Hibernate的java对象示例

下例为Hibernate的Java对象示例:

package hibernate_test;

public class TestDb {

private String username;

private Long id;

private boolean btest;

public Long getId() {

return id;

}

public void setId(Long id) {

this.id = id;

}

public String getUsername() {

return username;

}

public void setUsername(String myname) {

this.username = myname;

}

public boolean getBtest() {

return btest;

}

public void setBtest(boolean bbtest) {

this.btest = bbtest;

}

}

3.6.3Hibernate的java使用示例

下例为Hibernate的Java使用示例

/* 定义参数 */

String name = "username";

Long id = 0;

boolean btest = false;

/* 连接 DB */

SessionFactory sessionFactory = new Configuration().configure()

.buildSessionFactory();

Session session = sessionFactory.openSession();

Transaction tx = session.beginTransaction();

/* 新建一行数据插入 hibernate_test表 */

TestDb user = new TestDb();

user.setUsername(name);

user.setId(id);

user.setBtest(btest);

session.save(user);

/* 从hibernate_test表中查询数据 */

TestDb obj = (TestDb) session.load(TestDb.class, new Long(id));

System.out.println(obj.getUsername());

/* 更新数据 */

tx = session.beginTransaction();

obj = (TestDb) session.load(TestDb.class, new Long(id));

obj.setUsername("update_test" + id);

session.update(obj);

tx.commit();

3.7 Hibernate注意事项

  1. HQL(JPA QL)不支持KingbaseES特有的函数,包括:TO_HEX、UNICODE、SETSEED、STRPOS、GET_BIT、GET_BYTE、SET_BIT、SET_BYTE、EMPTY_BLOB、EMPTY_CLOB、CAST、ARRAY_NDIMS、ARRAY_FILL、UNNEST和ARRAY_LENGTH等。
  2. HQL(JPA QL)不支持某些操作符,包括:+、^、%、&、|、||、#和~等,以及UNION、UNION ALL、INTERSECT、EXCEPT。
  3. 不支持INTERVAL数据类型以及返回值为INTERVAL的系统函数,包括:AGE、DATE_FORMAT、ISFINITE、STR_VALID和TIMEOFDAY。
  4. 对于近义的系统函数,只支持常用的名称,例如:sqrt(dsqrt)、cbrt(dcbrt)等。
  5. 对于重载的系统函数,只支持常用的参数及返回值类型,例如:LEFT(expr1 TEXT, expr2 INTEGER)、REPLICATE(expr1 TEXT, expr2 INTEGER)、RIGHT(expr1 TEXT, expr2 INTEGER)和SUBSTRING(expr1 TEXT, [FROM] expr2 INTEGER[,[FOR] expr3 INTEGER])等。
  6. 使用原生查询时,某些函数的返回值与KingbaseES有差异,例如:SIGN()应返回整型值但实际返回浮点型。
  7. 只有在查询时才可使用Query.getSingleResult() 方法,例如因为该方法会添加Limit子句,call function() 执行函数取返回值时使用该方法会构造一个不合法的SQL语句。
  8. 3.0.3和4两个版本的方言包中还包含一个名称为KingbaseBooleanDialect的方言包,该方言包用于hibernate使用Java的boolean类型映射数据库的numeric类型且使用hibernate默认的BooleanType时,hibernate执行操作可以将hql中boolean类型的true或者false转换成1或者0。 如:HQL语句 select p.name FROM Person p where p.sex=true 会转换为SQL语句 select person0_.name as col_0_0_ from person person0_ where person0_.sex=1 。

3.8 常见问题

  • Springboot JPA配置方言包问题

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource

Caused by: org.hibernate.HibernateException: Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set

Hibernate SQL方言没有设置导致的,在properties文件中增加下面这行:

spring.jpa.database-platform=org.hibernate.dialect.Kingbase8Dialect或者

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.Kingbase8Dialect

  • Hibernate控制输出真实SQL日志

编辑hibernate.cfg.xml,配置方法:

  1. 参数:show_sql=true 打印SQL语句;

2、参数:format_sql=true 使SQL语句格式更加美观统一;

3、参数:use_sql_comments=true 使SQL语句中自动注入注释,增加可读性。

<property name="show_sql">true</property> //控制台打印SQL语句

<property name="format_sql">true</property> //格式化SQL语句

<property name="use_sql_comments">true</property> //指出是什么操作生成了该语句

  • 表取名user怎么规避?

在映射上@Table(name=“t_user")换个名字或者@Table(name="user",schema="xxx")显示指定模式名。

  • Hibernate的hql不支持部分数据库函数的使用

1.将hql语句转换为sql语句,createQuery使用的是hql,createSQLQuery使用的是sql语句;

2.在方言包里注册函数解决。

  • V8 Hibernate非法long值问题

这个问题是由于V8 hibernate把TEXT类型默认对应到CLOB类型处理,但是CLOB是通过OID来访问的,所以造成类型转换报错。解决办法更换新的方言包,新的dialect。

  • Hibernate 无法确定参数类型$1

1.使用cast函数对于不识别的类型进行强转,如cast(? as timestamp),as后面的类型需要为hibernate类型,hibernate类型自行百度。

2.对于V7,这个问题可能是用户打开了Hibernate的SQL注释功能,改为false即可。

<property name="use_sql_comments">false</property>

parse JDBC_STATEMENT_7: /* from TestDb where username=$1 */ select testdb0_.id as id0_, testdb0_.username as username0_, testdb0_.btest as btest0_ from hibernate_test testdb0_ where testdb0_.username=$2

ERROR: could not determine data type of parameter $1

  • Hibernate 错误: 字段的类型为 TEXT, 但表达式的类型为 BYTEA你需要重写或转换表达式

这个问题原因是JDBC指定了bytea的OID传给服务器,而服务器实际字段类型是TEXT,不支持类型转换。

查看hibernate源码:

public Query setParameter(int position, Object val) throws HibernateException {

if (val == null) {

setParameter( position, val, Hibernate.SERIALIZABLE );

}

}

看出对于null值,hibernate都是按照Hibernate.SERIALIZABLE类型处理。而Hibernate.SERIALIZABLE类型使用Hibernate.BINARY.set(st, toBytes(value), index)。

Hibernate.BINRAY底层使用JDBC的setBinaryStream或者setBytes绑定参数。

解决办法:JDBC直接修改所有Bind参数传bytea的地方都改成0。如仍需绑定为bytea,可通过连接参数bytestype=bytea来指定。

  • Hibernate设置为update已经建好表,仍旧去建表

原因为使用了大小写不敏感的数据库,在大小写不敏感的库中,查询返回的表名与建表时的大小写保持一致。如果建表时使用小写,Hibernate查询返回的表名为小写,本地的表名是转为大写去比较,找不到所以会去建表,请改为大小写敏感的数据库。

修改后可能存在的问题:

1.索引重复创建

应用可能是从MySQL、SQLServer迁移过来的。索引名称在某些数据库中(如 MySQL、SQLServer),索引是以表为维度创建的,在不同的表中的索引是可以重名的; 而在另外的一些数据库中(如 PostgreSQL、Oracle、KingbaseES),索引是以数据库为维度创建的,即使是作用在不同表上的索引,它们也要求其名称的唯一性。所以需要修改索引名称。

  • 控制台报错

java.lang.NoSuchMethodError: javax.persistence.Table.indexes()[Ljavax/persistence/Index;

jar包冲突,有多个jar包存在javax/persistence/Index类。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐