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

相关文章

从入门到精通详解Python虚拟环境完全指南

《从入门到精通详解Python虚拟环境完全指南》Python虚拟环境是一个独立的Python运行环境,它允许你为不同的项目创建隔离的Python环境,下面小编就来和大家详细介绍一下吧... 目录什么是python虚拟环境一、使用venv创建和管理虚拟环境1.1 创建虚拟环境1.2 激活虚拟环境1.3 验证虚

MySQL设置密码复杂度策略的完整步骤(附代码示例)

《MySQL设置密码复杂度策略的完整步骤(附代码示例)》MySQL密码策略还可能包括密码复杂度的检查,如是否要求密码包含大写字母、小写字母、数字和特殊字符等,:本文主要介绍MySQL设置密码复杂度... 目录前言1. 使用 validate_password 插件1.1 启用 validate_passwo

Java List 使用举例(从入门到精通)

《JavaList使用举例(从入门到精通)》本文系统讲解JavaList,涵盖基础概念、核心特性、常用实现(如ArrayList、LinkedList)及性能对比,介绍创建、操作、遍历方法,结合实... 目录一、List 基础概念1.1 什么是 List?1.2 List 的核心特性1.3 List 家族成

c++日志库log4cplus快速入门小结

《c++日志库log4cplus快速入门小结》文章浏览阅读1.1w次,点赞9次,收藏44次。本文介绍Log4cplus,一种适用于C++的线程安全日志记录API,提供灵活的日志管理和配置控制。文章涵盖... 目录简介日志等级配置文件使用关于初始化使用示例总结参考资料简介log4j 用于Java,log4c

史上最全MybatisPlus从入门到精通

《史上最全MybatisPlus从入门到精通》MyBatis-Plus是MyBatis增强工具,简化开发并提升效率,支持自动映射表名/字段与实体类,提供条件构造器、多种查询方式(等值/范围/模糊/分页... 目录1.简介2.基础篇2.1.通用mapper接口操作2.2.通用service接口操作3.进阶篇3

Python自定义异常的全面指南(入门到实践)

《Python自定义异常的全面指南(入门到实践)》想象你正在开发一个银行系统,用户转账时余额不足,如果直接抛出ValueError,调用方很难区分是金额格式错误还是余额不足,这正是Python自定义异... 目录引言:为什么需要自定义异常一、异常基础:先搞懂python的异常体系1.1 异常是什么?1.2

Python实现Word转PDF全攻略(从入门到实战)

《Python实现Word转PDF全攻略(从入门到实战)》在数字化办公场景中,Word文档的跨平台兼容性始终是个难题,而PDF格式凭借所见即所得的特性,已成为文档分发和归档的标准格式,下面小编就来和大... 目录一、为什么需要python处理Word转PDF?二、主流转换方案对比三、五套实战方案详解方案1:

Python实现网格交易策略的过程

《Python实现网格交易策略的过程》本文讲解Python网格交易策略,利用ccxt获取加密货币数据及backtrader回测,通过设定网格节点,低买高卖获利,适合震荡行情,下面跟我一起看看我们的第一... 网格交易是一种经典的量化交易策略,其核心思想是在价格上下预设多个“网格”,当价格触发特定网格时执行买

Spring WebClient从入门到精通

《SpringWebClient从入门到精通》本文详解SpringWebClient非阻塞响应式特性及优势,涵盖核心API、实战应用与性能优化,对比RestTemplate,为微服务通信提供高效解决... 目录一、WebClient 概述1.1 为什么选择 WebClient?1.2 WebClient 与

Spring Boot 与微服务入门实战详细总结

《SpringBoot与微服务入门实战详细总结》本文讲解SpringBoot框架的核心特性如快速构建、自动配置、零XML与微服务架构的定义、演进及优缺点,涵盖开发环境准备和HelloWorld实战... 目录一、Spring Boot 核心概述二、微服务架构详解1. 微服务的定义与演进2. 微服务的优缺点三