Hibernate学习笔记二
一、持久化类的编写规则
1、持久化类的概述
持久化:将内存中的一个对象持久化到数据库中的过程.Hibernate 框架就是用来持久化的框架
持久化类:一个 Java 类与数据库中的表建立映射关系.那么这个类在 Hibernate 中称为持久化类
持久化类 = Java 类 + 映射文件
2、持久化类的编写规则
- 对持久化类提供一个无参构造方法 :Hibernate 底层需要使用反射生成实例
- 属性需要私有,私有的属性提供 get 和 set 方法 :Hibernate 中获取、设置对象的值
- 对持久化类提供一个唯一标识 OID 与数据库主键对应 :Java 中通过内存地址区分是否是同一个
- 对象,数据库中通过主键区分是否为同一条记录,Hibernate 中通过 OID 区分是否为同一个对象
- 持久化类中属性尽量使用包装类 :因为基本数据类型默认值是:0,0有很多歧义.包装类默认值为 null
- 持久化类不要使用 final 修饰 :延迟加载本身是 Hibernate 的一个优化手段,返回一个代理对象(javassist可以对没有实现接口的类产生代理--使用类非常底层的字节码增强技术,继承这个类进行代理)。如果不能被继承,就不能产生代理对象,延迟加载也就失效了。load和 get 方法一致。
二、主键生成策略
1、主键的分类
-
自然主键
自然主键:主键本身就是表中的一个字段(实体类中的一个属性)。创建一个人员表,使用身份证(唯一不可重复)作为主键,这种主键称为自然主键 -
代理主键
代理主键:主键本身不是表中必须的一个字段(不是实体中的具体的属性)。创建一个人员表,不使用身份证作为主键,使用不相关的ID作为主键,这种主键称为代理主键。实际开发中,尽量使用代理主键
2、主键的生成策略
Hibernate 的主键生成策略,在实际开发中一般不允许用户手动设置主键,一般将主键交给数据库,或者手动编写程序进行设
置。在 Hibernate 中为了减少代码编写,提供了很多种主键生成的策略。
-
increment
Hibernate 中提供的自动增长机制,适用 short int lang 类型的主键,在单线程程序中使用首先发送一条SQL语句:select max(id) from 表; 然后让 id+1,作为下一条记录的主键 -
identity
适用 short int lang 类型的主键,使用的是数据库底层的自动增长机制.适用于有自动增长机制的数据库(MySQL), Oracle 没有自动增长机制. -
sequence
适用于 short int lang 类型的主键,采用序列的方式.(Oracle支持序列),MySQL 不支持序列. -
uuid
适用于字符串类型的主键,使用 Hibernate 中随机的方式生成字符串主键 -
native
本地策略,可以在 identity 和 sequence 之间切换. -
assigned
Hibernate 放弃外键的管理,需要通过手动编写程序和用户自己设置. -
foreign
外部的,在一对一的关联映射情况下使用.
三、持久化类的三种状态
Hibernate 是持久层的 ORM 框架,专注于数据的持久化工作。在进行数据持久化操作时,持久化对象可能处于不同的状态当中。这些状态可分为三种,分别为瞬时态、持久态和脱管态。下面分别针对这三种状态进行简单介绍。
1、三种状态的介绍
-
瞬时态(transient)
瞬时态也称为临时态或者自由态,瞬时态的对象是由 new 关键字开辟内存空间的对象,不存在持久化标识 OID(相当于主键值),且未与任何的 Session 实例相关联,在数据库中也没有记录,失去引用后将被 JVM 回收。瞬时对象在内存孤立存在,它是携带信息的载体,不和数据库的数据有任何关联关系。 -
持久态(persistent)
持久态的对象存在一个持久化标识 OID,当对象加入到 Session 缓存中时,就与 Session 实例相关联。它在数据库中存在与之对应的记录,每条记录只对应唯一的持久化对象。需要注意的是,持久态对象是在事务还未提交前变成持久态的。 -
脱管态(detached)
脱管态也称离线态或者游离态,当持久化对象与 Session 断开时就变成了脱管态,但是脱管态依然存在持久化标识 OID,只是失去了与当前 Session 的关联。需要注意的是,脱管态对象发生改变时Hibernate 是不能检测到的。
2、三种状态的区分
package com.qidishixun.Hibernate;
import com.qidishixun.Hibernate.domain.Customer;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import java.io.Serializable;
public class HibernateDemo2 {
@Test
public void test1(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Customer customer = new Customer();
//瞬时态对象:没有唯一标识OID,被session 管理
customer.setCust_name("张三丰");
Serializable id = session.save(customer);
//持久态对象:有唯一表示OID,被session 管理
Customer customer2 = session.get(Customer.class,id);
transaction.commit();
session.close();
//托管态对象:有唯一表示OID, 没有被session管理,session已经close了
System.out.println("客户名称:" + customer.getCust_name());
}
}
3、三种状态转换
- 三种状态转换图
- 瞬时态对象
获得
Customer customer = new Customer();
状态转换
瞬时 --> 持久
save(Object obj)、saveOrUpdate(Object obj)
瞬时 --> 托管
customer.setCust_id(1L);
- 持久态对象
获得
get()、load()
状态转换
持久 --> 瞬时
delete();
持久 --> 托管
close()、clear()、evict()
- 托管态对象
获得
Customer customer = new Customer();
customer.setCust_id(1L);
状态转换
托管 --> 持久
update()、saveOrUpdate();
托管 --> 瞬时
customer.setCust_id(null);
4、持久态对象的特性
- 持久态对象可以自动更新数据库
@Test
public void test2(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
//获得持久态对象 get load
Customer customer = session.get(Customer.class, 1L);
customer.setCust_name("王娜");
// session.update(customer);
transaction.commit();
session.close();
}
四、Hibernate 的一级缓存
1、Hibernate 的一级缓存
Hibernate 的一级缓存就是指 Session 缓存,Session 缓存是一块内存空间,用来存放相互管理的Java 对象,在使用 Hibernate 查询对象的时候,首先会使用对象属性的 OID 值在 Hibernate 的一级缓存中进行查找,如果找到匹配的 OID 值的对象,就直接将该对象从一级缓存中取出使用,不会再查询数据库,如果没有找到相同 OID 值的对象,则会去数据库中查找响应数据。当从数据库中查询到所需数据时,该数据信息也会放置到一级缓存中。Hibernate 的一级缓存的作用就是减少对数据库访问的次数。
在 Session 接口的实现中包含一系列的 Java 集合,这些 Java 集合构成了 Session 缓存。只要Session 实例没有结束生命周期,存放在它缓存中的对象也不会结束生命周期。固一级缓存也被称为Session 级别的缓存。
Hibernate 的一级缓存有如下特点:当应用程序调用 Session 接口的 sava()、update、saveOrUpdate
2、证明 Hibernate 的一级缓存存在
package com.qidishixun.Hibernate;
import com.qidishixun.Hibernate.domain.Customer;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
/**
* Hibernate 的一级缓存
* @ClassName: HibernateDemo3
* @Author Gui
* @Date 2021/6/28
* @Version 1.0
*/
public class HibernateDemo3 {
@Test
public void test1(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Customer customer1 = session.get(Customer.class, 1L);
System.out.println(customer1);
Customer customer2 = session.get(Customer.class, 1L);
System.out.println(customer2);
System.out.println(customer1 == customer2);
transaction.commit();
session.close();
}
}
五、Hibernate 事务管理
1、绑定线程的 Session
Hibernate5 中自身提供了三种管理 Session 对象的方法
- Session 对象的生命周期与本地线程绑定
- Session 对象的生命周期与 JTA 事务绑定
- Hibernate 委托程序管理 Session 对象的声明周期
在 Hibernate 配置文件中,hibernate.current_session_context_class 属性用于指定 Session 管理方式,可选值包括
- thread: Session 对象的生命周期与本地线程绑定
- jta: Session 对象的生命周期与 JTA 事务绑定
- managed: Hibernate 委托程序管理 Session 对象的声明周期
在 hibernate.cfg.xml 配置文件中进行如下配置:
<!-- 配置 Session 绑定本地线程 -->
<property name="hibernate.current_session_context_class">thread</property>
2、修改 HibernateUtils 工具类
/**
* 提供获得 Session方法
* @return
*/
public static Session getCurrentSession(){
return sessionFaction.getCurrentSession();
}
测试
@Test
public void test3(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
Customer customer = new Customer();
customer.setCust_name("大哥哥");
session.save(customer);
transaction.commit();
//这里不需要关闭session,因为线程结束Session自动销毁
}
六、Hibernate 的其他 API
1、Query
Query 代表面向对象的一个 Hibernate 操作. 在 Hibernate 中通常使用 session.createQuery() 方法接收一个 HQL 语句,然后使用 query 的 list() 或 uniqueResult() 方法执行查询. 所谓的 HQL 是Hibernate Query Language 的缩写,其语法很像 SQL 但是它是完全面向对象的.在 Hibernate 中使用 Query 的步骤:
1. 获得 Hibernate 的 Session 对象
2. 编写 HQL 语句
3. 调用 session.createQuery() 创建查询对象
4. 如果 HQL 语句包含参数,则调用 Query 的 setXXX 方法设置参数
5. 调用 Query 的 list() 或 uniqueResult() 方法执行查询
- 查询所有
package com.qidishixun.Hibernate;
import com.qidishixun.Hibernate.domain.Customer;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import java.util.List;
/**
* 利用Hibernate API 查询数据库表
* @ClassName: HibernateDemo4
* @Author Gui
* @Date 2021/6/28
* @Version 1.0
*/
public class HibernateDemo4 {
@Test
public void test1(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
String hql = "from Customer";
Query query = session.createQuery(hql);
List<com.qidishixun.Hibernate.domain.Customer> customers = query.list();
for (com.qidishixun.Hibernate.domain.Customer customer :customers){
System.out.println(customer);
}
transaction.commit();
}
}
- 条件查询
/**
* 模糊查询
*/
@Test
public void test2(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
String hql = "from Customer where cust_name like ?";
Query query = session.createQuery(hql);
query.setParameter(0, "大%");
List<com.qidishixun.Hibernate.domain.Customer> customers = query.list();
for (com.qidishixun.Hibernate.domain.Customer customer : customers){
System.out.println(customer);
}
transaction.commit();
}
- 分页查询
/**
* 分页查询
*/
@Test
public void test3(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
String hql = "from Customer";
Query query = session.createQuery(hql);
//设置分页查询的条件
query.setFirstResult(3); //从几开始
query.setMaxResults(3); //每页显示几条
List<com.qidishixun.Hibernate.domain.Customer> customers = query.list();
for (Customer customer : customers){
System.out.println(customer);
}
transaction.commit();
}
2、Criteria
Criteria:QBC查询(Query By Criteria) ,更加面向对象的一种查询方式
- 查询所有
package com.qidishixun.Hibernate;
import com.qidishixun.Hibernate.domain.Customer;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;
import org.junit.Test;
import java.util.List;
/**
* 更加面向对象的一种查询
* @ClassName: HibernateDemo5
* @Author Gui
* @Date 2021/6/28
* @Version 1.0
*/
public class HibernateDemo5 {
@Test
public void test1(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
//通过 Session 获取 criteria
Criteria criteria = session.createCriteria(com.qidishixun.Hibernate.domain.Customer.class);
List<com.qidishixun.Hibernate.domain.Customer> customers = criteria.list();
for (com.qidishixun.Hibernate.domain.Customer customer : customers){
System.out.println(customer);
}
transaction.commit();
}
}
- 条件查询
@Test
public void test2(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
//通过Session 获取 criteria
Criteria criteria = session.createCriteria(com.qidishixun.Hibernate.domain.Customer.class);
//设置条件
criteria.add(Restrictions.ilike("cust_name","小%"));
List<com.qidishixun.Hibernate.domain.Customer> list = criteria.list();
for (com.qidishixun.Hibernate.domain.Customer customer : list){
System.out.println(customer);
}
transaction.commit();
}
- 分页查询
/**
* 分页查询
*/
@Test
public void test3(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
//通过 Session 获取 criteria
Criteria criteria = session.createCriteria(com.qidishixun.Hibernate.domain.Customer.class);
//设置分页
criteria.setFirstResult(1); //跳过几个开始查询
criteria.setMaxResults(3);
List<com.qidishixun.Hibernate.domain.Customer> list = criteria.list();
for (Customer customer : list){
System.out.println(customer);
}
transaction.commit();
}
3、SQLQuery
/**
* HQL 和 SQL 的写法
*/
@Test
public void test4(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
SQLQuery sqlQuery = session.createSQLQuery("select * from cst_customer");
List<Object[]> list1 = sqlQuery.list();
for (Object[] object : list1){
System.out.println(object.toString());
}
transaction.commit();
session.close();
}