Hibernate第二天:Hibernate的一级缓存、其他的API


目录

​Hibernate第二天:Hibernate的一级缓存、其他的API​




​1持久化类的编写规则​

​1.2持久化类的编写规则​

​2主键生成策略​

​2.1主键的分类​

​2.1.1自然主键​

​2.1.2代理主键​

​2.2主键生成策略​

​3持久化类的三种状态​

​3.1持久化类的三种状态​

​3.2区分三种状态对象​

​3.3持久化类的状态转换(了解)​

​3.4持久化类持久态对象自动更新数据库​

​4Hibernate的一级缓存​

​4.1缓存概述​

​4.2Hibernate缓存​

​4.2.1Hibernate一级缓存​

​4.2.2证明Hibernate一级缓存存在​

​4.2.3Hibernate一级缓存结构​

​5Hibernate的事务管理​

​5.1什么是事务​

​5.2事务的特性​

​5.3如果不考虑隔离性,引发安全性问题​

​5.3读问题的解决​

​5.4Hibernate设置事务隔离级别​

​5.5Hibernate解决Service的事务管理​

​6Hibernate的其他API​

​6.1Query​

​6.2Criteria​

​6.3SQLQuery​



1持久化类的编写规则

1.1什么是持久化类


持久化,将内存中的一个对象持久化到数据库的过程。Hibernate框架就是用来进行持久化的框架。

持久化类,一个Java对象与数据库表建立了映射关系,那么这个类在Hibernate中称为持久化类。

持久化类=Java类+映射文件。


1.2持久化类的编写规则


  1. 持久化类提供一个无参的构造方法            Hibernate底层需要使用反射生成实例。
  2. 属性需要私有,对私有属性提供public的set和get方法:Hibernate中获取,设置对象的值。
  3. 对持久化类提供一个唯一的标识OID与数据库主键对应:Java中通过对象的地址区是否是同一个对象,数据库表中通过主键绑定是否是同一个记录,在Hibernate中通过持久化类的OID的属性区分是否是同一个对象。
  4. 持久化类中的属性,尽量使用包装类类型:因为基本数据类型默认值是0,会有很多歧义,包装类默认值为NUll。
  5. 持久化类不要用使用final进行修饰:延迟加载本身是hibernate一个优化的手段,返回的是一个代理对象(javassist可以对没有实现接口的类产生代理-使用了非常底层的字节码增强技术,继承这个类进行代理),如果不能继承,不能产生代理对象,延迟加载就会失效,load()和get()方法一致。

2主键生成策略

2.1主键的分类

2.1.1自然主键

  1. 自然主键,主键的本身就是表中的一个字段(实体中的一个具体属性)。
  2. 创建一个人员表,人员就会有一个身份证号(唯一且不可重复),使用了身份证号作为主键,这种主键称为是自然主键。



2.1.2代理主键

  1. 代理主键,主键的本身不是表中必须的一个字段(不是实体中的某个具体属性)。
  2. 创建一个人员表,没有使用人员中的身份证号,用了一个与这个表不相关的字段ID,(PNO)。这种主键称为是代理主键。

在实际开发中,尽量使用代理主键,因为一旦主键参与到业务逻辑中,后期可能需要修改原代码。好的程序设计满足OCP原则,对程序的扩展是Open的,对修改源码是close的。


2.2主键生成策略

在实际开发中,一般不允许用户手动设置主键,一般将主键交给数据库,或者手动编写程序进行设置。在Hibernate中为了减少程序编写,提供了很多主键生成策略。



  1. Increment :hibernate中提供的自动增长机制,适用short,int,long类型党的主键,在单线程中使用。首先发送一条语句,select id  from 表,然后让id+1作为下一条记录的主键。
  2. Identity:自动增长,适用short,int,long类型的主键,使用的是数据库底层的自动增长,适用于有自动增长机制的数据库(MySQL,MSSQL),Oracle没有自动增长。
  3. Sequence:自动增长,适用short,int,long类型的主键,采用序列方式(Oracle支持序列)。Mysql不能使用。
  4. UUID:适用于字符串类型,使用Hibernate中的随机方式生成字符串主键。
  5. Native:本地策略,可以在Identity和Sequence之间进行自动切换。
  6. Assigned:hibernate放弃外键管理,需要通过手动编写程序或者自己设置。
  7. Foreign:外部的,一对一的关联映射的情况下使用。(了解)



