hibernate知识详解,看完这篇文章,完全掌握hibernate

本文详细介绍了Hibernate,一个流行的Java ORM框架,它简化了数据持久化操作,减少了JDBC的繁琐任务。通过ORM,Hibernate实现了面向对象与关系数据库之间的映射,使得开发者能以面向对象的方式处理数据。文章涵盖了JDBC的问题、Hibernate的核心概念如SessionFactory、Session,以及实体对象的三种状态。还探讨了Hibernate的配置步骤、CRUD操作、缓存策略和延迟加载,并提到了使用注解进行实体映射的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JDBC
什么是JDBC?
JDBC,全名 JAVA接(java DataBase Connectivity)技术的简称,由一组使用java语言编写的类与接口组成,可以为多种关系数据库提供统一访问。连接数据库后通过SQL来操作数据库。
JDBC的问题:
1、从连接效率上考虑,每一个操作都要重新连接数据库,对数据库造成较大的压力。
2、从代码上考虑,我们每次操作都要写编译以及对连接的控制,还要考虑到事务的提交与回滚等,程序员重复性与验证性的工作量很大。
3、JDBC使用的SQL语言对数据进行操作,不符合JAVA一直提倡的面向对象编程思想。JDBC操作的数据是“瞬时”的,变量的值无法与数据库保持一致。
认识hibernate
概述:hibernate是轻量级JavaEE应用的一个持久层框架。它的作用在于管理Java实体类到数据库表之间的映射关系,并且提供数据查询和获取数据的方法,可以大幅度的缩短使用JDBC处理数据持久化的时间。

目前关系型数据库依旧是主流数据库,java则是一门面向对象的编程语言,hibernate完成了对象模型和基于SQL关系模型的映射关系,使得程序员可以采用面向对象的方式来开发程序,充当了两者之间的桥梁。

ORM对象/关系数据库映射
概述:ORM全称Object/Relation Mapping,对象/关系数据库映射,可以理解成一种规范。该框架的基本特征:完成面向对象的编程语言到关系数据库之间的映射。

我们使用Java语言来进行应用开发时,从项目开启就一直采用面向对象分析,面向对象设计,面向对象编程,如果在持久层采用关系数据库的访问方式,是非常槽糕的。把关系型数据库包装成面向对象的模型,这就是ORM框架。

面向对象编程的优势:
1、面向对象建模,操作
2、多态,继承
3、摒弃难以理解的过程
4、简单易用,容易理解
关系型数据库的优势:
1、大量数据查询、排序
2、集合数据连接操作、映射
3、数据库访问的并发、事物
4、数据库的约束、隔离
结合两者的优势,采用ORM框架后,我们的应用程序就不再直接访问数据库,而是以对象的方式对对象进行持久化(CRUD)。

示意图:

可以看出ORM框架是由:实体+XML配置文件

基本映射方式:

数据库表映射类:持久化类被映射到一个数据表 ,当使用一个持久类来创建实例,修改实例属性,删除实例时,系统自动回转换对这个表进行CRUD操作。

数据表的行映射对象(实例):持久化类会生成很多实例,每个实例就对应数据表中的一个特定行的操作。每个持久化对象对应数据表的一行记录。

数据表中的列映射对象的属性:当在应用中修改某个持久化对象的指定属性时(持久化实例映射到数据行),ORM将会转换成对对应数据表中指定数据行、指定列的操作。

Hibernate的介绍
Hibernate是一个面向JAVA环境的对象/关系数据库映射工具,用来把对象模型表示的对象映射到基于SQL的关系模型数据结构中去 ,Hibernate的目标主要是为了释放开发者通常的数据持久化相关的编程的繁重任务。
对于以数据为中心的程序而言,往往在数据库中使用存储过程实现商业逻辑,Hibernate可能不是最好的解决方案,但是对于那些基于JAVA的中间件应用,设计采用面向对象的业务逻辑和商业逻辑,Hibernate是最有用的。
Hibernate不仅仅管理JAVA类到数据库表的映射,还提供数据查询和获取数据的办法,可以大幅度减少开发时人员使用SQL和JDBC处理数据的时间。

