Hibernate 框架

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

Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的JavaEE架构中取代CMP,完成数据持久化的重任。

Hibernate 中只需要通过“方言”的形式指定当前使用的数据库,就可以根据底层数据库的实际情况生成适合的 SQL 语句。因此在使用 Hibernate 连接数据库时,我们主要关注的配置就是数据库方言这个参数。

Hibernate 使用 HGDB,只需要将“方言”这个配置参数,改为 HGDB 方言即可。

开发环境搭建

软件 版本
HGDB 安全版V4、企业版v5及以上版本
JDK 1.6、1.7、1.8
Java IDE Eclipse、IntelliJ IDEA

HGDB 针对 Hibernate 框架,封装了 HGDB 方言包,现有的 Hibernate HGDB方言包支持的 Hibernate 版本,如下图所示:

image-20220418151105678

Hibernate HGDB 方言包的说明,如下:

使用说明
HGDB 方言包是用于使用 Hibernate 开发提供支持的,该方言包使用依赖hibernate-core,因此需要应用程序中已经添加了相关的依赖包后才能使用。HGDB 方言包使用配置:org.hibernate.dialect.HgdbDialect

版本说明
HGDB 方言包使用依赖 hibernate-core,所以方言包的版本需要与hibernate-core 的版本对应,对应规则为:HGDB 方言包 jar 包名字末尾的编号即是对应的 hibernate-core 的版本号。

例:hgdb-hibernate-dialect-5.4.0.jar,需要对应使用 hibernate-core 的 5.4.0 版本。

编译环境说明

HGDB 的所有方言包均使用 jdk1.6 进行编译,所以需要在 jdk1.6 或以上的环境中使用。如果使用的 hibernate 版本在 HGDB 方言包的版本中不存在,请修改一下项目的 hibernate 版本,只要 hibernate 的大版本号一致,基本就没有问题。

Hibernate引入 HGDB 方言包

以maven 仓库方式为例:

mvn install:install-file -Dfile=C:\***\hgdb-hibernate-dialect-4.3.11.jar -DgroupId=highgo -DartifactId=hgdb-hibernate-dialect -Dversion=4.3.11 -Dpackaging=jar

## C:\***\hgdb-hibernate-dialect-4.3.11.jar 为本地绝对路径

执行结果,如下:

image-20220418152525445

示例项目

结构图如下:

image-20220516191541275

主要文件介绍

pom.xml:添加依赖(仅为片段部分)

<!-- hibernate配置-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.3.11.Final</version>
</dependency>
<!-- HGDB的方言包-->
<dependency>
<groupId>highgo</groupId>
<artifactId>hgdb-hibernate-dialect</artifactId>
<version>4.3.11</version>
</dependency>
<!-- HGDB jdbc-->
<dependency>
<groupId>highgo</groupId>
<artifactId>highgo</artifactId>
<version>5.0-42</version>
</dependency>

hibernate.cfg.xml:Hibernate的核心配置文件,主要用来描述Hibernate的相关配置

<hibernate-configuration>
<!--构造数据库的连接工厂-->
<session-factory>
<!-- 配置关于数据库连接信息 driverClass url username password仅为参考 -->
<property name="hibernate.connection.driver_class"><>com.highgo.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:highgo://localhost:5866/hibernateTest</property>
<property name="hibernate.connection.username">test</property>
<property name="hibernate.connection.password">test</property>
<!-- 可以将向数据库发送的sql显示出来 -->
<property name="hibernate.show_sql">true</property>
<!-- 格式化sql -->
<property name="hibernate.format_sql">true</property>
<!-- hibernate的方言,修改为 HGDB的方言包 -->
<property name="hibernate.dialect">org.hibernate.dialect.HgdbDialect</property>
<!-- 配置hibernate的映射文件所在位置 -->
<mapping resource="com/highgo/entitty/User.hbm.xml" />
</session-factory>
</hibernate-configuration>

User.hbm.xml:映射文件

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping
package="com.highgo.entity">

<class name="User" >
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<property name="birthday"/>

</class>

</hibernate-mapping>

User.java:实体bean

public class User {
private int id;
private String name;
private Date birthday;

public int getId() {
return id;
}

public String getName() {
return name;
}

public Date getBirthday() {
return birthday;
}

public void setId(int id) {
this.id = id;
}

public void setName(String name) {
this.name = name;
}

public void setBirthday(Date birthday) {
this.birthday = birthday;
}

@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", birthday=" + birthday
+ "]";
}
}