3持久化类的三种状态

3.1持久化类的三种状态

Hibernate是持久层框架,通过持久化类完成ORM操作,为了更好的管理持久化类,hIbernate把持久化类分层三种转态。

持久化类=Java类+映射


(1)瞬时态(Transient):没有唯一标识OID,没有被Session管理。


(2)持久态(Persistent):有唯一标识OID,被Session管理。

(持久化类的持久态对象,可以自动更新数据库)


(3)脱管态(Detached):有唯一标识OID,没有被Session管理。


3.2区分三种状态对象


@Test

// 三种状态区分

public void demo1() {



// 1通过工具类获取Session

Session session = HibernateUtils.openSession();

// 2开启事务

Transaction tx = session.beginTransaction();

// 3操作

// 向数据库插入一条记录

Customer Customer = new Customer(); // 1.瞬时态:没有位移标识OID(主键id),没有被session管理



Customer.setCust_name("小涵涵"); //



session.save(Customer); // 2.持久太:有唯一标识OID,被session管理

// 4事务提交 //

tx.commit(); //

// 5释放资源 //

session.close(); //



System.out.println(Customer.getCust_name()); // 3.托管态:有唯一标识OID,没有被session管理

}


3.3持久化类的状态转换(了解)

Hibernate第二天:Hibernate的一级缓存、其他的API_主键


  1. 瞬时态:

获得:由new关键字创建


  1. 瞬时态转换为持久态:执行Session中的save()方法或saveOrUpdate0方法
  2. 瞬时态转换为脱管态:为瞬时态对象设置持久化标识OID
    Customer customer = new Customer)://瞬时态customersetCust id(1); //脱管态

(2)持久态,

获得,通过Session的get()、load()方法或者Quey查询从数据库中获得.


  1. 持久态转换为瞬时态:执行Session中的delete()方法。
  2. 持久态转换为脱管态:执行Session的evict()、close()或clear()方法用于清除一级缓存中某个对象,clear()清除一级缓存 中的所有对象。

(3)脱管态,

获得,脱管态无法获得,只能由其他状态转换而来。


  1. 脱管态转换为持久态, 执行Session的update()、 saveOrUpdate()或lock()方法。
  2. 脱管态转换为瞬时态,将脱管态对象的持久化标识OID设置为null

3.4持久化类持久态对象自动更新数据库

@Test

/****

* 持久太的对象可以以自动更新数据库

*/

public void demo2() {



// 1通过工具类获取Session

Session session = HibernateUtils.openSession();

// 2开启事务

Transaction tx = session.beginTransaction();

// 3操作

/** 获取一个持久太对象了 **/

Customer Customer = (Customer) session.get(Customer.class, 1l);

Customer.setCust_name("王哈哈");

/** 此处可以省略一个update(如果此处数据和数据库一样,不执行Update()) **/

//session.update(Customer);

// 4事务提交

tx.commit();

// 5释放资源

session.close();

}

4Hibernate的一级缓存

4.1缓存概述

缓存是一种优化的方式,将一些数据放在内存,使用的时候直接从缓存中获取,不用通过数据源。

4.2Hibernate缓存

Hibernate第二天:Hibernate的一级缓存、其他的API_主键_02

4.2.1Hibernate一级缓存

Hibernate一级缓存又称为“Session的缓存”。

Session内置不能被卸载,Session的缓存是事务范围的缓存(Session对象的生命周期通常对应一个数据库事务或者一个应用事务)。

一级缓存中,持久化类的每个实例都具有唯一的OID。