Hibernate就是一个ORM框架的典型代表,与其他ORM框架对比而言:

有以下特点:
1、开源和免费的License,方便需要时研究源码,改写源代码,进行功能定制。
2、轻量级封装,避免引入过多复杂的问题,调试容易,减轻程序员负担。
3、有可扩展性,API开放,功能不够用时,自己可以编码扩展。
Hibernate持久化解决方案:
(掌握)Hibernate的持久化解决方案将用户从原始的JDBC访问中释放出来,用户无须再关注底层的JDBC的操作。而是以面向对象的方式进行持久层操作。底层数据连接的获得,数据访问的实现,事务控制都无须用户关心。将应用从底层的JDBC中抽象出来,通过配置文件管理底层的JDBC连接,让Hibernate解决持久化访问的实现。

Hibernate简单工作原理图:

分析上图:
1、Hibernate框架需要2种配置文件,分别是:hibernate.cfg.xml(存放数据库连接信息)与xxx.hbm.xml
2、xxx.hbm.xml是配置在hibernate.cfg.xml中,该文件确定了持久类与数据表,数据列之间的对应关系。
3、hibernate不再是直接调用JDBC访问,而是Session会话访问。在hibernate框架中,只有处于Seesion管理下的POJO对象才有持久化操作的能力。

体系架构如下图所示:

几个关键对象:

SessionFatory:hibernate关键对象,它是单个数据库映射关系经过编译后的内存镜像,线程安全。主要作用是生成Session的工厂,该对象可以为事务之间可重用的数据提供可选的二级缓存。

Session:它是应用程序与持久储存层之间交互操作的一个单线程对象,是hibernate持久化操作的关键对象,所有的持久化对象必须在Session管理下才可以进行持久化操作。此对象的生命周期极短,底层封装了JDBC连接。Session对象持有一个必选的一级缓存,显式执行flush()之前,所有持久化操作的数据都缓存在Session对象处。

持久化对象:系统创建的POJO实例,一旦与特定的Session关联,并对应数据表的指定记录,该对象就处于持久化状态,这一系列对象都被称为持久化对象。在程序中对持久化对象执行的修改,都将自动被转换为持久层的修改。持久化对象完全可以是普通的JavaBean,唯一特殊的是他们正与一个Session关联。

事务(transaction):具有数据库事务的概念,Hibernate事务是对底层具体的JDBC、JTA、以及CORBA事务的抽象,在某些情况下,一个Session之内可能包含多个Transaction对象。虽然事务操作是可选的,但所有持久化操作都应该在事务管理下进行,即便是只读操作。

连接提供者(ConnctionProvider):生成JDBC连接的工厂,通过抽象将应用程序与底层的DataSource或DriverManager隔离开,该对象无须应用程序直接访问,仅在应用程序需要扩展时使用。注:实际开发中,很少有采用DriverManager来获取数据库连接, 通常都会使用DataSource来获取数据库连接。

事务工厂(TransactionFactory):是生成Transaction对象实例的工厂,该对象无须应用程序直接访问,它负责对底层具体的事务实现进行封装、将底层具体的事务抽象成Hibernate事务。

理解JAVA对象的3种形态:

瞬态:对象由new操作符创建,且尚未与Hibernate Session关联的对象,被认为处于瞬态。瞬态对象不会被持久化到数据库中,也不会被赋予持久化标示,如果程序中失去了瞬态对象的引用,瞬态对象将被垃圾回收机制销毁。使用Hibernate session可以让其变为持久化状态。

持久化:持久化实例在数据库中有对应的记录,并拥有一个持久化标识(identifier),持久化的实例可以是刚保存的。也可以是刚被加载的。无论那种,持久化对象都必须与指定的Hibernate Session关联。Hibernate会检测到处于持久化状态对象的改动,在当前操作执行完成时将对象数据写回数据库。开发者不需要手动执行UPDATE。

