“Hibernate笔记 3:核心API”的版本间差异

来自Wikioe
跳到导航 跳到搜索
(创建页面,内容为“category:Hibernate == Configuration 接口 == Configuration 接口的作用是:对 Hibernate 进行配置、并启动 Hibernate 和连接数据库系统。 Configuration 仅仅是作为一个初始化时的对象,一个 Configeration 实例代表 Hibernate 所有 Java 类到 Sql 数据库映射的集合。 在 Hibernate 的启动过程中,Configuration 类的实例首先定位缺省 XML 配置文件(hibernate.cfg.xml),并读取关的…”)
 
 
(未显示同一用户的14个中间版本)
第1行: 第1行:
[[category:Hibernate]]
[[category:Hibernate]]


== Configuration 接口 ==
== 关于 ==
  Configuration 接口的作用是:对 Hibernate 进行配置、并启动 Hibernate 和连接数据库系统。
注意:以下 API 多数为接口,在开发时使用的一般是其实现类。
   
   
如:
1、'''SessionFactory''' 接口 —— '''SessionFactoryImpl''' 类
2、'''Session''' 接口 —— '''SessionImpl''' 类
   
   
见:<big>'''[[Hibernate源码分析:入门代码流程]]'''</big>
== Configuration 类 ==
  Configuration 仅仅是作为一个初始化时的对象,一个 Configeration 实例代表 Hibernate 所有 Java 类到 Sql 数据库映射的集合。
  Configuration 仅仅是作为一个初始化时的对象,一个 Configeration 实例代表 Hibernate 所有 Java 类到 Sql 数据库映射的集合。
Configuration 接口的作用是:对 Hibernate 进行配置、并启动 Hibernate 和连接数据库系统。


在 Hibernate 的启动过程中,Configuration 类的实例首先定位缺省 XML 配置文件(hibernate.cfg.xml),并读取关的配置项目,然后创建出一个 SessionFactory 对象。
作用:
 
: 在 Hibernate 的启动过程中,Configuration 类的实例首先定位缺省 XML 配置文件(hibernate.cfg.xml),并读取关的配置项目,然后创建出一个 SessionFactory 对象。
使用:
# 读取配置文件:
# 根据默认的 XML 配置文件:(位置:src/hibernate.cfg.xml)
## 根据默认的 XML 配置文件:(位置:src/hibernate.cfg.xml)
#: <syntaxhighlight lang="Java" highlight="">
##: <syntaxhighlight lang="Java" highlight="">
Configuration cfg = new Configuration().configure();
Configuration cfg = new Configuration().configure();
</syntaxhighlight>
</syntaxhighlight>
# 根据自定义的 XML 配置文件:(少用)
## 根据自定义的 XML 配置文件:(少用)
#: <syntaxhighlight lang="Java" highlight="">
##: <syntaxhighlight lang="Java" highlight="">
Configuration cfg = new Configuration().configure("cn/config/hibernate2.cfg.xml");
Configuration cfg = new Configuration().configure("cn/config/hibernate2.cfg.xml");
</syntaxhighlight>
</syntaxhighlight>
# 加载“映射配置文件”:(如果使用“hibernate.properties”作为核心配置文件,则无法在其中配置“映射配置文件”,需要使用 Configuration 对象加载)
## 加载“映射配置文件”:(如果使用“hibernate.properties”作为核心配置文件,则无法在其中配置“映射配置文件”,需要使用 Configuration 对象加载)
#: <syntaxhighlight lang="Java" highlight="">
##: <syntaxhighlight lang="Java" highlight="">
Configuration cfg = new Configuration().configure();
Configuration cfg = new Configuration().configure();
cfg.addResource("com/eijux/domain/Customer.hbm.xml");
cfg.addResource("com/eijux/domain/Customer.hbm.xml");
</syntaxhighlight>
</syntaxhighlight>
 
# 创建 SessionFactory 对象:
== SessionFactory 接口 ==
#* 在 Hibernate 4 之前:
SessionFactory 接口负责 Hibernate 的初始化和建立 Session 对象。
#*: <syntaxhighlight lang="Java" highlight="">
它在 Hibernate 中起到一个缓冲区作用,Hibernate 可以将自动生成的 SQL 语句、映射数据以及某些可重复利用的的数据放在这个缓冲区中。同时它还保存了对数据库配置的所有映射关系,维护了当前的<span style="color: blue; font-size: 120%">'''二级缓存'''</span>。
SessionFactory 的主要作用是:产生和管理 Session。
 
根据 Configuration 对象创建一个 SessionFactory 对象:
# 在 Hibernate 4 之前:
#: <syntaxhighlight lang="Java" highlight="">
Configuration cfg = new Configuration();
Configuration cfg = new Configuration();
cfg.configure();
cfg.configure();
SessionFactory sessionFactory = cfg.buildSessionFactory();
SessionFactory sessionFactory = cfg.buildSessionFactory();
</syntaxhighlight>
</syntaxhighlight>
# 在 Hibernate 4 之后:【???】
#* 在 Hibernate 4 之后:【???】
#: <syntaxhighlight lang="Java" highlight="">
#*: <syntaxhighlight lang="Java" highlight="">
Configuration cfg = new Configuration().configure();
Configuration cfg = new Configuration().configure();
ServiceRegistry sr = new ServiceRegistryBuilder().applySettings(cfg.getProperties()).buildServiceRegistry();
ServiceRegistry sr = new ServiceRegistryBuilder().applySettings(cfg.getProperties()).buildServiceRegistry();
第45行: 第45行:
</syntaxhighlight>
</syntaxhighlight>


 
== SessionFactory 接口 ==
  SessionFactory 具有以下特点:
  SessionFactory 接口负责 Hibernate 的初始化和建立 Session 对象。
1、线程安全,同一个实例能够供多个线程共享。
   
  2、重量级,不能随意的创建和销毁它的实例。
   
   
特点:
1、'''线程安全''',同一个实例能够供多个线程共享。
2、'''重量级''',不能随意的创建和销毁它的实例。
   
   
  所以,通常情况下每一个应用只需要一个 SessionFactory,当需要操作多个数据库时,可以为每个数据库指定一个 SessionFactory。
  所以,通常情况下每一个应用只需要一个 SessionFactory,当需要操作多个数据库时,可以为每个数据库指定一个 SessionFactory。
   
   
即:'''“一个 SessionFactory 实例”对应“一个数据存储源”'''。——【'''重量级,整个应用中共享'''】
    ——【'''整个应用中共享''',一个 SessionFactory 实例”对应“一个数据存储源”】


