1. Hibernate的持久化类和对象标识符
1.1 持久化类的编写规范
1.1.1 什么是持久化类
Hibernate是持久层的ORM映射框架,专注于数据的持久化工作。
- 持久化就是将内存中的数据永久存储到关系型数据库中。
- 持久化类指的是一个Java类与数据库表建立了映射关系,那么这个类称为是持久化类。其实你可以简单的理解为持久化类就是一个Java类有了一个映射文件与数据库的表建立了关系。
1.1.2 持久化类的编写规范
应该遵循JavaBean的编写规范:
- Bean:在软件开发中是指的可重用的组件。
- JavaBean:指的是用java语言编写的可重用组件。在我们的实际项目中:domain,service,dao都可以看成是JavaBean。
编写规范:
- 类都是public的
- 一般实现序列化接口
- 类成员(字段)都是私有的
- 私有类成员都有公有get/set方法
- 类都有默认无参构造函数
细节:
数据类型的选择问题:
基本类型和包装类,选择哪个?由于包装类可以有null值。所以实际开发中都是用包装类。
1.2 Hibernate中对象标识符(OID)
OID全称是Object Identifier,又叫做对象标识符。
它是hibernate用于区分两个对象是否是同一个对象的标识。
我们都知道,虚拟机内存区分两个对象看的是内存的地址是否一致。数据库区分两个对象,靠的是表的主键。Hibernate负责把内存中的对象持久化到数据库表中,靠的就是对象标识符来区分两个对象是否是同一个。实体类中映射主键的字段就是OID,如下图所示:
1.3 Hibernate的主键生成策略
2. Hibernate的一级缓存和对象状态
2.1 Hibernate的一级缓存
什么缓存?
它就是内存中的临时数据。
什么样的数据适用于缓存,什么样的数据不适用缓存?
适用缓存的数据:
经常查询的,并且不经常修改的。同时数据一旦出现问题,对最终结果影响不大的。
不适用缓存的数据:
不管是否经常查询,只要是经常修改的,都可以不用缓存。并且如果数据由于使用缓存,产生了异常数据,对最终结果影响很大,则不能使用。例如:股市的牌价,银行的汇率,商品的库存等等。
2.1.1 Hibernate中的一级缓存
Hibernate的一级缓存就是指Session缓存,Session缓存是一块内存空间,用来存放相互管理的java对象,在使用Hibernate查询对象的时候,首先会使用对象属性的OID值在Hibernate的一级缓存中进行查找,如果找到匹配OID值的对象,就直接将该对象从一级缓存中取出使用,不会再查询数据库;如果没有找到相同OID值的对象,则会去数据库中查找相应数据。当从数据库中查询到所需数据时,该数据信息也会放置到一级缓存中。Hibernate的一级缓存的作用就是减少对数据库的访问次数。
在 Session 接口的实现中包含一系列的 Java 集合, 这些 Java 集合构成了 Session 缓存。只要 Session 实例没有结束生命周期,存放在它缓存中的对象也不会结束生命周期。固一级缓存也被称为是Session基本的缓存。
Hibernate的一级缓存有如下特点:
- 当应用程序调用Session接口的save()、update()、saveOrUpdate时,如果Session缓存中没有相应的对象,Hibernate就会自动的把从数据库中查询到的相应对象信息加入到一级缓存中去。
- 当调用Session接口的load()、get()方法,以及Query接口的list()、iterator()方法时,会判断缓存中是否存在该对象,有则返回,不会查询数据库,如果缓存中没有要查询对象,再去数据库中查询对应对象,并添加到一级缓存中。
- 当调用Session的close()方法时,Session缓存会被清空。
2.1.2 测试一级缓存
1 | /** |
2.1.3 快照机制
Hibernate 向一级缓存放入数据时,同时复制一份数据放入到Hibernate快照中,当使用commit()方法提交事务时,同时会清理Session的一级缓存,这时会使用OID判断一级缓存中的对象和快照中的对象是否一致,如果两个对象中的属性发生变化,则执行update语句,将缓存的内容同步到数据库,并更新快照;如果一致,则不执行update语句。Hibernate快照的作用就是确保一级缓存中的数据和数据库中的数据一致。
1 |
|
2.2 对象的状态
2.2.1 对象的状态说明
Hibernate为了更好的来管理持久化类,特将持久化类分成了三种状态。在Hibernate中持久化的对象可以划分为四种状态,分别是瞬时态、持久态、脱管态和删除状态,一个持久化类的实例可能处于四种不同状态中的某一种,四种状态的详细介绍如下。
瞬时态(transient)
瞬时态也称为临时态或者自由态,瞬时态的实例是由new命令创建、开辟内存空间的对象,不存在持久化标识OID(相当于主键值),尚未与Hibernate Session关联,在数据库中也没有记录,失去引用后将被JVM回收。瞬时状态的对象在内存中是孤立存在的,与数据库中的数据无任何关联,仅是一个信息携带的载体。
持久态(persistent)
持久态的对象存在持久化标识OID ,加入到了Session缓存中,并且相关联的Session没有关闭,在数据库中有对应的记录,每条记录只对应唯一的持久化对象,需要注意的是,持久态对象是在事务还未提交前变成持久态的。
脱管态(detached)
脱管态也称离线态或者游离态,当某个持久化状态的实例与Session的关联被关闭时就变成了脱管态。脱管态对象存在持久化标识OID,并且仍然与数据库中的数据存在关联,只是失去了与当前Session的关联,脱管状态对象发生改变时Hibernate不能检测到。
删除状态(了解)
2.2.2 学习对象状态我们要明确的
是为了更好的掌握hibernate中操作的方法。
区分状态只有两个标识:一是否有OID,二是否和Session建立的关系
瞬时状态(临时状态)
标志:没有OID,和Session没有关系。
持久化状态
标志:有OID,和Session有关系。只有持久化状态的对象才会有一级缓存的概念。
脱管状态(游离状态)
标志:有OID,和Session没有关系。
删除状态(了解):
标志:有OID,和Session有关系。同时已经调用了删除方法,即将从数据库中把记录删除。但是事务还没有提交,此时的对象状态是删除态。
1 |
|
1 |
|
3. Hibernate的事务控制
3.1 配置Session和线程绑定
保证在Service中开启的事务时使用的Session对象和DAO中多个操作使用的是同一个Session对象。
在hibernate.cfg.xml文件中配置
1
2<!-- 把session和线程绑定,从而实现一个线程只有一个Session -->
<property name="hibernate.current_session_context_class">thread</property>获取Session时使用的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29/**
* 抽取hibernate的工具类
*
* @author wgy
*/
public class HibernateUtil {
private static SessionFactory factory;
//了解:hibernate把可以预见的异常都转成了运行时异常
static {
try {
Configuration configuration = new Configuration();
configuration.configure();
factory = configuration.buildSessionFactory();
} catch (ExceptionInInitializerError e) {
throw new ExceptionInInitializerError("初始化SessionFactory失败,请检查配置文件");
}
}
/**
* 从当前线程上获取Session对象
* @return session
*/
public static Session getCurrentSession(){
//只有配置了把session和线程绑定之后,才能使用此方法,否则返回值是null
return factory.getCurrentSession();
}
}验证session和线程绑定的配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public void test1() {
Session s1 = HibernateUtil.getCurrentSession();
Session s2 = HibernateUtil.getCurrentSession();
// true
System.out.println(s1 == s2);
}
/**
* 当我们把session和线程绑定之后,hibernate就会在提交或者回滚事务之后,自动帮我们关闭session
*/
public void test2() {
//瞬时状态
Customer c = new Customer();
c.setCustName("测试_getCurrentSession");
Session s1 = HibernateUtil.getCurrentSession();
Transaction tx1 = s1.beginTransaction();
s1.saveOrUpdate(c);
tx1.commit();
//s1.close();
}
4. Hibernate中的查询方式
hibernate中一共有5种查询方式
OID查询:
根据id查询一个实体。涉及的方法:get和load
SQL查询:
使用SQL语句查询数据库。涉及两种方式:
第一种:SQLQuery(一般不怎么用)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void testFindAll() {
Session s = HibernateUtil.openSession();
Transaction tx = s.beginTransaction();
//使用session对象,获取一个查询对象Query
SQLQuery sqlquery = s.createSQLQuery("select * from cst_customer");
//使用sqlquery对象获取结果集
List<Object[]> list = sqlquery.list();
for (Object[] os : list) {
System.out.println("------------数组中的内容-----------");
for (Object o : os) {
System.out.println(o);
}
}
tx.commit();
s.close();
}第二种:session的doWork方法,它可以拿到Connection
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20/**
* hibernate中如何使用原始JDBC API
* JDBC的API:
* Connection
* Statement
* PreparedStatement
* ResultSet
*/
public void test1() {
//1.获取Session对象
Session s = HibernateUtil.openSession();
//2.调用doWork方法
s.doWork(new Work() {
public void execute(Connection conn) throws SQLException {
System.out.println(conn.getClass().getName());
}
});
}
HQL查询:
使用HQL语句查询数据库
QBC查询:
使用Criteria对象查询数据库
对象导航查询:
对象图导航检索方式是根据已经加载的对象,导航到他的关联对象。它利用类与类之间的关系来检索对象。
5. Hibernate查询对象的API
5.1 Query
5.1.1 概述
Query代表面向对象的一个Hibernate查询操作。
在Hibernate中,通常使用session.createQuery()方法接受一个HQL语句,然后调用Query的list()或uniqueResult()方法执行查询。
所谓的HQL是Hibernate Query Language缩写,其语法很像SQL语法,但它是完全面向对象的。
在Hibernate中使用Query对象的步骤,具体所示:
- 获得Hibernate的Session对象
- 编写HQL语句
- 调用session.createQuery 创建查询对象
- 如果HQL语句包含参数,则调用Query的setXxx设置参数
- 调用Query对象的方法执行查询
HQL的说明:
把表的名称换成实体类名称。把表字段名称换成实体类属性名称。
例如:
1 | SQL:select * from cst_customer where cust_name like ? |
5.1.2 常用查询
5.1.2.1 基本查询
1 | /** |
5.1.2.2 条件查询
1 | /** |
5.1.2.3 分页查询
1 | /** |
5.1.2.4 排序查询
1 | /** |
5.1.2.5 统计查询
1 | /** |
5.1.2.6 投影查询
1 | /** |
1 | /** |
5.1.3 Query中的方法说明
- list方法:该方法用于查询语句,返回的结果是一个list集合。
- uniqueResult方法:该方法用于查询,返回的结果是一个Object对象。
- setter方法:Query接口中提供了一系列的setter方法用于设置查询语句中的参数,针对不同的数据类型,需要用到不同的setter方法。
- uniqueResult()方法:该方法用于返回唯一的结果,在确保只有一条记录的查询时可以使用该方法。
- setFirstResult()方法:该方法可以设置获取第一个记录的位置,也就是它表示从第几条记录开始查询,默认从0开始计算。
- setMaxResult()方法:该方法用于设置结果集的最大记录数,通常与setFirstResult()方法结合使用,用于限制结果集的范围,以实现分页功能。
5.2 Criteria
5.2.1 概述
Criteria是一个完全面向对象,可扩展的条件查询API,通过它完全不需要考虑数据库底层如何实现,以及SQL语句如何编写,它是Hibernate框架的核心查询对象。
Criteria 查询,又称为QBC查询(Query By Criteria),它是Hibernate的另一种对象检索方式。
通常,使用Criteria对象查询数据的主要步骤,具体如下:
- 获得Hibernate的Session对象
- 通过Session获得Criteria对象
- 使用Restrictions的静态方法创建Criterion条件对象。Restrictions类中提供了一系列用于设定查询条件的静态方法,这些静态方法都返回Criterion实例,每个Criterion实例代表一个查询条件
- 向Criteria对象中添加Criterion 查询条件。Criteria的add()方法用于加入查询条件
- 执行Criterita的 list() 或uniqueResult() 获得结果
细节:
HQL能查的,QBC都能查,反之亦然。
5.2.2 常用查询
5.2.2.1 基本查询
1 | /** |
5.2.2.2 条件查询
1 | /** |
5.2.2.3 分页查询
1 | /** |
5.2.2.4 排序查询
1 | /** |
5.2.2.5 统计查询
1 | /** |
5.2.2.6 离线查询
1 | /** |
5.2.3 QBC常用查询条件说明
短语 | 含义 |
---|---|
Restrictions.eq | 等于= |
Restrictions.allEq | 使用Map,使用key/value进行多个等于的判断 |
Restrictions.gt | 大于> |
Restrictions.ge | 大于等于>= |
Restrictions.lt | 小于< |
Restrictions.le | 小于等于<= |
Restrictions.between | 对应sql的between子句 |
Restrictions.like | 对应sql的like子句 |
Restrictions.in | 对应sql的in子句 |
Restrictions.and | and 关系 |
Restrictions.or | or关系 |
Restrictions.sqlRestriction | Sql限定查询 |
Restrictions.asc() | 根据传入的字段进行升序排序 |
Restrictions.desc() | 根据传入的字段进行降序排序 |
运算类型 | HQL运算符 | QBC运算方法 |
---|---|---|
type | = | Restrictions.eq() |
<> | Restrictions.not(Restrictions.eq()) | |
>= | Restrictions.ge() | |
< | Restrictions.lt() | |
<= | Restrictions.le() | |
is null | Restrictions.isNull() | |
is not null | Restrictions.isNotNull() | |
范围运算符 | in | Restrictions.in() |
not in | Restrictions.not(Restrictions.in()) | |
between | Restrictions.between() | |
not between | Restrictions.not(Restrictions.between()) |
-------------本文结束感谢您的阅读-------------
本文标题: Hibernate(二)
本文链接: https://wgy1993.gitee.io/archives/4074cb7b.html
版权声明: 本作品采用 CC BY-NC-SA 4.0 进行许可。转载请注明出处!
