Hibernate3入门之第五章Hibernate的抓取策略和事务处理

本文主要是介绍Hibernate3入门之第五章Hibernate的抓取策略和事务处理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Hibernate3入门之第五章Hibernate的抓取策略和事务处理

Hibernate的抓取策略

hibernate抓取策略概述

​ Hibernate抓取策略(fetching strategy)是指:当应用程序需要在(Hibernate实体对象图的)关联关系间进行导航的时候, Hibernate如何获取关联对象的策略。抓取策略可以在O/R映射的元数据中声明,也可以在特定的HQL 或条件查询(Criteria Query)中重载声明。

hibernate抓取策略分类

hibernate有如下四种原生态的Hibernate抓取策略,分别是:

  • select fetching
  • join fetching
  • subselect fetching
  • Batch fetching。

hibernate抓取策略详细介绍

主要针对一对多的情况进行阐述

  • 区分延迟和立即检索

    立即检索:

    ​ 当执行某行代码的时候,马上发出SQL语句进行查询.

    ​ 典型:get()

    延迟检索:

    ​ 当执行某行代码的时候不会马上发出SQL语句进行查询.当真正使用这个对象的时候才会发送SQL语句

    ​ 典型:load()

  • 类级别检索和关联级别检索:

    1. 类级别的检索:

      <class>标签上配置lazy

    2. 关联级别的检索:

      <set>/<many-to-one>上面的lazy

    3. 问题思考:

      查询某个对象的时候,是否需要查询关联对象?

      查询关联对象的时候是否采用延迟检索?

    4. 关联关系表

      一个客户(Customer)有多个订单(Order)

      Customer

      	private Integer cid;private String cname;private Set<Order> orders = new HashSet<>();
      

      Order

      	private Integer oid;private String addr;private Customer customer;
      
  • 从一的一方关联多的一方

    首先介绍其属性和可以的取的值

    fetch

    描述
    join发送迫切左外连接的SQL查询关联对象.fetch=”join”那么lazy被忽略了
    select默认值,发送多条SQL查询关联对象
    subselect发送子查询查询关联对象.(需要使用Query接口测试)

    lazy

    描述
    true默认值, 查询关联对象的时候使用延迟检索
    false查询关联对象的时候不使用延迟检索.
    extra极其懒惰

    如果fetch是join的情况,lazy属性将会忽略

    1. <set>没有配置fetch 和 lazy情况

    默认情况下fetch =“select”,lazy=“true”.

    // 首先发送查询客户的SQL.
    Customer customer = (Customer) session.get(Customer.class, 1);
    // 然后又发送一条SQL 去查询客户的关联的订单
    System.out.println(customer.getOrders().size());
    
    1. <set>配置fetch=“join” lazy就会被忽略

      发送迫切左外连接查询两个表(将查询结果封装到对象中)只发送一条sql语句

      //查询Custome的同时一并将订单也查询出,并计算大小
      Customer customer = (Customer) session.get(Customer.class, 1);
      System.out.println(customer.getOrders().size());
      
    2. <set>配置fetch=“select” lazy="true"

      fetch取select无论lazy取什么值都会发送多条语句

      默认取值

      // 发送一条只查询客户的SQL
      Customer customer = (Customer) session.get(Customer.class, 1);
      // 使用订单的时候又发送一条查询这个客户的订单的SQL
      System.out.println(customer.getOrders().size());
      
    3. <set>配置fetch=“select” lazy="false"

      关联对象的检索不使用延迟,一次发送多条sql语句

      //发送多条SQL,查询关联对象.
      Customer customer = (Customer) session.get(Customer.class, 1);//运行到这里一次发送全部sql语句
      System.out.println(customer.getOrders().size());
      
    4. <set>配置fetch=“select” lazy=“extra”(极其懒惰的)

      要订单的数量(只发送count对订单的数量进行查询)

      // 发送一条sql语句对Customer进行查询
      Customer customer = (Customer) session.get(Customer.class, 1);
      // 发送一条sql语句对Order数量进行查询
      System.out.println(customer.getOrders().size());
      

      第二条sql语句:

      	Hibernate: selectcount(oid) fromorders wherecno =?
      
    5. 在<set>集合上配置fetch=“subselect” lazy=" "

      使用subselect的时候 需要使用 query接口进行测试.
      查询一个客户 查询多个订单(=的效率要高于in)
      如果有多个客户:
      select * from orders where cno in (1,2,3);
      如果只有一个客户:
      select * from orders where cno = 1;

      //	fetch="subselect"  lazy="extra"用一次发一次,不做任何多余的事(循环加1次)
      //	fetch="subselect"  lazy="true" 初始化给该类时一次打印订单发送两次
      //  fetch="subselect"  lazy="false"只要一使用该类,连着关联类的sql语句一起输出,发送一次
      // 查询每个客户的订单数量
      List<Customer> list = session.createQuery("from Customer").list();for (Customer customer : list) {System.out.println(customer.getOrders().size());}
      
  • 在多的一方关联一的一方

    首先介绍其属性和可以的取的值

    fetch

    描述
    join发送一个迫切左外连接查询关联对象.fetch=”join”,lay属性会被忽略.
    select发送多条SQL检索关联对象.

    lazy

    描述
    false不延迟
    proxy使用代理.检索订单额时候,是否马上检索客户 由Customer对象的映射文件中<class>上lazy属性来决定.
    no-proxy不使用代理

    如果fetch是join的情况,lazy属性将会忽略

    1. 在<many-to-one>标签上什么也不进行配置

      发送两条sql语句

      // 获取1号订单,发送一条sql语句(用到的时候才进行sql查询)
      Order order = (Order) session.get(Order.class, 1);// 使用订单的客户对象的时候,又发送一条SQL查询订单关联的客户
      System.out.println(order.getCustomer().getCname());
      
    2. 在<many-to-one>标签上配置fetch=“join” lazy=" ",lazy失效

      只发送一条sql语句

      // 发送一条迫切左外连接.查询关联对象.
      Order order = (Order) session.get(Order.class, 1);
      // 不再进行发送sql语句
      System.out.println(order.getCustomer().getCname());
      
    3. 在<many-to-one>标签上配置fetch=“select” lazy="false"

      发送多条SQL(一次性发送多条)

      Order order = (Order) session.get(Order.class, 1);// 在这行发送多条SQL 查询关联对象.
      System.out.println(order.getCustomer().getCname());
      
    4. 对<many-to-one>标签上配置fetch=“select” lazy=“proxy” Customer类lazy="true"

      发送多条SQL==>proxy是否马上检索客户,由一的一方(Customer)对象的映射文件中<class>上lazy属性来决定.

      // 延迟加载发送多条sql
      Order order = (Order) session.get(Order.class, 1);
      System.out.println(order.getCustomer().getCname());
      
  • 批量抓取

    1. 未使用批量抓取的情况

      有几个订单将会查询几次,与数据库交互频繁

      List<Customer> list = session.createQuery("from Customer").list();for (Customer customer : list) {for (Order order : customer.getOrders()) {System.out.println(order);}}
      
    2. 客户查订单,在客户一端配置批量抓取,<set>集合上配置batch-size="3"

      ​ 查询客户并得到其所有的订单
      ​ 查询的方式:根据每次用户的id进行逐一查询(效率低下)
      ​ 在一的一方的set集合上配置batch-size=“3”(一次抓取3个Customer客户信息进行查询)
      ​ Customer客户batch-size的值大于Customser直接一次查询完,不足取整加1

      List<Customer> list = session.createQuery("from Customer").list();for (Customer customer : list) {for (Order order : customer.getOrders()) {System.out.println(order);}}
      
    3. 订单批量抓取客户:需要在客户一端<class>标签上配置batch-size

      都是在一的一方进行配置

      	// 查询订单,找出所属的客户List<Order> list = session.createQuery("from Order").list();for (Order order : list) {System.out.println(order.getCustomer().getCname());}
      