游离:某个实例曾经处于持久化状态,但随着与之关联的session被关闭,该对象就变成游离状态了。游离对象的引用依旧有效,对象可以继续被修改,只是不会同步到数据库中。如果重新让游离对象与某个session关联,该对象会重新转换为持久化状态。
hibernate的配置步骤
1、创建WEB项目
2、
从http://www.hibernate.org/下载hibernate-release-4.3.11.Final.zip,并解压。
3、将hibernate必须的包加入lib

4、打开hibernate-release-4.3.11.Final\lib\required文件夹,导入jar文件:

5、打开hibernate-release-4.3.11.Final\lib\optional\ehcache文件夹,导入jar文件:

6、打开hibernate-release-4.3.11.Final\lib\optional\c3p0文件夹,导入jar文件:

7、配置hibernate.cfg.xml
打开hibernate-release-4.3.11.Final\project\etc文件夹,选择hibernate.cfg.xml文件并
复制到src下。
8、打开hibernate.cfg.xml文件,并设置数据库连接

<session-factory>
	<!-- 定义方言 -->
	<property name="dialect">
		org.hibernate.dialect.MySQLDialect
	</property>

	<!-- 定义连接路径 -->
	<property name="connection.url">
		jdbc:mysql://localhost:3306/hibernate?characterEncoding=UTF-8
	</property>
	<!-- 定义连接名与密码 -->
	<property name="connection.username">root</property>
	<property name="connection.password"></property>
	<property name="connection.driver_class">com.mysql.jdbc.Driver</property>

	<!-- 指定使用c3p0连接池 -->
	<property name="hibernate.connection.provider_class">org.hibernate.c3p0.internal.C3P0ConnectionProvider</property>
	<!-- 指定连接池最大连接数 -->
	<property name="hibernate.c3p0.max_size">20</property>
	<!-- 指定连接池最小连接数 -->
	<property name="hibernate.c3p0.min_size">1</property>
	<!-- 指定连接池里连接超时时长 -->
	<property name="hibernate.c3p0.timeout">5000</property>

	<!-- 指定连接池里最大缓存多少个PreparedStatement对象 -->
	<property name="hibernate.c3p0.max_statements">100</property>
	<property name="hibernate.c3p0.idle_test_period">3000</property>

2

	<!--以格式良好的方式显示SQL语句-->
	<property name="format_sql">true</property>
	<!--显示SQL语句-->
	<property name="show_sql">true</property>

	<!-- 添加hbm文件配置 -->
	<mapping resource="com/lovo/xmls/UserInfoT.hbm.xml" />

</session-factory>

9、创建数据库表,并封装实体Bean与XXX.hbm.xml文件,例如:
UserInfoT.java:

package com.lovo.beans;

/**

  • UserInfoT entity. @author MyEclipse Persistence Tools
    */

public class UserInfoT implements java.io.Serializable {

// Fields

/**
 * 
 */
private static final long serialVersionUID = -8360690722407472061L;
private Long id;
private String userName;
private String password;
private Integer age;

// Constructors

/** default constructor */
public UserInfoT() {
}

/** full constructor */
public UserInfoT(String userName, String password, Integer age) {
	this.userName = userName;
	this.password = password;
	this.age = age;
}

// Property accessors

public Long getId() {
	return this.id;
}

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

public String getUserName() {
	return this.userName;
}

public void setUserName(String userName) {
	this.userName = userName;
}

public String getPassword() {
	return this.password;
}

public void setPassword(String password) {
	this.password = password;
}

public Integer getAge() {
	return this.age;
}

public void setAge(Integer age) {
	this.age = age;
}

}

打开 hibernate-release-4.3.11.Final\project\hibernate-core\src\main\resources\org\hibernate文件夹下的hibernate-mapping-3.0.dtd文件。,复制head部分。
UserInfoT.hbm.xml

<?xml version="1.0" encoding="utf-8"?> 用户名 密码 年龄