因此,在实际项目使用中,通常会抽取一个 '''HibernateUtils''' 的工具类,用于提供 Session 对象:
因此,在实际项目使用中,通常会抽取一个 '''HibernateUtils''' 的工具类,用于提供 Session 对象:
第71行: 第73行:
public static Session openSession() {  
public static Session openSession() {  
return sessionFactory.openSession();
return sessionFactory.openSession();
}
/**
* 获取当前线程绑定的会话:
*/
public static Session getCurrentSession(){
return sessi.onFactory.getCurrentSession();
}
}
}
}
</syntaxhighlight>
</syntaxhighlight>
SessionFactory 可以通过两种方法产生 Session。
生成 Sessin:
# '''openSession()''':每次打开都是新的 Session,并且需要人为的调用 '''close''' 方法关闭 Session。
#: <syntaxhighlight lang="Java" highlight="">
Session session = sessionFactory.openSession();
</syntaxhighlight>
# '''getCurrentSession()''':从当前上下文中获取 Session 并且会绑定到当前线程:
#: 第一次调用会自动创建一个 Session 实例,如果未手动关闭多次获取的是同一个 Session,事物提交或者回滚时会'''自动关闭''' Session。
#: <syntaxhighlight lang="Java" highlight="">
Session session = sessionFactory.getCurrentSession();
</syntaxhighlight>
#* 需要在配置文件(hibernate.cfg.xml)中添加如下配置:【否则会报错“org.hibernate.HinerbateException: No CurrentSessionContext configured!”】
#*# 如果使用的是'''本地事务'''(JDBC 事务):
#*#: <syntaxhighlight lang="xml" highlight="">
<property name="current_session_context_class">thread</property>
</syntaxhighlight>
#*# 如果使用的是'''全局事务'''(JTA 事务):
#*#: <syntaxhighlight lang="xml" highlight="">
<property name="current_session_context_class">jta</property>
</syntaxhighlight>
'''全局事务''':资源管理器管理和协调的事务,可以跨越多个数据库和进程。资源管理器一般使用 XA 二阶段提交协议与“企业信息系统”(EIS)或数据库进行交互。   
'''本地事务''':在单个 EIS 或数据库的本地并且限制在单个进程内的事务。本地事务不涉及多个数据来源。


=== 连接池 ===
=== 连接池 ===
  SessionFactory 内部还维护了一个连接池,如果需要使用第三方连接池(如:C3PO),则需要手动进行配置。
  SessionFactory 内部还维护了一个连接池,如果需要使用第三方连接池(如:C3PO),则需要手动进行配置。


步骤:
详见:'''[[Hibernate笔记 2:配置文件详解#配置:连接池]]'''
# 引入 C3PO 相关 JAR 包:
#* c3p0-0.9.2.1.jar
#* hibernate-c3p0-5.0.7.Final.jar
#* mchange-commons-java-0.2.3.4.jar
# 配置 C3PO 连接池(hibernate.cfg.xml 中):
#: <syntaxhighlight lang="xml" highlight="">
<!-- 配置C3PO连接池 -->
<property name= "connection.provider_c1ass">org.hibernate.connection.C3POConnectionProvider</property>
<!-- 连接池中可用数据库连接的最少数目 -->
<property name= "c3p0.min_size">5</property>
<!-- 连接池中所有数据库连接的最大数目 -->
<property name= "c3p0.max_size">20</property>
<!-- 数据库连接的过期时间(单位:秒):
如果池中某个连接处于空闲状态的时间超过了 timeout 时间,就会从连接池中消除
-->
<property name= "c3p0.timeout">120</property>
<!-- 检查连接池中的空闲连接的时间间隔(单位:秒)-->
<property name= "c3p0.idle_test_period ">3000</property>
</syntaxhighlight>


== Session ==
== Session 接口 ==
  Session 用于管理一个数据库的任务单元(增、删、改、查),它是 Java 应用和 Hibernate 之间主要运行接口,是抽象持久性服务概念的主要 API。
  Session 用于管理一个数据库的任务单元(增、删、改、查),它是 Java 应用和 Hibernate 之间主要运行接口,是抽象持久性服务概念的主要 API。
   
   
【类似于 JDBC 中的连接(“connection”)】
   
   
特点:
1、'''非线程安全''',因此最好是一个线程只创建一个Session对象(将它设计为局部对象)。
2、'''轻量级''',创建和销毁 Session 对象不会有太大开销。
   
   
Session 对象是'''非线程安全'''的,因此最好是一个线程只创建一个Session对象(将它设计为局部对象)。
     ——【'''不共享''':“一请求”>>“一线程”>>“一session”>>“一事务”】
     ——【'''轻量级,不共享''':“一请求”>>“一线程”>>“一session”>>“一事务”】


=== 生命周期 ===
类似于 JDBC 中的连接(“connection”)。
Session 的生命周期是以一个逻辑事物的开始和结束为边界,Session 的主要功能是提供创建、读取和删除映射的实体类的操作。


实体可能存在于三种状态:
=== 生成方式 ===
# '''瞬时状态'''(transient):实体对象在内存是自由存在的(即为普通的 Java 对象),即:“该实体从未与任何持久化上下文关联过,它没有持久化标识”。
可以通过两种方法产生 Session。
#* 与“Session对象”:无关联;
#* 与“数据库记录”:无关联;
# '''持久状态'''(persistent):实体对象处于 Hibernate 框架所管理的状态,即:“该实体在数据库中有对应的记录,并拥有一个持久化标识”。
#* 与“Session对象”:有关联;
#* 与“数据库记录”:有关联;
#* Hibernate 会:依据 persistent 状态的实体对象的属性变化,而改变数据库中相对应的记录;
#**在一个 Session 中,对持久对象的改变不会马上对数据库进行变更,而是发生在 Transaction 终止,执行 commit 之后。
# '''游离状态'''(detached):与持久状态的对象关联的 Session 被关闭后,该对象就变成游离状态,即:“游离态是由持久态实体对象转变(关联的 Session 被关闭)而来的”。
#* 与“Session对象”:无关联;
#* 与“数据库记录”:无直接关联;(可能有相关数据,但未关联)
#* 此状态下对游离对象的引用依然有效,也可以继续被修改;
#** 但,对其所做的任何修改将不会影响到到数据库中的数据。


 
生成方式:
* 三种状态可以互相转换:
# '''openSession()''':获取一个新的 Session;
*: [[File:Hibernate 生命周期图.png|600px]]
#: <syntaxhighlight lang="Java" highlight="">
 
Session session = sessionFactory.openSession();
=== Session 缓存 ===
</syntaxhighlight>
Session 中有一个缓存,被称为“Hibernate 的<span style="color: blue; font-size: 120%">'''一级缓存'''</span>”。
#* 每次打开都是新的 Session;
#* 需要调用 '''close''' 方法以关闭 Session。
Session 缓存,用于存放被当前工作单元加载的对象,这块缓存中有一个 '''map'''
# '''getCurrentSession()''':从当前上下文中获取 Session,并<span style="color: blue">'''绑定到当前线程'''</span>
1、在执行 '''save()''' 方法后,会生成一个 '''id'''(<span style="color: blue">'''OID'''</span>),这个 id 会保存在 map 的 '''key''' 中;
#: <syntaxhighlight lang="Java" highlight="">
2、与之对应的 '''value''' 值就是该是该对象的引用,执行 '''commit()''' 方法后,数据库就有对应这条数据了,此时该实体处于“持久状态”;
Session session = sessionFactory.getCurrentSession();
3、当执行完 Session.'''close()'''后,处于“游离状态”。
</syntaxhighlight>
 