依赖于hibernate一级缓存【就是将数据库/硬盘文件中数据,放到缓存中(就是内存中一块空间),当再次使用时,可以直接从内存中获取数据信息】。

4.2.2证明Hibernate一级缓存存在

@Test

/****

* 证明一级缓存的存在

*/

public void demo3() {



// 1通过工具类获取Session

Session session = HibernateUtils.openSession();

// 2开启事务

Transaction tx = session.beginTransaction();

// 3操作



/**

* 分别用两次get执行两次查询id=1的客户,按道理执行两次get应发送两条sql语句,

* 且Customer1与Customer2不是同一个对象,

* 实际上只发送一次,且Customer1与Customer2是同一个对象

* 证明第二次查询使用的是一级缓存中的数据

**/

/** 数据库中第一本书的信息 **/

Customer Customer1 = (Customer) session.get(Customer.class, 1l);

System.out.println(Customer1);

/** 一级缓存中中第一本书的信息 **/

Customer Customer2 = (Customer) session.get(Customer.class, 1l);

System.out.println(Customer2);



System.out.println(Customer1==Customer2);

// 4事务提交

tx.commit();

// 5释放资源

session.close();

}


4.2.3Hibernate一级缓存结构

Hibernate第二天:Hibernate的一级缓存、其他的API_持久化_03



@Test

/****

* 深入了解持久态的对象可以以自动更新数据库

* 基于一级缓存:快照区

*/

public void demo4() {



// 1通过工具类获取Session

Session session = HibernateUtils.openSession();

// 2开启事务

Transaction tx = session.beginTransaction();

// 3操作

Customer Customer = (Customer) session.get(Customer.class, 1l);

/** 将信息存储于快照区 **/

Customer.setCust_name("张三丰");// 先将一级缓存区的【cust_name】修改为【"张三丰"】-----中间会进行一个比对查看是否一致,如果一致不更新(不会执行update语句),如果不一致----再将快照区中的【cust_name】修改为【"张三丰"】(执行update语句)。

// 4事务提交

tx.commit();

// 5释放资源

session.close();

}

5Hibernate的事务管理

5.1什么是事务


事务:指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。

5.2事务的特性

1.原子性

(Atomic)(Atomicity)

事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。

2.一致性

(Consistent)(Consistency)

事务在完成时,必须使所有的数据都保持一致状态。

3.隔离性

(Insulation)(Isolation)

由并发事务所作的修改必须与任何其它并发事务所作的修改隔离。

4.持久性

(Duration)(Durability)

事务完成之后,它对于系统的影响是永久性的。该修改即使出现致命的系统故障也将一直保持。

5.3如果不考虑隔离性,引发安全性问题

读的问题:

脏读:一个事务读到另一个事务未提交的数据。

不可重复读:一个事务读到另一个事务已经提交的update数据,导致在前一个事务多次查询结果不一致。

虚读:一个事务读到另一个事务已经提交的insert数据,导致在前一个事务多次查询结果不一致。


写问题(了解)

     引发丢失更新。

5.3读问题的解决

设置事务的隔离级别

   ① Serializable (串行化):可避免脏读、不可重复读、幻读的发生。

  ② Repeatable read (可重复读):可避免脏读、不可重复读的发生。

  ③ Read committed (读已提交):可避免脏读的发生。

  ④ Read uncommitted (读未提交):最低级别,任何情况都无法保证。

在MySQL数据库中,支持上面四种隔离级别,默认的为Repeatable read (可重复读);而在Oracle数据库中,只支持Serializable (串行化)级别和Read committed (读已提交)这两种级别,其中默认的为Read committed级别。

5.4Hibernate设置事务隔离级别

核心配置文件中加入:

<!--  事务隔离级别

0:TRANSACTION_NONE

1:TRANSACTION_READ_UNCOMMITTED

2:TRANSACTION_READ_COMMITTED

4:TRANSACTION_REPEATABLE_READ

8:TRANSACTION_SERIALIZABLE

