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

相关文章

从入门到精通MySQL联合查询

《从入门到精通MySQL联合查询》:本文主要介绍从入门到精通MySQL联合查询,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下... 目录摘要1. 多表联合查询时mysql内部原理2. 内连接3. 外连接4. 自连接5. 子查询6. 合并查询7. 插入查询结果摘要前面我们学习了数据库设计时要满

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决

SpringBoot中4种数据水平分片策略

《SpringBoot中4种数据水平分片策略》数据水平分片作为一种水平扩展策略,通过将数据分散到多个物理节点上,有效解决了存储容量和性能瓶颈问题,下面小编就来和大家分享4种数据分片策略吧... 目录一、前言二、哈希分片2.1 原理2.2 SpringBoot实现2.3 优缺点分析2.4 适用场景三、范围分片

从入门到精通MySQL 数据库索引(实战案例)

《从入门到精通MySQL数据库索引(实战案例)》索引是数据库的目录,提升查询速度,主要类型包括BTree、Hash、全文、空间索引,需根据场景选择,建议用于高频查询、关联字段、排序等,避免重复率高或... 目录一、索引是什么?能干嘛?核心作用:二、索引的 4 种主要类型(附通俗例子)1. BTree 索引(

Redis 配置文件使用建议redis.conf 从入门到实战

《Redis配置文件使用建议redis.conf从入门到实战》Redis配置方式包括配置文件、命令行参数、运行时CONFIG命令,支持动态修改参数及持久化,常用项涉及端口、绑定、内存策略等,版本8... 目录一、Redis.conf 是什么?二、命令行方式传参(适用于测试)三、运行时动态修改配置(不重启服务

MySQL DQL从入门到精通

《MySQLDQL从入门到精通》通过DQL,我们可以从数据库中检索出所需的数据,进行各种复杂的数据分析和处理,本文将深入探讨MySQLDQL的各个方面,帮助你全面掌握这一重要技能,感兴趣的朋友跟随小... 目录一、DQL 基础:SELECT 语句入门二、数据过滤:WHERE 子句的使用三、结果排序:ORDE

Redis过期删除机制与内存淘汰策略的解析指南

《Redis过期删除机制与内存淘汰策略的解析指南》在使用Redis构建缓存系统时,很多开发者只设置了EXPIRE但却忽略了背后Redis的过期删除机制与内存淘汰策略,下面小编就来和大家详细介绍一下... 目录1、简述2、Redis http://www.chinasem.cn的过期删除策略(Key Expir

Python中OpenCV与Matplotlib的图像操作入门指南

《Python中OpenCV与Matplotlib的图像操作入门指南》:本文主要介绍Python中OpenCV与Matplotlib的图像操作指南,本文通过实例代码给大家介绍的非常详细,对大家的学... 目录一、环境准备二、图像的基本操作1. 图像读取、显示与保存 使用OpenCV操作2. 像素级操作3.

利用Python实现时间序列动量策略

《利用Python实现时间序列动量策略》时间序列动量策略作为量化交易领域中最为持久且被深入研究的策略类型之一,其核心理念相对简明:对于显示上升趋势的资产建立多头头寸,对于呈现下降趋势的资产建立空头头寸... 目录引言传统策略面临的风险管理挑战波动率调整机制:实现风险标准化策略实施的技术细节波动率调整的战略价