#* 第一次调用会创建新的 Session 实例,(如未手动管理,则)同一线程中多次获取的是同一个 Session;
区分实体的三种状态:
#* 无需手动关闭,'''线程结束时会自动关闭''' Session。
:{| class="wikitable"
#* 必须配置“'''Session 管理方式'''”为:(否则会报错“org.hibernate.HinerbateException: No CurrentSessionContext configured!”)
! 实体状态 !! OID !! Session缓存 !! 数据库
#*: <syntaxhighlight lang="xml" highlight="">
|-
<property name="current_session_context_class">thread</property>
| 瞬时状态 || null || 不存在 || 无记录
</syntaxhighlight>
|-
#*:【详见:<big>'''[[Hibernate笔记 4:核心知识#事务管理]]'''</big>
| 持久状态 || 非null || 存在 || 有记录
|-
| 托管状态 || 非null || 不存在 || (可能)有记录
|}
 
 
<span style="color: blue; font-size: 150%;">'''OID'''</span>(object identifier),即:“对象标识符”,是 hibernate 用于区分两个对象是否是同一个对象的标识的方法。
OID 在对象持久化之前是 '''null''',持久化的时候 hibernate 或者我们手动指定一个 id('''被插入到数据库当做主键,在 session中 当做索引'''),所以,需要保证 OID 与主键的一致性,比如:类型、长度等。
 
OID 类型:
# '''自然主键''':带有业务含义的主键(比如:学号,工作编号)。
#* 需要手动的指定主键(合成或者拼接);如果不指定主键就提交缓存进行更新,则会报错!
#* 主键生成策略:
#*# <span style="color: blue">'''assinged'''</span>:Hibernate不维护主键,开发人员需要手动设置主键;
# '''代理主键''':通过编码自动生成的,无业务含义的主键。
#* 主键生成策略:
#*# <span style="color: blue">'''increment'''</span>:(由 Hibernate 提供的)'''自动增长'''。
#*#* 适用于:short、int、long 类型的主键;
#*#* 不适用:与并发访问数据库;
#*# <span style="color: blue">'''identity'''</span>:(由数据库提供的)'''自动增长'''。
#*#* 适用于:short、int、long 类型的主键;
#*#* 不适用:不支持自动增长的数据库(如:Oracle);
#*# <span style="color: blue">'''sequence'''</span>:(由数据库提供的)'''序列'''。
#*#* 适用于:short、int、long 类型的主键;
#*#* 适用于:支持序列的方式的数据库(如:Oracle、db2、sap、db、postgresql);
#*# <span style="color: blue">'''native'''</span>:本地策略,根据底层的数据库不同,'''自动选择'''使用 identity 还是 sequence。
#*#* 适用于:short、int、long 类型的主键;
#*# <span style="color: blue">'''uuid'''</span>:随机字符串。
#*#* 适用于:字符串类型的主键。
 
 
Session 缓存是由一系列的 Java 集合构成的:
    当一个对象被加入到 Session 缓存中,这个对象的引用就加入到了 Java 的集合中,即使以后应用程序中的引用变量不再引用该对象,只要 Session 缓存不被清空,这个对象一直处于生命周期中。
 
作用:
# 减少访问数据库的频率。
# 保证缓存中的对象与数据库中的相关记录保持同步。
 
Session 清理缓存的时机:
# 提交前:当调用 Transaction 的 commit() 方法时,commit() 方法先清理缓存(前提是:FlushMode.COMMIT/AUTO),然后再向数据库提交事务。
# 查询前:当应用程序调用 Session 的 find() 或者 iterate() 时,如果缓存中的持久化对象的属性发生了变化,就会先清理缓存,以保证查询结果能反映持久化对象的最新状态。
# flush:当应用程序显示调用 Session 的 flush() 方法的时候。
: 如下图:
:{| class="wikitable"
! FlashMode !! Session.find()/iterate() !! Session.commit() !! Session.flush()
|-
| FlashMode.AUTO || ✔ || ✔ || ✔
|-
| FlashMode.COMMIT || ✘ || ✔ || ✔
|-
| FlashMode.NEVER || ✘ || ✘ || ✔
|}
:* 清理(✔),不清理(✘)