-->

<property name="hibernate.connection.isolation">4</property>



5.5Hibernate解决Service的事务管理

Hibernate第二天:Hibernate的一级缓存、其他的API_持久化_04

改写工具类:

package top.yangxianyang.utils;



import org.hibernate.Session;

import org.hibernate.SessionFactory;

import org.hibernate.cfg.Configuration;



/**

* Hibernate的工具类

* @author yxy

*

*/

public class HibernateUtils {



public static final Configuration cfg;

public static final SessionFactory sf;



static{

cfg = new Configuration().configure();

sf = cfg.buildSessionFactory();

}

/*

* 提供获得session的方法

*/

public static Session openSession(){

return sf.openSession();

}



/*

* 提供获得session的方法

*/

public static Session getCurrentSession(){

return sf.getCurrentSession();

}

}

核心文件配置:

<!-- 配置当前线程绑定的Session -->

<property name="hibernate.current_session_context_class">thread</property>


代码:

package top.yangxianyang.demo1;



import org.hibernate.Session;

import org.hibernate.Transaction;

import org.junit.Test;



import top.yangxianyang.utils.HibernateUtils;





/*

* Hibernate线程绑定Session

* @author yxy

*

*/

public class HibernateTest3 {





@Test

public void demo1(){

Session session=HibernateUtils.getCurrentSession();

Transaction tx=session.beginTransaction();



Customer Customer = new Customer();

Customer.setCust_name("涵涵");



session.save(Customer);



tx.commit();



}

}


6Hibernate的其他API

6.1Query

1 使用query对象,不需要写sql语句,但是写hql语句

(1)hql:hibernate query language,hibernate提供查询语言,这个hql语句和普通sql语句很相似

(2)hql和sql语句区别:

- 使用sql操作表和表字段

- 使用hql操作实体类和属性


2 查询所有hql语句:

(1)from 实体类名称


3 Query对象使用

(1)创建Query对象

(2)调用query对象里面的方法得到结果


@Test

//Query

public void demo1(){

Session session=HibernateUtils.getCurrentSession();

Transaction tx=session.beginTransaction();

//通过session获得Query接口

//String hql="from Customer";//简单查询

//条件查询

//String hql="from Customer where cust_name like ?";

//分页查询

String hql="from Customer";



Query query=session.createQuery(hql);

//设置条件

//query.setParameter(0, "张%");

//设置分页

query.setFirstResult(0);

query.setMaxResults(2);

List<Customer> list=query.list();



for (Customer customer : list) {

System.out.println(customer);

}



tx.commit();



}

6.2Criteria

1使用这个对象时候,不需要写语句,直接调用方法实现,更加面向对象。

2 实现过程

(1)创建criteria对象

(2)调用对象里面的方法得到结果 

@Test

//Criteria

public void demo2(){

Session session=HibernateUtils.getCurrentSession();

Transaction tx=session.beginTransaction();

//通过session获得Criteria对象

Criteria ct=session.createCriteria(Customer.class);

//条件查询

ct.add(Restrictions.like("cust_name", "张%"));

List<Customer> list=ct.list();

//分页

ct.setFirstResult(0);

ct.setMaxResults(2);







for (Customer customer : list) {

System.out.println(customer);

}



tx.commit();



}


6.3SQLQuery


1 使用hibernate时候,调用底层sql实现

2 实现过程

(1)创建对象

(2)调用对象的方法得到结果


@Test

// 查询所有

public void demo6(){

Session session = HibernateUtils.openSession();

Transaction tx = session.beginTransaction();



// 接收SQL:

SQLQuery query = session.createSQLQuery("select * from cst_customer");

List<Object[]> list = query.list();

for (Object[] objects : list) {

System.out.println(Arrays.toString(objects));

}

tx.commit();

session.close();

}


今天任务完成。

源码地址:

链接:​​https://pan.baidu.com/s/1rMQ9XBMIeu2O_VbNZBo3MQ​​ 密码:0hgz