本文主要是介绍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()
-
类级别检索和关联级别检索:
-
类级别的检索:
<class>标签上配置lazy
-
关联级别的检索:
<set>/<many-to-one>上面的lazy
-
问题思考:
查询某个对象的时候,是否需要查询关联对象?
查询关联对象的时候是否采用延迟检索?
-
关联关系表
一个客户(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属性将会忽略
- <set>没有配置fetch 和 lazy情况
默认情况下fetch =“select”,lazy=“true”.
// 首先发送查询客户的SQL. Customer customer = (Customer) session.get(Customer.class, 1); // 然后又发送一条SQL 去查询客户的关联的订单 System.out.println(customer.getOrders().size());
-
<set>配置fetch=“join” lazy就会被忽略
发送迫切左外连接查询两个表(将查询结果封装到对象中)只发送一条sql语句
//查询Custome的同时一并将订单也查询出,并计算大小 Customer customer = (Customer) session.get(Customer.class, 1); System.out.println(customer.getOrders().size());
-
<set>配置fetch=“select” lazy="true"
fetch取select无论lazy取什么值都会发送多条语句
默认取值
// 发送一条只查询客户的SQL Customer customer = (Customer) session.get(Customer.class, 1); // 使用订单的时候又发送一条查询这个客户的订单的SQL System.out.println(customer.getOrders().size());
-
<set>配置fetch=“select” lazy="false"
关联对象的检索不使用延迟,一次发送多条sql语句
//发送多条SQL,查询关联对象. Customer customer = (Customer) session.get(Customer.class, 1);//运行到这里一次发送全部sql语句 System.out.println(customer.getOrders().size());
-
<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 =?
-
在<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属性将会忽略
-
在<many-to-one>标签上什么也不进行配置
发送两条sql语句
// 获取1号订单,发送一条sql语句(用到的时候才进行sql查询) Order order = (Order) session.get(Order.class, 1);// 使用订单的客户对象的时候,又发送一条SQL查询订单关联的客户 System.out.println(order.getCustomer().getCname());
-
在<many-to-one>标签上配置fetch=“join” lazy=" ",lazy失效
只发送一条sql语句
// 发送一条迫切左外连接.查询关联对象. Order order = (Order) session.get(Order.class, 1); // 不再进行发送sql语句 System.out.println(order.getCustomer().getCname());
-
在<many-to-one>标签上配置fetch=“select” lazy="false"
发送多条SQL(一次性发送多条)
Order order = (Order) session.get(Order.class, 1);// 在这行发送多条SQL 查询关联对象. System.out.println(order.getCustomer().getCname());
-
对<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());
-
-
批量抓取
-
未使用批量抓取的情况
有几个订单将会查询几次,与数据库交互频繁
List<Customer> list = session.createQuery("from Customer").list();for (Customer customer : list) {for (Order order : customer.getOrders()) {System.out.println(order);}}
-
客户查订单,在客户一端配置批量抓取,<set>集合上配置batch-size="3"
查询客户并得到其所有的订单
查询的方式:根据每次用户的id进行逐一查询(效率低下)
在一的一方的set集合上配置batch-size=“3”(一次抓取3个Customer客户信息进行查询)
Customer客户batch-size的值大于Customser直接一次查询完,不足取整加1List<Customer> list = session.createQuery("from Customer").list();for (Customer customer : list) {for (Order order : customer.getOrders()) {System.out.println(order);}}
-
订单批量抓取客户:需要在客户一端<class>标签上配置batch-size
都是在一的一方进行配置
// 查询订单,找出所属的客户List<Order> list = session.createQuery("from Order").list();for (Order order : list) {System.out.println(order.getCustomer().getCname());}
-
事务处理
事务:
事务就是逻辑上的一组操作,要么全都成功,要么全都失败!!!
事务特性
- 原子性:事务一组操作不可分割.
- 一致性:事务的执行前后,数据完整性要保持一致.
- 隔离性:一个事务在执行的过程中不应该受到其他事务的干扰.
- 持久性:一旦事务结束,数据就永久保存数据库.
5大类问题:3类读问题 2类写问题.
-
读问题:
- 脏读 :一个事务读到另一个事务未提交数据.
- 不可重复读 :一个事务读到另一个事务已经提交数据(update),导致查询结果不一致.
- 虚读 :一个事务读到另一个事务已经提交的数据(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的抓取策略和事务处理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!