=== 常用方法 ===
=== 常用方法 ===
  Session 的所有方法,见博客:[https://www.cnblogs.com/lukun/archive/2011/03/31/1968937.html Hibernate session的方法全集]
  Session 的所有方法,见 JBoss 的 Hibernate 文档:<big>'''[https://docs.jboss.org/hibernate/core/3.5/api/org/hibernate/Session.html https://docs.jboss.org/hibernate/core/3.5/api/org/hibernate/Session.html]'''</big>


常见方法:
常见方法:
第438行: 第330行:
</syntaxhighlight>
</syntaxhighlight>
#: 如上,两个 load 方法均会发送查询到数据库。如果注释掉 clear,则第二次 load 不发送查询到数据库,而是直接使用第一次 load 的缓存(两次 load 的是同一个记录)。
#: 如上,两个 load 方法均会发送查询到数据库。如果注释掉 clear,则第二次 load 不发送查询到数据库,而是直接使用第一次 load 的缓存(两次 load 的是同一个记录)。
# '''flush()''':'''强制同步数据(从内存到数据库)'''
# '''flush()''':'''Session 缓存刷出'''(到数据库)。
#* 在默认的情况下 session.commit() 之前时,其实执行了一个 flush 命令。
#: 【即,<span style="color: blue">“'''缓存清理'''”</span>,强制同步数据(从内存到数据库)  ——见:<big>'''[[Hibernate笔记 4:核心知识:Session缓存#缓存清理机制(缓存刷出)]]'''</big>】
#* 只有部分 SQL 语句(update、insert、delete),才需要 flush。
#* 在默认的情况下 session.commit() 之前时,其实执行了一个 flush 命令。 ——【一般不需要手动调用该方法】
#** 对于“session.save()”方法:
#* 可以通过 '''<syntaxhighlight lang="Java" inline>session.setFlushMode(FlushMode)</syntaxhighlight>''' 来设置“'''刷新时机'''”:
#**: 如果主键生成策略是“由数据库生成”(native),则 session.save 的同时就发出 SQL 语句(insert)。否则(uuid),session.save 不会发出 SQL 语句。【???】
# '''evict()''':'''从 session 缓存中逐出该对象'''。
#* 可以通过 <syntaxhighlight lang="Java" inline>session.setFlushMode(FlushMode);</syntaxhighlight> 来设置“'''刷新模式'''”:
#*: FlushMode 的枚举值:
#*#“FlushMode.ALWAYS”:任务一条SQL语句,都会 flush 一次;
#*#“FlushMode.AUTO”:自动 flush(默认);
#*#“FlushMode.COMMIT”:只有在 commit 时才 flush;
#*#“FlushMode.MANUAL”:手动 flush;
#*#“FlushMode.NEVER”:永远不 flush。(此选项在性能优化时可能用,比如 session 取数据为只读时用,这样就不需要与数据库同步了)
#** 设置 flush 模式(FlushMode),应该在 session 开启事务之前。
# '''evict()''':'''从 session 缓存(EntityEntries属性)中逐出该对象'''。
#* 与 commit 同时使用,会抛出异常。【???】
#* 与 commit 同时使用,会抛出异常。【???】
#*: 示例:
#*: 示例:
第458行: 第341行:
tx = session.beginTransaction();
tx = session.beginTransaction();


User1 user = new User1();
User user = new User();
user.setName("李四");
user.setName("李四");
user.setPassword("123");
user.setPassword("123");
第469行: 第352行:
session.save(user);
session.save(user);


// 从session缓存(EntityEntries属性)中逐出该对象
// 从 session 缓存中逐出该对象
session.evict(user);
session.evict(user);
/* 无法成功提交。
/* 无法成功提交。
因为 hibernate 在清理缓存时,在 session 的临时集合(insertions)中取出 user 对象进行 insert 操作后,需要更新 entityEntries 属性中的 existsInDatabase 为 true,而我们采用 evict 已经将 user 从 session 中逐出了,所以找不到相关数据,无法更新,抛出异常。
因为 hibernate 在清理缓存时,在 session 的临时集合(insertions)中取出 user 对象进行 insert 操作后,需要更新 entityEntries 属性中的 existsInDatabase 为 true,而我们采用 evict 已经将 user 从 session 中逐出了,所以找不到相关数据,无法更新,抛出异常。
*/
*/
tx.commit();
tx.commit();
第486行: 第369行:
session.flush();
session.flush();


// 从session缓存(EntityEntries属性)中逐出该对象
// 从 session 缓存中逐出该对象
session.evict(user);
session.evict(user);
第498行: 第381行:




==== load() 与 get() ====
  load() 与 get():
  load() 与 get():
  1、不存在对应记录时:
  1、不存在对应记录时:
第511行: 第395行:
  此外,get() 和 load() '''只根据主键查询''',不能根据其它字段查询,如果想根据非主键查询,可以使用 '''HQL'''。
  此外,get() 和 load() '''只根据主键查询''',不能根据其它字段查询,如果想根据非主键查询,可以使用 '''HQL'''。


== Transaction ==
== Transaction 接口 ==
  Hibernate 的 Transaction 是底层的 '''JDBC Transaction''' 或者 '''JTA Transaction''' 的封装,具体取决于在 hibernate.properties(hibernate.cfg.xml 中 property “current_session_context_class”) 的配置。
  Hibernate 进行持久化操作时(CRUD)必须进行事务控制。


配置事务管理器(hibernate.cfg.xml 中):
使用:
# 使用 JDBC Transaction:
# 开启事务:
#: <syntaxhighlight lang="xml" highlight="">
#: <syntaxhighlight lang="Java" highlight="">
<property name="current_session_context_class">thread</property>
Transaction tx = session.beginTransaction();
</syntaxhighlight>
</syntaxhighlight>
# 使用 JTA Transaction:
# 提交事务:
#: <syntaxhighlight lang="xml" highlight="">
#: <syntaxhighlight lang="Java" highlight="">
<property name="current_session_context_class">jta</property>
tx.commit();
</syntaxhighlight>
# 回滚事务:
#: <syntaxhighlight lang="Java" highlight="">
tx.rollback();
</syntaxhighlight>
</syntaxhighlight>


Hibernate 进行持久化操作时(CRUD)必须进行事务控制。


示例:
示例:
第543行: 第430行:
session.close();
session.close();
}
}
}
</syntaxhighlight>
== 其他 API ==
以下包括了 Hibernate 的几种种对象检索方式。
# '''Query''':HQL 查询;(类似于 SQL)
# '''Criteria''':QBC 查询;(无任何语句)
# '''SQLQuery''':SQL 查询;
=== Query ===
----
<span style="color: blue; font-size: 120%;">'''Query'''</span> 代表面向对象的一个【'''Hibernate 查询'''】操作,所使用的语句为 <span style="color: blue; font-size: 120%;">'''HQL'''(Hibernate Query Language)</span>。
    其语法很像 SQL 语法,但它是完全“'''面向对象'''”的。
==== 使用 ====
在 Hibernate 中,通常使用 session.createQuery() 方法接受一个 HQL 语句, 然后调用 Query 的 list() 或 uniqueResult() 方法执行查询。
使用 Query 对象的步骤:
# 获得 Hibernate 的 Session 对象;
# 通过 '''session.createQuery("HQL 语句")''' 创建查询对象,并编写 '''HQL''' 语句;
# 如果 HQL 语句包含参数,则调用 Query 的 '''setXxx()''' 设置参数;
# 调用 Query 对象的 '''list()''' 或 '''uniqueResult()''' 方法执行查询。
示例,Query 执行 HQL 语句的常用查询:
: <syntaxhighlight lang="Java" highlight="">
public void demo_Query() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
Query query = null;
List<Customer> list = null;
// 1. 查询所有记录
query = session.createQuery("from Customer");
list = query.list();
System.out.println(list);
// 2. 条件查询:
query = session.createQuery("from Customer where name = ?");
query.setString(0, "张三");
list = query.list();
System.out.println(list);
// 3. 条件查询:
query = session.createQuery("from Customer where name = :aaa and age = : bbb");
query.setString ("aaa", "张三");
query.setinteger("bbb", 38);
list = query.list();
System.out.println(list);
// 4. 分页查询:
query = session.createQuery("from Customer");
query.setFirstResult(3);
query.setMaxResults(3);
list = query.list();
System.out.println(list);
tx.commit();
session.close();
}
</syntaxhighlight>
==== 常用方法 ====
Query 中除了使用 list() 方法查询全部数据外,还有一些常用方法。
常用方法:
# '''setterXxx()''':Query 接口中提供了一系列的 setter 方法用于设置查询语句中的'''参数'''。
#* 针对不同的数据类型,需要用到不同的 setter 方法。
# '''iterator()''':用于查询语句,返回的结果是一个 Iterator 对象(只能按照顺序读取)。
#* 它仅把使用到的数据转换为 Java 实体对象;【???】
# '''uniqueResult()''':用于返回唯一的结果。
#* 确保查询结果仅有一条记录才可使用;
# '''executeUpdate()''':用于支持 HQL 语句的'''更新和删除'''操作。
#* Hibernate3 的新特性;
# '''setFirstResult()''':用于设置获取第一个记录的位置(从第几条记录开始查询)。
#* 默认从 0 开始计算;
# '''setMaxResult()''':用于设置结果集的最大记录数。
setFirstResult() 通常与 setMaxResult() 方法结合使用,用于限制结果集的范围,以实现'''分页功能'''。
=== Criteria ===
----
<span style="color: blue; font-size: 120%;">'''Criteria'''</span>,又称<span style="color: blue; font-size: 120%;">“'''QBC 查询'''”</span>(Query By Critena),是 Hibernate 框架的核心查询对象。
    它是一个完全“'''面向对象,可扩展'''”的条件查询 API,通过它完全“'''不需要考虑数据库底层如何实现,以及 SQL 语句如何编写'''”。