hibernate如何CRUD
获取Session对象:
//-----------------实例化Configuration(3.0)---------------------
Configuration conf = new Configuration()
.configure();//加载hibernate.cfg.xml配置

	//以Configuration创建SessionFactory
	SessionFactory factory = conf.buildSessionFactory();
	//创建Session
	Session session = factory.openSession();

/**

  • Hibernate4新增了一个接口ServiceRegistry,

所有基于Hibernate的配置或者服务都必须统一向这个ServiceRegistry注册后才能生效。

Hibernate4的配置入口不再是Configuration对象,而是ServiceRegistry对象,Configuration对象将通过ServiceRegistry对象获取配置信息。

使用了Builder模式创建一个ServiceRegistry对象
*
*
*/
static {
cfg = new Configuration().configure();
serviceRegistry = new StandardServiceRegistryBuilder().applySettings(
cfg.getProperties()).build();
sessionFactory = cfg.buildSessionFactory(serviceRegistry);
}

讲解get()与load()的区别:
get和load方法都是根据id去获得对应数据的,但是获得机制不同:如果使用get方法,hibernate会去确认该id对应的数据是否存在,它首先会去session中去查询(session缓存其实就hibernate的一级缓存),如果没有,再去二级缓存中去查询,如果再没有,就去数据库中查询,仍然没有找到的话,就返回null

而使用load方法的话,hibernate会认定该id对应的数据一定存在,它也会先去session缓存中去查找,
如果没有找到,hibernate会根据lazy属性值来确定是否使用延迟加载。如果lazy=‘true’ ,就使用延迟加载,返回该代理对象,
等到真正访问到该对象的属性时才会去二级缓存中查询,如果没有,再去数据库中查询,如果还没有,就抛出org.hibernate.ObjectNotFoundException异常。
如果lazy=‘false’ 则不使用延迟加载,这是load的访问机制就和get一样了。
  
  总之get和load的根本区别,hibernate对于load方法认为该数据在数据库中一定存在,可以放心的使用代理来延迟加载,如果在使用过程中发现了问题,只能抛异常;而对于get方法,hibernate一定要获取到真实的数据,否则返回null。
hibernate的实体映射
一对一
主键关联
见PPT

外键关联
见PPT
一对多

多对多
家庭作业
Hibernate的性能
Hibernate提供了2个级别的缓存,分别是:一级缓存,二级缓存
默认总是启动的Session级别的一级缓存
一级缓存不需要开发者关心,默认总是有效的,当应用保存持久化实体,修改持久化实体时,Session并不会立即把改变flush到数据库,而是先缓存在session一级缓存中,除非程序显式调用flush(),或程序关闭Session时才会把这些改变一次性的flush到底层数据库,通过这种缓存,可以减少与数据库的交互,从而提高数据库访问性能。

SessionFactory级别的缓存,我们叫做二级缓存,二级缓存是全局性的,应用的所有的Session都共享这个二级缓存,不过Session级别的缓存默认是关闭的,必须由程序显式开启。一旦在应用中开启了二级缓存,当Session需要抓取数据时,Session将会优先从二级缓存中抓取。

二级缓存
为了开启二级缓存,需要在hibernate.cfg.xml文件中配置如下属性:

	<property name="cache.use_second_level_cache">true</property>

一旦开启了二级缓存,并设置了对某个持久化实体类启动缓存,SessionFactory就会缓存应用访问过的该实体类的每个对象,除非缓存的数据超出缓存空间。

在实际应用中,一般不需要开发者自己实现缓存,直接使用第3方提供的开源缓存实现即可。因此在hibernate.cfg.xml文件中设置开启缓存后,还需要设置使用哪种缓存实现类。配置如下:

org.hibernate.cache.ehcache.EhCacheRegionFactory注意:
实际上在项目中使用EHCache缓存实现,仅仅复制lib\optional\下对应缓存的JAR包还不够,应用EHCache还需要依赖于commons-logging.jar,backport-util-concurrent.jar两个工具包。

