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

时间:2022-07-24
本文章向大家介绍Hibernate第二天:Hibernate的一级缓存、其他的API,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

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

1持久化类的编写规则

1.1什么是持久化类

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

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

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

1.2持久化类的编写规则

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

2主键生成策略

2.1主键的分类

2.1.1自然主键

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

2.1.2代理主键

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

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

2.2主键生成策略

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

Increment :hibernate中提供的自动增长机制,适用short,int,long类型党的主键,在单线程中使用。首先发送一条语句,select id from 表,然后让id+1作为下一条记录的主键。

Identity:自动增长,适用short,int,long类型的主键,使用的是数据库底层的自动增长,适用于有自动增长机制的数据库(MySQL,MSSQL),Oracle没有自动增长。

Sequence:自动增长,适用short,int,long类型的主键,采用序列方式(Oracle支持序列)。Mysql不能使用。

UUID:适用于字符串类型,使用Hibernate中的随机方式生成字符串主键。

Native:本地策略,可以在Identity和Sequence之间进行自动切换。

Assigned:hibernate放弃外键管理,需要通过手动编写程序或者自己设置。

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操作
              // 向数据库插入一条记录
              CustomerCustomer = 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持久化类的状态转换(了解)

(1)瞬时态:

获得:由new关键字创建

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

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

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

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

  • 脱管态转换为持久态, 执行Session的update()、 saveOrUpdate()或lock()方法。
  • 脱管态转换为瞬时态,将脱管态对象的持久化标识OID设置为null
  • 持久化类持久态对象自动更新数据库
@Test
       /****
        * 持久太的对象可以以自动更新数据库
        */
       public void demo2() {
              // 1通过工具类获取Session
              Session session= HibernateUtils.openSession();
              // 2开启事务
              Transaction tx= session.beginTransaction();
              // 3操作
              /** 获取一个持久太对象了 **/
              CustomerCustomer = (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缓存

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是同一个对象
               * 证明第二次查询使用的是一级缓存中的数据
               **/
              /** 数据库中第一本书的信息 **/
              CustomerCustomer1 = (Customer) session.get(Customer.class, 1l);
              System.out.println(Customer1);
              /** 一级缓存中中第一本书的信息 **/
              CustomerCustomer2 = (Customer) session.get(Customer.class, 1l);
              System.out.println(Customer2);
              System.out.println(Customer1==Customer2);
              // 4事务提交
              tx.commit();
              // 5释放资源
              session.close();
       }

4.2.3Hibernate一级缓存结构

@Test
       /****
        * 深入了解持久态的对象可以以自动更新数据库
        * 基于一级缓存:快照区
        */
       public void demo4() {
              // 1通过工具类获取Session
              Session session= HibernateUtils.openSession();
              // 2开启事务
              Transaction tx= session.beginTransaction();
              // 3操作
              CustomerCustomer = (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的事务管理

改写工具类:

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 finalConfiguration cfg;
       public static finalSessionFactory sf;
       static{
              cfg = newConfiguration().configure();
              sf = cfg.buildSessionFactory();
       }
       /*
        * 提供获得session的方法
        */
       public static SessionopenSession(){
              return sf.openSession();
       }
       /*
        * 提供获得session的方法
        */
       public static SessiongetCurrentSession(){
              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(){
              Sessionsession=HibernateUtils.getCurrentSession();
              Transactiontx=session.beginTransaction();
              CustomerCustomer = 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(){
              Sessionsession=HibernateUtils.getCurrentSession();
              Transactiontx=session.beginTransaction();
              //通过session获得Query接口
              //String hql="fromCustomer";//简单查询
              //条件查询
              //String hql="fromCustomer where cust_name like ?";
              //分页查询
              String hql="fromCustomer";
              Queryquery=session.createQuery(hql);
              //设置条件
              //query.setParameter(0,"张%");
              //设置分页
              query.setFirstResult(0);
              query.setMaxResults(2);
              List<Customer>list=query.list();
              for (Customercustomer : list) {
                     System.out.println(customer);
              }
              tx.commit();
       }
6.2Criteria
1使用这个对象时候,不需要写语句,直接调用方法实现,更加面向对象。
2 实现过程
(1)创建criteria对象
(2)调用对象里面的方法得到结果
 @Test
       //Criteria
       public void demo2(){
              Sessionsession=HibernateUtils.getCurrentSession();
              Transactiontx=session.beginTransaction();
              //通过session获得Criteria对象
              Criteriact=session.createCriteria(Customer.class);
              //条件查询
              ct.add(Restrictions.like("cust_name","张%"));
              List<Customer>list=ct.list();
              //分页
              ct.setFirstResult(0);
              ct.setMaxResults(2);
              for (Customercustomer : 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