==== 使用 ====
用到的“接口/类”:【注意区别:“Criteria”与“Criterion”】
    1、<span style="color: blue">'''org.hibernate.Criteria'''</span> :Hibernate 提供的一个面向对象<span style="color: blue">“'''查询接口'''”</span>。
    2、<span style="color: blue">'''org.hibernate.criterion.Criterion'''</span> :Hibernate 提供的一个面向对象<span style="color: blue">“'''查询条件接口'''”</span>。
      ——“一个单独的查询就是 Criterion 接口的一个实例”。
   
    3、<span style="color: blue">'''org.hibernate.criterion.Restrictions'''</span> 类:提供了一系列用于设定查询条件的静态方法,<span style="color: blue">'''用于创建 Criterion 对象'''</span>。
使用 Criteria 对象的步骤:
# 获得 Hibernate 的 Session 对象。
# 通过 Session 获得 '''Criteria''' 对象。
#* 需要
# 使用 Restrictions 的静态方法创建 Criterion 条件对象。
#* Restrictions 类中提供了一系列用于设定查询条件的静态方法,这些静态方法都返回 Criterion 实例,'''每个 Criterion 实例代表个查询条件'''。
# 向 Criteria 对象中添加 Criterion 查询条件。
#* Criteria 的 '''add()''' 方法用于加入查询条件。
# 执行 Criteria 的 '''list()''' 或 '''uniqueResult()''' 获得结果。
示例,Criteria 的常用查询:
: <syntaxhighlight lang="Java" highlight="">
public void demo_Criteria() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
Criteria criteria = null;
List<Customer> list = null;
// 1. 查询所有记录
criteria = session.createCriteria(Customer.class);
list = criteria.list();
System.out.println(list);
// 2. 条件查询:
criteria = session.createCriteria(Customer.class);
criteria.add(Restrictions.eq("name", "张三"));
list = query.list();
System.out.println(list);
// 3. 条件查询:
criteria = session.createCriteria(Customer.class);
criteria.add(Restrictions.eq("name", "张三"));
criteria.add(Restrictions.eq("age", 38));
list = query.list();
System.out.println(list);
// 4. 分页查询:
criteria = session.createCriteria(Customer.class);
criteria.setFirstResult(3);
criteria.setMaxResults(3);
list = query.list();
System.out.println(list);
tx.commit();
session.close();
}
</syntaxhighlight>
==== 常用方法 ====
Criteria 中除了使用 list() 方法查询全部数据外,还有一些常用方法。
常用方法:
# '''uniqueResult()''':用于返回唯一的结果。
#* 确保查询结果仅有一条记录才可使用;
# '''setFirstResult()''':用于设置获取第一个记录的位置(从第几条记录开始查询)。
#* 默认从 0 开始计算;
# '''setMaxResult()''':用于设置结果集的最大记录数。
setFirstResult() 通常与 setMaxResult() 方法结合使用,用于限制结果集的范围,以实现'''分页功能'''。
=== SQLQuery ===
<span style="color: blue; font-size: 120%;">'''SQLQuery'''</span> 接口:用于接收一个【'''sql 语句'''】进行查询,然后调用 list() 或者 uniqueResult() 方法进行查询。
采用 HQL 或 QBC 检索方式时,Hibernate 生成标准的 SQL 查询语句,适用于所有的数据库平台,因此这两种检索方式都是跨平台的。但有的应用程序可能需要根据底层数据库的 SQL 方言,来生成一些特殊的查询语句。在这种情况下,可以利用 Hibernate 提供的 SQL 检索方式。
    <span style="color: blue">'''但是 sql 语句不会直接封装到实体对象中,需要手动写代码才可以封装为实体中。'''</span>
示例:
# 未封装的查询:(查询结果为基本对象集合)
#: <syntaxhighlight lang="Java" highlight="">
SQLQuery sqlQuery = session.createSQLQuery("select * from cst_customer");
List<Object[]> list = sqlQuery.list();
for (Object [] objects : list) {
System.out.println(Arrays.toString(objects));
}
</syntaxhighlight>
# 封装的查询:(查询结果为实体对象集合)
#: <syntaxhighlight lang="Java" highlight="">
SQLQuery sqlQuery = session.createSQLQuery("select * from cst_customer");
// 封装到对象中
sqlQuery.addEntity(Customer.class);
List<Customer> list = sqlQuery.list();
for(Customer customer:list) {
System.out.println(customer);
}
}
</syntaxhighlight>
</syntaxhighlight>

2022年7月15日 (五) 17:54的最新版本


关于

注意:以下 API 多数为接口,在开发时使用的一般是其实现类。

如:
1、SessionFactory 接口 —— SessionFactoryImpl 类
2、Session 接口 —— SessionImpl 类

见:Hibernate源码分析:入门代码流程

Configuration 类

Configuration 仅仅是作为一个初始化时的对象,一个 Configeration 实例代表 Hibernate 所有 Java 类到 Sql 数据库映射的集合。

Configuration 接口的作用是:对 Hibernate 进行配置、并启动 Hibernate 和连接数据库系统。

作用:

在 Hibernate 的启动过程中,Configuration 类的实例首先定位缺省 XML 配置文件(hibernate.cfg.xml),并读取关的配置项目,然后创建出一个 SessionFactory 对象。
  1. 读取配置文件:
    1. 根据默认的 XML 配置文件:(位置:src/hibernate.cfg.xml)
      		Configuration cfg = new Configuration().configure();
      
    2. 根据自定义的 XML 配置文件:(少用)
      		Configuration cfg = new Configuration().configure("cn/config/hibernate2.cfg.xml");
      
    3. 加载“映射配置文件”:(如果使用“hibernate.properties”作为核心配置文件,则无法在其中配置“映射配置文件”,需要使用 Configuration 对象加载)
      		Configuration cfg = new Configuration().configure();
      		cfg.addResource("com/eijux/domain/Customer.hbm.xml");
      
  2. 创建 SessionFactory 对象:
    • 在 Hibernate 4 之前:
      		Configuration cfg = new Configuration();
      		cfg.configure();
      		SessionFactory sessionFactory = cfg.buildSessionFactory();
      
    • 在 Hibernate 4 之后:【???】
      		Configuration cfg = new Configuration().configure();
      		ServiceRegistry sr = new ServiceRegistryBuilder().applySettings(cfg.getProperties()).buildServiceRegistry();
      		SessionFactory sessionFactory = cfg.buildSessionFactory(sr);
      

SessionFactory 接口

SessionFactory 接口负责 Hibernate 的初始化和建立 Session 对象。


特点:
1、线程安全,同一个实例能够供多个线程共享。
2、重量级,不能随意的创建和销毁它的实例。

所以,通常情况下每一个应用只需要一个 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();
	}
	
	/**
	* 获取当前线程绑定的会话:
	*/
	public static Session getCurrentSession(){ 
		return sessi.onFactory.getCurrentSession(); 
	}
}