MainTest.java:测试类

public class MainTest {
public static void main(String[] args) {
try {
Configuration conf=new Configuration();
SessionFactory sessionFactory= conf.configure().buildSessionFactory();
Session session=sessionFactory.openSession();
Transaction tx=session.beginTransaction();
User user=new User() ;
user.setName("张三");
user.setBirthday(new Date());
session.save(user);
tx.commit();
session.close();
//获取数据集合
Transaction tx1=session.beginTransaction();
Criteria criteria =session.createCriteria(User.class);
List<User> list = criteria.list();
//使用forEach遍历集合
for (User userEntity : list) {
System.out.println(userEntity);
}
tx1.commit();
} catch (Exception e) {
e.printStackTrace();
}
}
}

执行结果:

image-20220418172933992

image-20220418173905608

注意事项

Hibernate主键生成策略

Hibernate要求实体类里面有一个属性作为唯一值,对应表主键,提供了多种主键的生成方式,具体有哪些以下做简单介绍。

一、在映射配置文件中指定主键生成策略

<class name="User"  table="test_user">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<property name="birthday"/>
</class>

二、常见的主键生成策略

策略名称 说明
Assigned Assigned方式由用户生成主键值,并且要在save()之前指定否则会抛出异常。
特点:主键的生成值完全由用户决定,与底层数据库无关。用户需要维护主键值,在调用session.save()之前要指定主键值。
Hilo Hilo使用高低位算法生成主键,高低位算法使用一个高位值和一个低位值,然后把算法得到的两个值拼接起来作为数据库中的唯一主键。Hilo方式需要额外的数据库表和字段提供高位值来源。默认情况下使用的表是hibernate_unique_key,默认字段叫作next_hi。next_hi必须有一条记录否则会出现错误。
特点:需要额外的数据库表的支持,能保证同一个数据库中主键的唯一性,但不能保证多个数据库之间主键的唯一性。Hilo主键生成方式由Hibernate 维护,所以Hilo方式与底层数据库无关,但不应该手动修改hi/lo算法使用的表的值,否则会引起主键重复的异常。
Increment Increment方式对主键值采取自动增长的方式生成新的主键值,但要求底层数据库的主键类型为long,int等数值型。主键按数值顺序递增,增量为1。
特点:由Hibernate本身维护,适用于所有的数据库,不适合多进程并发更新数据库,适合单一进程访问数据库。不能用于群集环境。
Identity Identity方式根据底层数据库,来支持自动增长,不同的数据库用不同的主键增长方式。
特点:与底层数据库有关,要求数据库支持Identity,如MySQl中是auto_increment, SQL Server 中是Identity,支持的数据库有MySql、SQL Server、DB2、Sybase和HypersonicSQL。 Identity无需Hibernate和用户的干涉,使用较为方便,但不便于在不同的数据库之间移植程序。
Sequence Sequence需要底层数据库支持Sequence方式,例如Oracle数据库等
特点:需要底层数据库的支持序列,支持序列的数据库有DB2、PostgreSql、Oracle、SAPDb等在不同数据库之间移植程序,特别从支持序列的数据库移植到不支持序列的数据库需要修改配置文件。
Native Native主键生成方式会根据不同的底层数据库自动选择Identity、Sequence、Hilo主键生成方式
特点:根据不同的底层数据库采用不同的主键生成方式。由于Hibernate会根据底层数据库采用不同的映射方式,因此便于程序移植,项目中如果用到多个数据库时,可以使用这种方式。
UUID UUID使用128位UUID算法生成主键,能够保证网络环境下的主键唯一性,也就能够保证在不同数据库及不同服务器下主键的唯一性。
特点:能够保证数据库中的主键唯一性,生成的主键占用比较多的存贮空间

三、常见问题

遇到的问题:项目有mysql迁移到HGD环境时,提示ERROR: relation "HIBERNATE_SEQUENCE" does not exist

经查证,Hibernate中的实体类使用native方式生成主键时,native是由Hibernate根据使用的数据库自行判断采用identity、hilo、sequence其中一种作为主键生成方式。而HGDB数据库没有类似的自增类型,因此需要手动创建一个名称为hibernate_sequence的序列做支持。

create sequence HIBERNATE_SEQUENCE
minvalue 1
maxvalue 9999999999999999
start with 1
increment by 1
cache 20;