事务处理

事务:

​ 事务就是逻辑上的一组操作,要么全都成功,要么全都失败!!!

事务特性

  • 原子性:事务一组操作不可分割.
  • 一致性:事务的执行前后,数据完整性要保持一致.
  • 隔离性:一个事务在执行的过程中不应该受到其他事务的干扰.
  • 持久性:一旦事务结束,数据就永久保存数据库.

5大类问题:3类读问题 2类写问题.

  • 读问题:

    1. 脏读 :一个事务读到另一个事务未提交数据.
    2. 不可重复读 :一个事务读到另一个事务已经提交数据(update),导致查询结果不一致.
    3. 虚读 :一个事务读到另一个事务已经提交的数据(insert),导致查询结果不一致

    避免三种读的问题

    ​ 设置事务的隔离级别:

    ​ 未提交读:以上三种读问题 都有可能发生.

      已提交读:避免脏读,但是不可重复读和虚读有可能发生.
    

    ​ 重复读:避免脏读和不可重复读,但是虚读是有可能发生.

    ​ 串行的:可以避免以上三种读问题.、

    ​ 在Hibernate中设置事务的隔离级别:

    ​ 在核心配置文件中:

    ​ 1—Read uncommitted isolation

    ​ 2—Read committed isolation

    ​ 4—Repeatable read isolation

    ​ 8—Serializable isolation

    <property name="hibernate.connection.isolation">4</property>
    
  • 写问题:丢失更新

    • 使用悲观锁解决丢失更新(基于for update)

      public Object get(Class clazz, Serializable id, LockMode lockMode)(已经过时但是能用)

      修改名字

      // 使用悲观锁(排他锁)
      Customer customer = (Customer) session.get(Customer.class, 3, LockMode.UPGRADE);
      customer.setCname("小强");
      

      修改年龄

      // 使用悲观锁(排他锁)
      Customer customer = (Customer) session.get(Customer.class, 3, LockMode.UPGRADE);
      customer.setAge(32);
      
    • 使用乐观锁解决丢失更新(基于vesrion)

      在Customer添加属性用于版本比对

      同时Customer.hbm.xml添加

      <version name="version"/><!--name就是属性名-->
      

      修改名字:

      Customer customer = (Customer) session.get(Customer.class, 3);
      customer.setCname("小强");
      

      修改年龄:

      Customer customer = (Customer) session.get(Customer.class, 3);
      customer.setAge(26);
      