连接池

SessionFactory 内部还维护了一个连接池,如果需要使用第三方连接池(如:C3PO),则需要手动进行配置。

详见:Hibernate笔记 2:配置文件详解#配置:连接池

Session 接口

Session 用于管理一个数据库的任务单元(增、删、改、查),它是 Java 应用和 Hibernate 之间主要运行接口,是抽象持久性服务概念的主要 API。


特点:
1、非线程安全,因此最好是一个线程只创建一个Session对象(将它设计为局部对象)。
2、轻量级,创建和销毁 Session 对象不会有太大开销。

    ——【不共享:“一请求”>>“一线程”>>“一session”>>“一事务”】

类似于 JDBC 中的连接(“connection”)。

生成方式

可以通过两种方法产生 Session。

生成方式:

  1. openSession():获取一个新的 Session;
    		Session session = sessionFactory.openSession();
    
    • 每次打开都是新的 Session;
    • 需要调用 close 方法以关闭 Session。
  2. getCurrentSession():从当前上下文中获取 Session,并绑定到当前线程
    		Session session = sessionFactory.getCurrentSession();
    
    • 第一次调用会创建新的 Session 实例,(如未手动管理,则)同一线程中多次获取的是同一个 Session;
    • 无需手动关闭,线程结束时会自动关闭 Session。
    • 必须配置“Session 管理方式”为:(否则会报错“org.hibernate.HinerbateException: No CurrentSessionContext configured!”)
      		<property name="current_session_context_class">thread</property>
      
      【详见:Hibernate笔记 4:核心知识#事务管理

常用方法

Session 的所有方法,见 JBoss 的 Hibernate 文档:https://docs.jboss.org/hibernate/core/3.5/api/org/hibernate/Session.html