将缓存实现所需要的配置文件添加到系统的类加载路径中,对于EHCache缓存,它还需要一个ehcache.xml配置文件(可以在Hibernate发行包的project\etc路径下找到该文件的示例)

<?xml version="1.0" encoding="GBK"?>
    <!-- maxElementsInMemory 设置缓存中最多可放多少个对象 -->
    <!-- eternal 设置缓存是否永久有效 -->
    <!-- timeToIdleSeconds 设置缓存的对象多少秒没有被使用就会清理掉 -->
    <!-- timeToLiveSeconds 设置缓存的对象在过期之前可以缓存多少秒 -->
    <!-- overflowToDisk 设置当内存中缓存的记录达到maxElementsInMemory 时是否被持久化到硬盘中,保存路径有<diskStore../>元素指定 -->

在实体的缓存策略放在不同的映射文件中分别管理,例如:

<?xml version="1.0" encoding="utf-8"?>
<class name="com.lovo.beans.UserInfoT" table="user_info_t" catalog="hibernate">
    <!-- 设置缓存策略 -->
    <cache usage="read-only"/>
    
    
    
    <id name="id" type="java.lang.Long">
        <column name="id" />
        <!-- 指定ID的生成方式 -->
        <generator class="identity" />
    </id>
    <property name="userName" type="java.lang.String">
        <column name="user_name" length="32">
            <comment>用户名</comment>
        </column>
    </property>
    <property name="password" type="java.lang.String">
        <column name="password" length="32">
            <comment>密码</comment>
        </column>
    </property>
    <property name="age" type="java.lang.Integer">
        <column name="age">
            <comment>年龄</comment>
        </column>
    </property>
</class>

Hibernate支持的缓存策略:
Read-only 只读
Read/write 读写
二级缓存适合场合:
1、很少被修改的数据
2、不是很重要的数据,允许出现偶尔并发的数据
3、不会被并发访问的数据
4、 参考数据,指的是供应用参考的常量数据,它的实例数目有限,它的实例会被许多其他类的实例引用,实例极少或者从来不会被修改。

延迟加载:
Hiberante注解
从JDK1.5开始,JAVA增加了Annotation支持,通过Annotation可以将一些额外的信息写在JAVA源程序中,这些信息可以在编译,类加载,运行时被读取,并执行相应的处理。通过使用Annotation程序开发人员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充的信息。
由于JAVA Annotation的盛行,很多原来采用XML配置文件进行管理的信息,现在都开始改为使用Annotation进行管理。其实不管是XML配置,还是Annotaion,他们的本质都是一样,只是信息的载体不同而已。
Hibernate这种ORM框架的出现启发了JavaEE规范的制定者,于是催生了JPA规范。从另一个方面看,JPA规范的出现又为Hibernate等ORM框架制定了标准。
早期Hibernate使用XML映射文件来管理持久化类和数据表之间的映射关系,而JPA规范则推荐使用更简单,易用的Annotation来管理实体类与数据库表之间的映射关系,这样就可以避免了一个实体需要同时维护两份文件(JAVA类和XML映射文件),实体类的JAVA代码以及映射信息(写在Annotation中)都可集中在一份文件中。
Annotation基本配置:
实例如下:

(表结构)

JAVA类为:
package com.lovo.entitys;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.annotations.GenericGenerator;

@Entity //将一个JAVA类声明为一个可持久化的POJO对象
@Table(name=“person_info_t”) //该持久类所对应的表,声明在name属性中给定
public class PersonInfoT {
@Id //指定标识属性
@Column(name=“id”) //指定属性所对应的列,如果列名和属性名一致,可以不定义name属性
@GeneratedValue(strategy=GenerationType.IDENTITY) //定义主键JPA生成策略
/**如果主键生成想使用Hibernate的特有生成方式,
必须使用Hibernate定义的注解(非JPA注解)
@GeneratedValue(generator=“identity”)
@GenericGenerator(name=“identity”,strategy=“identity”) */
private Long id;
@Column(name=“user_name”)
private String userName;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}

一对多,多对多,见PPT

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值