管理session

事务通常在service层开启.session在DAO层.

事务开启由session开启.

如何保证在DAO获取到的session是同一个对象

线程绑定

Hibernate为我们提供了线程绑定的方法

在我们Hibernate的工具类中通过

//sessionFactory是SessionFactory的实例化对象
sessionFactory.getCurrentSession();
//底层就是ThreadLocal.

同时在我们的配置文件

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

当前线程中的session不需要进行关闭,线程结束后自动关闭!!!

Hibernate3Utils.java工具类:

public class Hibernate3Utils {private static Configuration configuration;private static SessionFactory sessionFactory;static {configuration = new Configuration().configure();sessionFactory = configuration.buildSessionFactory();}public static Session getSession() {return sessionFactory.openSession();}public static Session openSession() {return sessionFactory.getCurrentSession();}public static void main(String[] args) {openSession();}
}

这篇关于Hibernate3入门之第五章Hibernate的抓取策略和事务处理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/775958

相关文章

Spring Boot + MyBatis Plus 高效开发实战从入门到进阶优化(推荐)

《SpringBoot+MyBatisPlus高效开发实战从入门到进阶优化(推荐)》本文将详细介绍SpringBoot+MyBatisPlus的完整开发流程,并深入剖析分页查询、批量操作、动... 目录Spring Boot + MyBATis Plus 高效开发实战:从入门到进阶优化1. MyBatis

SpringBoot如何通过Map实现策略模式

《SpringBoot如何通过Map实现策略模式》策略模式是一种行为设计模式,它允许在运行时选择算法的行为,在Spring框架中,我们可以利用@Resource注解和Map集合来优雅地实现策略模式,这... 目录前言底层机制解析Spring的集合类型自动装配@Resource注解的行为实现原理使用直接使用M

Python FastAPI入门安装使用

《PythonFastAPI入门安装使用》FastAPI是一个现代、快速的PythonWeb框架,用于构建API,它基于Python3.6+的类型提示特性,使得代码更加简洁且易于绶护,这篇文章主要介... 目录第一节:FastAPI入门一、FastAPI框架介绍什么是ASGI服务(WSGI)二、FastAP

Redis 内存淘汰策略深度解析(最新推荐)

《Redis内存淘汰策略深度解析(最新推荐)》本文详细探讨了Redis的内存淘汰策略、实现原理、适用场景及最佳实践,介绍了八种内存淘汰策略,包括noeviction、LRU、LFU、TTL、Rand... 目录一、 内存淘汰策略概述二、内存淘汰策略详解2.1 ​noeviction(不淘汰)​2.2 ​LR

Deepseek使用指南与提问优化策略方式

《Deepseek使用指南与提问优化策略方式》本文介绍了DeepSeek语义搜索引擎的核心功能、集成方法及优化提问策略,通过自然语言处理和机器学习提供精准搜索结果,适用于智能客服、知识库检索等领域... 目录序言1. DeepSeek 概述2. DeepSeek 的集成与使用2.1 DeepSeek API

Redis的数据过期策略和数据淘汰策略

《Redis的数据过期策略和数据淘汰策略》本文主要介绍了Redis的数据过期策略和数据淘汰策略,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录一、数据过期策略1、惰性删除2、定期删除二、数据淘汰策略1、数据淘汰策略概念2、8种数据淘汰策略

SpringBoot中的404错误:原因、影响及解决策略

《SpringBoot中的404错误:原因、影响及解决策略》本文详细介绍了SpringBoot中404错误的出现原因、影响以及处理策略,404错误常见于URL路径错误、控制器配置问题、静态资源配置错误... 目录Spring Boot中的404错误:原因、影响及处理策略404错误的出现原因1. URL路径错

Redis多种内存淘汰策略及配置技巧分享

《Redis多种内存淘汰策略及配置技巧分享》本文介绍了Redis内存满时的淘汰机制,包括内存淘汰机制的概念,Redis提供的8种淘汰策略(如noeviction、volatile-lru等)及其适用场... 目录前言一、什么是 Redis 的内存淘汰机制?二、Redis 内存淘汰策略1. pythonnoe

Python 中 requests 与 aiohttp 在实际项目中的选择策略详解

《Python中requests与aiohttp在实际项目中的选择策略详解》本文主要介绍了Python爬虫开发中常用的两个库requests和aiohttp的使用方法及其区别,通过实际项目案... 目录一、requests 库二、aiohttp 库三、requests 和 aiohttp 的比较四、requ

Redis过期键删除策略解读

《Redis过期键删除策略解读》Redis通过惰性删除策略和定期删除策略来管理过期键,惰性删除策略在键被访问时检查是否过期并删除,节省CPU开销但可能导致过期键滞留,定期删除策略定期扫描并删除过期键,... 目录1.Redis使用两种不同的策略来删除过期键,分别是惰性删除策略和定期删除策略1.1惰性删除策略