常见方法:

  1. save():向数据库中保存(持久化)实体。
    示例:
    		session.save(Object);
    
  2. delete():从数据库中删除实体。
    • 对象删除后,其状态为“Transistent”;
    • 对象需要有 ID;
    示例:
    		session.delete(Object);
    
  3. load():从数据库中加载实体。
    Session.load(Class arg0, Serializable arg1) throws HibernateException
    
    1. 参数:
      • “arg0”:需要加载对象的类,例如:User.class;
      • “arg1”:查询条件(实现了序列化接口的对象),例如:"4028818a245fdd0301245fdd06380001" 字符串已经实现了序列化接口;
        • 如果是数值类类型,则 hibernate 会自动使用包装类。
    2. 返回:
      • 此方法返回类型为 Object,但返回的是“代理对象”(并非实际可用的对象,因为“延迟加载”)。【第一次使用对象时,session 不能关闭】
      • 如果数据库中没有相应的记录,则会抛出异常“找不到对象”(org.hibernate.ObjectNotFoundException)。【记录不存在时抛出异常】
    3. 执行:因为 load 方法实现了“延迟加载”(懒加载,“lazy load”),所以,只有在使用返回的对象时,它才发出查询 SQL 语句,加载对象。
      • 其延迟加载实现原理是代理方式。【???】
    示例:
    		try {
    			session = sf.openSession();
    			session.beginTransaction();
    			User user = (User)session.load(User.class,1);
    			
    			// 在使用对象时,才发出查询SQL语句,加载对象
    			System.out.println("user.name=" + user.getName());
    
    			// 此时 user 为 persistent 状态
    			user.setName("eijux");
    
    			session.getTransaction().commit();
    		} catch (HibernateException e) {
    			e.printStackTrace();
    			session.getTransaction().rollback();
    		} finally{
    			if (session != null){
    			if (session.isOpen())
    			session.close();
    		}
    
  4. get():从数据库中加载实体。
    Session.get(Class arg0, Serializable arg1)
    
    1. 参数:
      • “arg0”:需要加载对象的类,例如:User.class;
      • “arg1”:查询条件(实现了序列化接口的对象),例如:"4028818a245fdd0301245fdd06380001" 字符串已经实现了序列化接口;
        • 如果是数值类类型,则 hibernate 会自动使用包装类。
    2. 返回:
      • 此方法返回类型为 Object,然后我们再强行转换为需要加载的对象就可以了。【返回值需要强制类型转换???】
      • 如果数据库中没有相应的记录,则返回 null。【不会抛出异常】
    3. 执行:该方法会立即发出查询 SQL 语句,加载对象。
    示例:
    		try {
    			session = sf.openSession();
    			session.beginTransaction();
    
    			// 方法返回类型为Object,需要再强行转换为需要加载的对象
    			// 方法会立即发出查询语句
    			User user = (User)session.get(User.class, 1);
    
    			// 数据加载完后的状态为 persistent 状态。数据将与数据库同步
    			System.out.println("user.name=" + user.getName());
    
    			// 此时 user 为 persistent 状态
    			 user.setName("eijux");
    		  
    			 session.getTransaction().commit();
    		} catch (HibernateException e) {
    			 e.printStackTrace();
    			 session.getTransaction().rollback();
    		} finally{
    			 if (session != null){
    			 if (session.isOpen()){
    				 session.close();
    			 }
    		}
    
  5. update():向数据库中更新实体。
    • 用于更新“detached”对象,更新完成后转为为“persistent”状态;【默认更新全部字段】
    • 更新“transient”对象(没有 ID)会报错;
      • 更新自己设定 ID 的“transient”对象则可以。
    • “persistent”状态的对象,只要设定字段不同的值,在 session 提交时,会自动更新(默认更新全部字段)。
    • 如果需要更新部分字段,有两种方法:
      1. update / updatable 属性:用于设置参与更新的字段。【适合 xml、注解 方式】【较少用,不灵活】
        1. xml 方式:(映射关系配置文件中)设置“<property>”标签的“update”属性,以设置在更新时是否参与更新。
          • false:不参与更新;true(默认):参与更新。
          示例:
          		<property name="name" update="false"/>
          
        2. annotation 方式:(映射关系类中)设定“@Column”的“updatable”属性值,以设置在更新时是否参与更新。
          示例:
          		@Column(updatable=false)
          		public String getTitle() {return title;}
          
      2. dynamic-update 属性:用于设置仅更新变更的字段。【只适合 xml 方式,JAP1.0 annotation 没有对应属性】
        在实体类的映射文件(映射关系配置文件)中的“<class>”标签中,设置“dynamic-update”属性:true,表示修改了哪个字段就更新哪个字段,其它字段不更新。
        • 但要求是同一个 session(不能跨 session),如果跨了 session 同样会更新所有的字段内容。
        示例:
        		...
        		<class name="com.bjsxt.Student" dynamic-update="true">
        		...
        
        	@Test
        	public void testUpdate() {
        		Session session = sessionFactory.getCurrentSession();
        		session.beginTransaction();
        		
        		Student s = (Student)session.get(Student.class, 1);
        		s.setName("zhangsan");
        		
        		// 提交时,会只更新 name 字段,因为此时的 s 为 persistent 状态
        		session.getTransaction().commit();
        		
        		
        		s.setName("zhangsi");
        		
        		
        		Session session2 = sessionFactory.getCurrentSession();
        		session2.beginTransaction();
        		
        		// 更新时,会更新所有的字段,因为此时的 s 不是 persistent 状态
        		session2.update(s);
        		session2.getTransaction().commit();
        	}
        
        • 如果需要跨 session 实现更新修改的部分字段,需要使用 session.merget() 方法,合并字段内容:
          示例:
          	@Test
          	public void testUpdate() {
          		Session session = sessionFactory.getCurrentSession();
          		session.beginTransaction();
          		
          		Student s = (Student)session.get(Student.class, 1);
          		s.setName("zhangsan");
          		
          		// 提交时,会只更新 name 字段,因为此时的 s 为 persistent 状态
          		session.getTransaction().commit();
          		
          		
          		s.setName("zhangsi");
          		
          		
          		Session session2 = sessionFactory.getCurrentSession();
          		session2.beginTransaction();
          		
          		// 使用s ession.merget() 方法,合并字段内容
          		session2.merge(s);
          		
          		// 提交时,会只更新 name 字段
          		session2.getTransaction().commit()
          	}
          
          如上,虽然可以实现部分字段更新,但这样会多出一条 select 语句,因为在字段数据合并时,需要比较字段内容是否已变化,就需要从数据库中取出这条记录进行比较。
          所以,跨 Session 更新部分字段,建议使用 HQL(EJBQL)面向对象的查询语言:
          示例:
          	@Test
          	public void testUpdate7() {
          		Session session = sessionFactory.getCurrentSession();
          		session.beginTransaction();
          		
          		Query q = session.createQuery("update Student s set s.name='z5' where s.id = 1");
          		q.executeUpdate();
          		
          		session.getTransaction().commit();
          	}
          
  6. saveOrUpdate():向数据库中保存/更新实体。
    • 在执行的时候 hibernate 会检查,如果对象在数据库中已经有对应的记录(存在同样主键的记录),则会更新(update),否则会添加数据(save)。
  7. clear()清除 session 缓存
    • 无论是 load 还是 get,都会首先查找缓存(一级缓存,也叫“session 缓存”),如果没有,才会去数据库查找,调用 clear() 方法可以强制清除 session 缓存。
    示例:
    		// 使用 getCurrentSession,所以不需要手动关闭 Session
    		Session session = sessionFactory.getCurrentSession();
    		session.beginTransaction();
    		
    		Teacher t = (Teacher)session.load(Teacher.class, 1);
    		System.out.println(t.getName());
    		
    		session.clear();
    		
    		Teacher t2 = (Teacher)session.load(Teacher.class, 1);
    		System.out.println(t2.getName());
    		
    		session.getTransaction().commit();
    
    如上,两个 load 方法均会发送查询到数据库。如果注释掉 clear,则第二次 load 不发送查询到数据库,而是直接使用第一次 load 的缓存(两次 load 的是同一个记录)。
  8. flush()Session 缓存刷出(到数据库)。
    【即,缓存清理,强制同步数据(从内存到数据库) ——见:Hibernate笔记 4:核心知识:Session缓存#缓存清理机制(缓存刷出)
    • 在默认的情况下 session.commit() 之前时,其实执行了一个 flush 命令。 ——【一般不需要手动调用该方法】
    • 可以通过 session.setFlushMode(FlushMode) 来设置“刷新时机”:
  9. evict()从 session 缓存中逐出该对象
    • 与 commit 同时使用,会抛出异常。【???】
      示例:
      		session = HibernateUtils.getSession();
      		tx = session.beginTransaction();
      
      		User user = new User();
      		user.setName("李四");
      		user.setPassword("123");
      		user.setCreateTime(new Date());
      		user.setExpireTime(new Date());
      
      		/* 利用 Hibernate 将实体类对象保存到数据库中。
      		因为 user 主键生成策略采用的是 uuid,所以调用完成 save 后,只是将 user 纳入 session 的管理,不会发出 insert 语句,但是 id 已经生成,session 中的 existsInDatabase 状态为 false
      		*/
      		session.save(user);
      
      		// 从 session 缓存中逐出该对象
      		session.evict(user);
      		
      		/* 无法成功提交。
      		因为 hibernate 在清理缓存时,在 session 的临时集合(insertions)中取出 user 对象进行 insert 操作后,需要更新 entityEntries 属性中的 existsInDatabase 为 true,而我们采用 evict 已经将 user 从 session 中逐出了,所以找不到相关数据,无法更新,抛出异常。
      		*/
      		tx.commit();
      
      • 解决在逐出 session 缓存中的对象不抛出异常的方法:在 session.evict() 之前进行显示的调用 session.flush() 方法就可以了。【???】
        示例:
        		session.save(user);
        
        		/* flush 后 hibernate 会清理缓存,会将 user 对象保存到数据库中,将 session 中的 insertions 中的 user 对象清除,并且会设置 session 中的 existsInDatabase 状态为 false
        		*/
        		session.flush();
        
        		// 从 session 缓存中逐出该对象
        		session.evict(user);
        		
        		/* 可以成功提交。
        		因为 hibernate 在清理缓存时,在 Session 的 insertions 中集合中无法找到 user 对象所以不会发出 insert 语句,也不会更新 session 中 existsInDatabase 的状态。
        		*/
        		tx.commit();
        
  10. persist():做一个瞬态的实例持久化。
    • 在事务里执行 session.persist(),不会向数据库插数据,事务 commit 了才会插入数据。


load() 与 get()

load() 与 get():
1、不存在对应记录时:
    load 抛出异常。
    get 返回 null。
2、返回对象:
    load 返回的是代理对象,等到真正使用对象的内容时才发出 sql 语句,这样就要求在第一次使用对象时,要求 session 处于 open 状态,否则出错。
    get 返回的对象即为 Object。(需要进行强制类型转换,来得到需要的对象类型)
3、加载时机:
    load 进行延迟加载。
    get 进行立即加载。
   
此外,get() 和 load() 只根据主键查询,不能根据其它字段查询,如果想根据非主键查询,可以使用 HQL

Transaction 接口

Hibernate 进行持久化操作时(CRUD)必须进行事务控制。

使用:

  1. 开启事务:
    		Transaction tx = session.beginTransaction();
    
  2. 提交事务:
    		tx.commit();
    
  3. 回滚事务:
    		tx.rollback();
    


示例:

		Transaction tx = null;
		
		try{
			tx = session.beginTransaction();
			session.save(obj);
			tx.commit();
		}catch(HibernateException e){
			if(tx != null){
				tx.rollback();
			}
			throw e;
		}finally{
			if(session != null){
				session.close();
			}
		}

其他 API

以下包括了 Hibernate 的几种种对象检索方式。
  1. Query:HQL 查询;(类似于 SQL)
  2. Criteria:QBC 查询;(无任何语句)
  3. SQLQuery:SQL 查询;

Query


Query 代表面向对象的一个【Hibernate 查询】操作,所使用的语句为 HQL(Hibernate Query Language)。

    其语法很像 SQL 语法,但它是完全“面向对象”的。

使用

在 Hibernate 中,通常使用 session.createQuery() 方法接受一个 HQL 语句, 然后调用 Query 的 list() 或 uniqueResult() 方法执行查询。

使用 Query 对象的步骤:

  1. 获得 Hibernate 的 Session 对象;
  2. 通过 session.createQuery("HQL 语句") 创建查询对象,并编写 HQL 语句;
  3. 如果 HQL 语句包含参数,则调用 Query 的 setXxx() 设置参数;
  4. 调用 Query 对象的 list()uniqueResult() 方法执行查询。


示例,Query 执行 HQL 语句的常用查询:

	public void demo_Query() { 
		Session session = HibernateUtils.openSession(); 
		Transaction tx = session.beginTransaction(); 
	
		Query query = null;
		List<Customer> list = null;
	
		// 1. 查询所有记录
		query = session.createQuery("from Customer");
		
		list = query.list();
		
		System.out.println(list);

	
		// 2. 条件查询:
		query = session.createQuery("from Customer where name = ?");
		query.setString(0, "张三");
		
		list = query.list();
		
		System.out.println(list);
		
		
		// 3. 条件查询:
		query = session.createQuery("from Customer where name = :aaa and age = : bbb");
		query.setString ("aaa", "张三");
		query.setinteger("bbb", 38);
		
		list = query.list();
		
		System.out.println(list);
		
		
		// 4. 分页查询:
		query = session.createQuery("from Customer"); 
		
		query.setFirstResult(3); 
		query.setMaxResults(3); 
		
		list = query.list(); 
		
		System.out.println(list); 
		
		
		tx.commit(); 
		session.close();
	}

常用方法

Query 中除了使用 list() 方法查询全部数据外,还有一些常用方法。

常用方法:

  1. setterXxx():Query 接口中提供了一系列的 setter 方法用于设置查询语句中的参数
    • 针对不同的数据类型,需要用到不同的 setter 方法。
  2. iterator():用于查询语句,返回的结果是一个 Iterator 对象(只能按照顺序读取)。
    • 它仅把使用到的数据转换为 Java 实体对象;【???】
  3. uniqueResult():用于返回唯一的结果。
    • 确保查询结果仅有一条记录才可使用;
  4. executeUpdate():用于支持 HQL 语句的更新和删除操作。
    • Hibernate3 的新特性;
  5. setFirstResult():用于设置获取第一个记录的位置(从第几条记录开始查询)。
    • 默认从 0 开始计算;
  6. setMaxResult():用于设置结果集的最大记录数。
setFirstResult() 通常与 setMaxResult() 方法结合使用,用于限制结果集的范围,以实现分页功能

Criteria


Criteria,又称QBC 查询(Query By Critena),是 Hibernate 框架的核心查询对象。

    它是一个完全“面向对象,可扩展”的条件查询 API,通过它完全“不需要考虑数据库底层如何实现,以及 SQL 语句如何编写”。 

使用

用到的“接口/类”:【注意区别:“Criteria”与“Criterion”】

    1、org.hibernate.Criteria :Hibernate 提供的一个面向对象查询接口。

    2、org.hibernate.criterion.Criterion :Hibernate 提供的一个面向对象查询条件接口。
      ——“一个单独的查询就是 Criterion 接口的一个实例”。
   
    3、org.hibernate.criterion.Restrictions 类:提供了一系列用于设定查询条件的静态方法,用于创建 Criterion 对象

使用 Criteria 对象的步骤:

  1. 获得 Hibernate 的 Session 对象。
  2. 通过 Session 获得 Criteria 对象。
    • 需要
  3. 使用 Restrictions 的静态方法创建 Criterion 条件对象。
    • Restrictions 类中提供了一系列用于设定查询条件的静态方法,这些静态方法都返回 Criterion 实例,每个 Criterion 实例代表个查询条件
  4. 向 Criteria 对象中添加 Criterion 查询条件。
    • Criteria 的 add() 方法用于加入查询条件。
  5. 执行 Criteria 的 list()uniqueResult() 获得结果。


示例,Criteria 的常用查询:

	public void demo_Criteria() { 
		Session session = HibernateUtils.openSession(); 
		Transaction tx = session.beginTransaction(); 
	
		Criteria criteria = null;
		List<Customer> list = null;
	
		// 1. 查询所有记录
		criteria = session.createCriteria(Customer.class);

		list = criteria.list(); 

		System.out.println(list);
	
		// 2. 条件查询:
		criteria = session.createCriteria(Customer.class);
		criteria.add(Restrictions.eq("name", "张三"));
		
		list = query.list();
		
		System.out.println(list);
		
		
		// 3. 条件查询:
		criteria = session.createCriteria(Customer.class);
		criteria.add(Restrictions.eq("name", "张三"));
		criteria.add(Restrictions.eq("age", 38)); 
		
		list = query.list();
		
		System.out.println(list);
		
		
		// 4. 分页查询:
		criteria = session.createCriteria(Customer.class);
		
		criteria.setFirstResult(3); 
		criteria.setMaxResults(3); 
		
		list = query.list(); 
		
		System.out.println(list); 
		
		
		tx.commit(); 
		session.close();
	}

常用方法

Criteria 中除了使用 list() 方法查询全部数据外,还有一些常用方法。

常用方法:

  1. uniqueResult():用于返回唯一的结果。
    • 确保查询结果仅有一条记录才可使用;
  2. setFirstResult():用于设置获取第一个记录的位置(从第几条记录开始查询)。
    • 默认从 0 开始计算;
  3. setMaxResult():用于设置结果集的最大记录数。
setFirstResult() 通常与 setMaxResult() 方法结合使用,用于限制结果集的范围,以实现分页功能

SQLQuery

SQLQuery 接口:用于接收一个【sql 语句】进行查询,然后调用 list() 或者 uniqueResult() 方法进行查询。

采用 HQL 或 QBC 检索方式时,Hibernate 生成标准的 SQL 查询语句,适用于所有的数据库平台,因此这两种检索方式都是跨平台的。但有的应用程序可能需要根据底层数据库的 SQL 方言,来生成一些特殊的查询语句。在这种情况下,可以利用 Hibernate 提供的 SQL 检索方式。
    但是 sql 语句不会直接封装到实体对象中,需要手动写代码才可以封装为实体中。

示例:

  1. 未封装的查询:(查询结果为基本对象集合)
    		SQLQuery sqlQuery = session.createSQLQuery("select * from cst_customer"); 
    		
    		List<Object[]> list = sqlQuery.list(); 
    		for (Object [] objects : list) { 
    			System.out.println(Arrays.toString(objects)); 
    		}
    
  2. 封装的查询:(查询结果为实体对象集合)
    		SQLQuery sqlQuery = session.createSQLQuery("select * from cst_customer"); 
    		
    		// 封装到对象中
    		sqlQuery.addEntity(Customer.class); 
    		
    		List<Customer> list = sqlQuery.list(); 
    		for(Customer customer:list) { 
    			System.out.println(customer); 
    		}