Hibernate概述
Hibernate框架是当今主流的Java持久层框架之一,是一个开源的ORM(Object Relational Mapping,对象惯性映射)框架,它对JDBC进行了轻量级的对象封装,使得Java开发人员可以使用面向对象的编程思维来操作数据库。
与其他操作数据库的技术相比,Hibernate具有以下几点优势:
- Hibernate对JDBC访问数据库的代码做了轻量级封装,大大简化了数据访问层的繁琐的重复性代码,并且减少了内存消耗,加快了运行效率。
- Hibernate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现,它很大程度上简化了DAO(Data Access Object)层的编码。
- Hibernate性能非常好,映射的灵活性很出色。它支持很多关系型数据库,从一对一到多对多的各种复杂关系。
- 可扩展性强。
Mybatis与Hibernate对比:
Mybatis | Mybatis | |
---|---|---|
针对高级查询 | 映射机制 | 手动编写SQL |
开发难度 | 开发难度相对较大 | 开发难度相对简单 |
日志统计 | 有日志统计 | 没有日志统计 |
数据库扩展性 | XML关联 | 扩展性、迁移性较差 |
缓存机制 | 工厂生产配置文件 | 映射中配置 |
Mytais:小巧、方便、高效、简单、直接、半自动
Hibernate:强大、方便、高效、复杂、绕弯、全自动
Hibernate快速开始
引入依赖
在官网(https://hibernate.org/orm/releases/)有详细说明,注意如果使用JDK1.8则最高只能下载Hibernate5,从Hibernate6开始至少需要JDK11,最新的Hibernate7则是要求JDK17起步,这里使用Hibernate5进行演示。鉴于日常的Java项目几乎都是基于Maven/Gradle开发,展示他们的坐标引入方法。当然如果你的项目没有使用这些框架进行构建,你也可以在官网中下载压缩包进行解压安装,最后手动配置。
-
Gradle:
dependencies { implementation platform "org.hibernate.orm:hibernate-platform:5.6.15.Final" // use the versions from the platform implementation "org.hibernate.orm:hibernate-core" implementation "jakarta.transaction:jakarta.transaction-api" }
-
Maven:
<dependencies> <!--Hibernate5最后版本,此后Hibernate都不再兼容jdk1.8--> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.6.15.Final</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.infinispan</groupId> <artifactId>infinispan-directory-provider</artifactId> <version>9.0.1.Final</version> </dependency> <!--注意这个依赖的版本必须与自己数据库的版本一致--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.28</version> </dependency> <dependency> <groupId>jakarta.xml.bind</groupId> <artifactId>jakarta.xml.bind-api</artifactId> <version>2.3.2</version> </dependency> <dependency> <groupId>org.glassfish.jaxb</groupId> <artifactId>jaxb-runtime</artifactId> <version>2.3.5</version> </dependency> </dependencies>
创建实体
在src目录下创建一个包,并且在包中创建一个Customer类进行演示,Customer类包含了cst_customer数据表字段对应的属性,以及get、set方法。
public class Customer{
private Long cust_id;
private String cust_name;
private String cust_source;
private String cust_industry;
private String cust_level;
private String cust_phone;
private String cust_mobile;
//因为篇幅省略get、set方法
}
创建数据库和表
create database hibernate;
user hibernate;
CREATE TABLE 'cst_customer'{
'cust_id' bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)'
'cust_name' varchar(32) NOT NULL COMMENT '客户名称'
'cust_source' varchar(32) DEFAULT NULL COMMENT '客户信息来源'
'cust_industry' varchar(32) DEFAULT NULL COMMENT '客户所属行业'
'cust_level' varchar(32) DEFAULT NULL COMMENT '客户级别'
'cust_phone' varchar(64) DEFAULT NULL COMMENT '固定电话'
'cust_mobile' varchar(16) DEFAULT NULL COMMENT '移动电话'
PRIVATE KEY('cust_id')
}ENGINE=InnoDB AUTO_INCREMENT=94 DEFAULT CHARSET=UTF8
创建映射文件
实体类Customer目前还不具备持久化操作的能力,而Hibernate需要知道实体类Customer映射到数据库中的哪个表,以及类中的哪个属性对应数据库表中的哪个字段,这些都需要在映射文件中配置。
在实体类Customer所在的包中,创建一个名为Customer.hbm.xml的映射文件。在该文件中定义了实体类和Customer的属性是如何映射到cst_customer表的列上的。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTO 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3,0.dtd"
<hibernate-mappping>
<!-- 建立类和表的一个映射关系-->
<!--
class标签:用来建立类和表的映射
* name属性:类中的全路径
* table属性:表明(如果类名和表名一致,那么table属性可省略)
* catalog属性:数据库名字,可省略
-->
<class name="cn.itcast.domain.Customer" table="cst_customer">
<!-- 建立类中的属性与表中的主键的映射 -->
<!--
id标签:用来建立类中的属性和表中字段对应
* name属性:类中的属性名
* column属性:表中的字段名(如果类中的属性名和表中的字段名一致,那么column属性可省略)
* length属性:字段的长度
* type属性:类型。写Java数据类型,Hibernate数据类型(默认),SQL类型
-->
<id name="cust_id" column="cust_id">
<!-- 主键生成策略 -->
<generator class="native"/>
</id>
<!-- 建立类中的属性与表中的普通的映射 -->
<!--
property标签:用来建立类中的属性和表中字段对应
* name属性:类中的属性名
* column属性:表中的字段名(如果类中的属性名和表中的字段名一致,那么column属性可省略)
* length属性:字段的长度
* type属性:类型。写Java数据类型,Hibernate数据类型(默认),SQL类型
-->
<property name="cust_name" column="cust_name"/>
<property name="cust_source" column="cust_source"/>
<property name="cust_industry column="cust_property"/>
<property name="cust_level" column="cust_level"/>
<property name="cust_phone column="cust_phone"/>
<property name="cust_mobile" column="cust_mobile"/>
</class>
</hibernate-mapping>
创建核心配置文件
Hibernate的映射文件反应了持久化和数据库的表的映射信息,而Hibernate的配置文件则主要是用来配置数据库连接以及Hibernate运行时所需的各个属性的值。在项目中的src下创建一个名称为hibernate.cfg.xml的文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTO 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3,0.dtd"
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class"com,mysql.jdbc.Driver</property>
<property name="hibernate.connection.url"jdbc:mysql://hibernate_day01</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<!-- Hibernate的属性 -->
<!-- Hibernate的方言:作用,根据配置的方言生成相应的SQL语句-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Hibernate显示SQL语句 -->
<property name="hibernate.show_sql">true</property>
<!-- Hibernate格式化SQL语句 -->
<property name="hibernate.format_sql">true</property>
<!-- Hibernate加载映射 -->
<mapping resource="cn/itcast/domain/Customer.hbm.xml"/>
</session-factory>
</hibernate-configuration>
该配置文件设置了数据库连接的相关属性以及其他的一些常用属性,并且通过mapping的resorce属性将对象的映射信息加入到了Hibernate的配置文件中。
编写测试代码
在项目中新建一个test包,然后在包中建立一个名为HibernateDemo1.java文件,该文件是用来测试的。
public class HibernateDemo1{
@Test
public void demo1(){
//1.加载配置文件
Configuration cfg = new Configuration().configure();
//2.创建一个SessionFactory
SessionFactory sessionFactroy = cfg.buildSessionFactory();
//3.创建Session对象
Session session = sessionFactory.openSession();
//4.开启事务
Transaction tx = session.beginTransaction();
//5.执行业务逻辑
Customer customer = new Customer();
customer.setCust_name("张三");
customer.setCust_source("网络推广");
session.save(customer);
//6.事务提交
tx.commit();
//7.释放资源
session.close();
}
}
Hibernate的常见配置
Hibernate的配置文件,包含了连接持久层的映射文件所需要的基本信息,其配置文件有两种格式,具体如下:
- properties类型:properties属性文件格式的配置文件,它使用键值对的形式存放信息,默认文件名称是hibernate.properties。
- XML类型:XML配置文件的默认名称为hibernate.cfg.xml。
上述两种格式的配置文件效果想同。**XML配置文件更易修改,配置能力更强。**当改变底层配置时不需要重新编译代码,只需要修改配置文件的对应属性即可,而properties格式的文件则不具备此优势。
Hibernate常用配置属性:
名称 | 用途 |
---|---|
hibernate.dialect | 操作数据库方言 |
hibernate.connection.driver_class | 连接数据库驱动程序 |
hibernate.connection.url | 连接数据库URL |
hibernate.connection.username | 数据库用户名 |
hibernate.connection.password | 数据库密码 |
hibernate.show_sql | 在控制台上输出SQL语句 |
hibernate.format_sql | 格式化控制台输出的SQL语句 |
hibernate.connection.autocommit | 事务是否自动提交 |
Hibernate常见API
Configuration:配置对象
Configuration类的作用是对Hibernate进行配置,以及对它进行启动。在Hibernate的启动过程中,Configuration类的实例首先定位映射文档的位置,读取这些配置,然后创建一个SessionFactory对象。虽然Configuration类在整个项目中只扮演一个小角色,但是它是启动Hibernate时遇到的第一个对象。它会加载核心配置文件和映射文件。
Configuration config = new Configuration().configure("核心配置文件位置");
config,addResource("映射配置文件位置");
SessionFactory:Seesion工厂对象
SessionFactory接口负责Hibernate的初始化和建立Session对象。它充当数据存储源的代理,并且负责创建Session对象。这里用到了工厂模式。它在Hibernate中起到一个缓冲区的作用,Hibernate可以将自动生成的SQL语句,映射数据以及某些可重复利用的数据放在这个缓冲区中。同时它还保存了对数据库配置的所有映射关系,维护了当前的二级缓存。
SessionFactory sessionFactory = config.buildSessionFactory();
SessionFactory具有以下特点:
- 线程安全:它的同一个实例能提供多个线程共享。
- 重量级:不能随意的创建和销毁它的实例。
由于SessionFactory的这些特点,一般情况下,一个项目只需要一个SessionFactory,只有当应用中存在多个数据源时,才能为每个数据源建立一个SessionFactory实例。因此在实际项目中,我们通常会抽离出一个HibernateUtils工具类,用来提供Session对象。代码具体如下:
public class HibernateUtils{
private static final Configuration configuration;
private static final SessionFactory sessionFactory;
static{
configuration = new Configuration().configure();
sessionFactory = configuration.buildSessionFactory();
}
//提供获得session的方法
public static Session openSession(){
return sessionFactory.opensession();
}
}
SessionFactory内部还维护着一个连接池,如果我们还需要动刀第三方连接池如C3P0等可以手动配置,但在这儿不过多赘述。
Session:
Session是应用程序与数据库之间交互操作的一个单线程对象,是Hibernate运作的中心,它的主要功能是持久化创建对象提供创建、读取和删除的能力,所有的持久化对象必须在session的管理下才能进行持久化操作。
获取Session实例的方法有两种方式,如下:
//采取openSession方法创建session
Session session = sessionFactory().openSession();
//采取getCurrentSession()方法创建session
Session session = sessionFactory().getCurrentSession();
以上两种获取session实例方式的主要区别是:
- 采用openSession获取Session实例时,SessionFactory直接创立一个新的Session实例。并且在使用完成后需要调用close方法手动关闭。
- 而getCurrentSession方法创建的Session实例会被绑定到当前线程中,它在提交或者回滚操作时会自动关闭。
在这里插入代码片
Session是线程不安全的。**多个并发线程同时操作一个Session实例时,就可能导致Session数据存取的混乱。因此在设计软件架构时,应避免多个线程共享一个Session实例。它还有一个缓存,即Hibernate的一级缓存。
在Session中还提供了大量常用方法,具体如下:
- save()、update()和saveOrUpdate()方法:用于增加和修改对象。
- delete()方法:用于删除对象。
- get()和load()方法:根据主键查询。
- createQuery()和createSQLQuery()方法:用于数据库操作对象。
- createCriteria()方法:条件查询。
Transaction:
Transction接口是一个可选的API。Transction接口是对实际事务的一个抽象,主要用于管理事务、它是Hibernate的数据库事务接口,且对底层的事务接口进行了封装。Transaction接口的事务对象是通过Session对象开启的,代码如下:
Transaction transaction = session.beginTransaction();
在Transaction接口中,提供了事务管理的实用方法,具体如下:
- commit()方法:提交相关联的session实例。
- rollback()方法:撤销事务操作。
Session执行完数据库操作后,要使用Transction接口的commit()方法进行事务提交,才能真正将数据操作同步到数据库中。发生异常时,要使用rollback()方法进行事务回滚,以免数据发生错误。因此在持久化操作后,必须调用这两个方法。如果没有开启事务,那么 每一个Session的操作,都相当于一个独立的操作。