`
bencode
  • 浏览: 109255 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Hibernate学习笔记1–Session与对象

    博客分类:
  • Java
阅读更多
1. 不同的对象状态

在Hibernate中,对象有四种状态(Transient, Persistent, Detached, Removed)
对象通过与Session交互,在这四种状态间进行迁移。

	public void test1() {
		Item item = new Item(); // transient
		
		Session session = HibernateUtil.openSession();
		Transaction tx = session.beginTransaction();
		
		session.save(item); // persistent
		//session.saveOrUpdate(item);  // persistent

		tx.commit();
		session.close();
		
		// item is detached
	}


	public void test2() {
		Session session = HibernateUtil.openSession();
		Transaction tx = session.beginTransaction();
		
		Item item = (Item) session.get(Item.class, 1);
		
		session.delete(item);
		// item's state is removed
		
		tx.commit();
		session.close();
		
		// item's state is transient
	}


2. 在persistent状态下,hibernate会自动检测到对象的修改,并延迟更新到数据库中(会尽可能晚地执行SQL语句)。

	public void test3() {
		Session session = HibernateUtil.openSession();
		Transaction tx = session.beginTransaction();
		
		Item item = (Item) session.get(Item.class, 1);
		
		item.setName("Another Name");  // 将会自动更新到数据库中, 你不需要调用session.update
		
		tx.commit();
		session.close();
	}



默认情况下,hibernate将会对表格中的所有字段进行更新,差不多会产生这样的sql语句:

update items set name=?, price=? where id=?


如果你的字段非常多,或者有些字段非常大,你可以在hbm.xml中设置dynamic-update(dynamic-insert)属性,让其只更新必要的字段:

<class name="Item" table="items" dynamic-update="true">


现在,产生的SQL语句就像这样了:
update items set name=? where id=?


需要注意的是,dynamic-update需要在运行时产生SQL语句, 而原来的update语句是在一开始就产生好的。

什么是尽可能地晚? 默认的时候,大约会在以下三种情况下进行
1. transaction commit
2. 在一个query执行前
3. 当然也可以主动调用session.flush


3. object identity & 一级缓存
	public void test4() {
		Session session = HibernateUtil.openSession();
		Transaction tx = session.beginTransaction();
		
		Item item1 = (Item) session.get(Item.class, 1);
		assertNotNull(item1);
		
		Item item2 = (Item) session.createQuery("from Item item where item.name = :name")
				.setString("name", "item1").uniqueResult();
		assertNotNull(item2);
		assertEquals(1, item2.getId()); 
		
		assertTrue(item1 == item2);  // 它们是同一样对象, 虽然通过不同的途经取得
		
		tx.commit();
		session.close();
	}

上面这个例子执行了两个SQL语句:
session.get(... ---->  select ... from items item0_ where item0_.id=?
session.createQuery(... ----> select ... from items item0_ where item0_.name=?

在同一个Session中,相同id的对象是同一个对象(上面代码中使用引用比较)。这在面向对象语义上是必要的,因为在数据库中,它们对应于同一条记录。
这也隐含了session中的对象(即persistent状态下的对象)将以id进行缓存, 这样才能在将来取得其他对象时,与已有的对象进行比较,以达到上面这个要求

	public void test5() {
		Session session = HibernateUtil.openSession();
		Transaction tx = session.beginTransaction();
		
		Item item1 = (Item) session.get(Item.class, 1);
		Item item2 = (Item) session.get(Item.class, 1); // 不需要执行SQL语句,缓存中已有
		assertTrue(item1 == item2); // 它们是同一个对象
		tx.commit();
		session.close();
	}

上面例子只需要进行一条SQL语句的查询

	public void test6() {
		Session session1 = HibernateUtil.openSession();
		Transaction tx1 = session1.beginTransaction();
		
		Item item1 = (Item) session1.get(Item.class, 1); // 从第一个session取得
		
		tx1.commit();
		session1.close();
		
		
		Session session2 = HibernateUtil.openSession();
		Transaction tx2= session2.beginTransaction();
		
		Item item2 = (Item) session2.get(Item.class, 1); // 从第二个session取得
		
		tx2.commit();
		session2.close();
		
		assertTrue(item1.getId() == item2.getId());  // id 相等
		assertFalse(item1 == item2);  // 却不是同一个对象
	}


由于session的缓存, 所以当在一个unit work中操作很多对象的时候,就会有问题啦
public class Item {

	private int id;
	private String code;
	private String name;
	private double price;
	
	private byte[] cache = new byte[10 * 1024 * 1024]; // 添加了这行,内存大户
	...

	public void test10() {
		Session session = HibernateUtil.openSession();
		Transaction tx = session.beginTransaction();

		for (int i = 0; i < 100; i++) {
			Item item = new Item();
			session.save(item);
		}
		
		tx.commit();
		session.close();
	}


你会看到OutOfMemoryError

你需要这样:

	public void test10() {
		Session session = HibernateUtil.openSession();
		Transaction tx = session.beginTransaction();
		
		//session.setCacheMode(CacheMode.IGNORE); // 如果有二级缓存的话,也需要禁止二级缓存
		for (int i = 0; i < 100; i++) {
			Item item = new Item();
			session.save(item);
			if (i % 3 == 0) {
				session.flush();
				session.clear();
			}
		}
		
		tx.commit();
		session.close();
	}


4. equals & hashCode

上述例子中
item1 != item2, 因为在不同的session中
item1.getId() == item2.getId(), 因为它们本来就对应数据库中的同一条记录, 属于同一个对象

于是我们期望: item1.equals(item2),  // 我们很多时候都需要这样的东西,contains, hashtable 等等
可是怎么样实现呢, 最直接的想到是用 id, 但是id在transient 往往不存在,而在hibernate save 之后才取得。 这会是一个problem。

所以我们最好是使用 business key(像身份证号, 用户名等,在业务层面确定一个实体) 实现equals。
还要记得,重写equals,一定要重写 hashCode,因为 equals 的两个对象, hashCode 需要相同

像这样:
	@Override
	public boolean equals(Object other) {
		if (this == other) {
			return true;
		}
		if (other instanceof Item) {
			Item item = (Item) other;
			return this.getCode() == item.getCode(); // code 是item的编号...
		}
		return false;
	}
	
	@Override
	public int hashCode() {
		return this.getCode().hashCode();
	}




5. session.get & session.load

session.get 会返回实际的对象,而session.load可能会返回一个代理

	public void test7() {
		Session session = HibernateUtil.openSession();
		Transaction tx = session.beginTransaction();
		
		Item item1 = (Item) session.get(Item.class, 1);
		Item item1_ = (Item) session.load(Item.class, 1);  // 会在缓存中找到
		Item item2 = (Item) session.load(Item.class, 2);  // 仅返回一个proxy
		
		assertTrue(item1 == item1_);  // 它们是同一个对象
		assertTrue(item1.getClass()== Item.class);
		assertTrue(item1_.getClass()== Item.class);
		
		assertFalse(item2.getClass() == Item.class);  // item2 是一个proxy
		
		println(item2.getId());  // 此时不需要查询数据库
		println(item2.getClass());  
		println(item2.getName()); // 此时再骈查询数据库
		
		tx.commit();
		session.close();
	}


在控制台,可以看到类似这样的输出:
Hibernate: select ...
class bencode.in.hibernate.model.Item_$$_javassist_0
Hibernate: select ...
item2

可以看到,在println(item2.getName()) 的时候,才会去查询数据库。

另外, 当记录不存在时, session.get 会返回null, session.load 会返回一个proxy, 在访问该proxy时,会throw ObjectNotFoundException

	public void test8() {
		Session session = HibernateUtil.openSession();
		Transaction tx = session.beginTransaction();
		
		Item item1 = (Item) session.get(Item.class, 1000);
		Item item2 = (Item) session.load(Item.class, 2000);
		
		assertNull(item1);  // item1 == null
		assertNotNull(item2);  // item2 is a proxy
		
		try {
			item2.getName();  // 出异常
			fail();
		} catch (Exception ex) {
			assertTrue(ex.getClass() == ObjectNotFoundException.class);
		}
		
		tx.commit();
		session.close();
	}


这有啥用呢? 有时候我们仅仅需要一个对象引用。

假设Item 有一个 many_to_one 的 Part
<many-to-one name="part" column="part_id"/>


	public void test11() {
		Session session = HibernateUtil.openSession();
		Transaction tx = session.beginTransaction();
		
		Item item = (Item) session.load(Item.class, 1);
		Part part = (Part) session.load(Part.class, 1);
		
		item.setPart(part);
		
		tx.commit();
		session.close();
	}


上面的part就不需要载入了, 可能看到,只有两条sql语句:
select item...
update items...
分享到:
评论

相关推荐

    Hibernate学习笔记整理

    Hibernate学习笔记整理 以下是 Hibernate 框架的详细知识点: Hibernate 介绍 Hibernate 是一个 ORM(Object-Relational Mapping)框架,用于将 Java 对象映射到数据库表中。它提供了一个简洁的方式来访问和操作...

    Hibernate学习笔记特别详细

    《Hibernate学习笔记特别详细》 Hibernate,作为一款开源的Object-Relational Mapping(ORM)框架,为Java开发者提供了强大的数据库操作支持。它简化了数据库访问的复杂性,使得开发人员可以像操作对象一样操作...

    hibernate学习笔记

    在本篇《Hibernate学习笔记》中,我们将深入探讨Hibernate这一流行的Java对象关系映射(ORM)框架。Hibernate允许开发者以面向对象的方式处理数据库操作,极大地简化了数据存取的复杂性。以下是一些关键知识点: 1....

    Hibernate学习笔记与总结

    **Hibernate学习笔记与总结** Hibernate 是一款开源的对象关系映射(ORM)框架,它为Java开发者提供了一种在关系数据库上操作对象数据的便捷方式。本文将深入探讨Hibernate的核心概念、配置、实体类、映射文件、...

    hibernate学习笔记1

    【hibernate学习笔记1】 一、理解Hibernate Hibernate是一个流行的Java对象关系映射(ORM)框架,它的主要目的是简化数据库操作,通过将Java对象与数据库表进行映射,使得开发者能够以面向对象的方式处理数据,而...

    Java相关课程系列笔记之十四Hibernate学习笔记

    【Java相关课程系列笔记之十四Hibernate学习笔记】 Hibernate是一个开源的对象关系映射(ORM)框架,它极大地简化了Java应用程序对数据库的操作。本笔记将详细阐述Hibernate的核心概念、使用方法和特性。 一、...

    hibernate 学习笔记1

    ### 对象持久化与Hibernate学习笔记 #### 一、对象持久化的概念与重要性 - **定义**: 对象持久化是指将程序中的对象状态存储到持久化存储设备上的过程,以便在程序结束运行后仍然可以保留这些数据。 - **必要性**:...

    hibernate学习笔记mashibing

    《Hibernate学习笔记——马士兵教程解析》 在Java开发领域,ORM(Object-Relational Mapping)框架的使用已经非常普遍,其中Hibernate作为一款优秀的ORM框架,因其强大的功能和易用性深受开发者喜爱。本文将根据马...

    Hibernate学习笔记!

    **Hibernate学习笔记** Hibernate是一个强大的Java对象关系映射(ORM)框架,它为开发者提供了在Java应用程序中操作数据库的强大工具。本笔记将深入探讨Hibernate的核心概念、配置、实体管理、查询语言以及最佳实践...

    hibernate API帮助文档 及hibernate学习笔记

    Hibernate是一款强大的Java持久...通过阅读这份“Hibernate API帮助文档”和“Hibernate学习笔记”,你将能够深入理解Hibernate的工作原理,掌握其API的使用,并能在实际项目中有效地利用Hibernate进行数据持久化操作。

    hibernate学习笔记第二天的源码

    在深入探讨Hibernate学习笔记第二天的源码之前,我们先来理解一下Hibernate的核心概念。Hibernate是一个开源的对象关系映射(ORM)框架,它允许Java开发者将数据库操作转化为对象模型,大大简化了数据访问层的开发...

    Hibernate学习笔记和资料

    hibernate概述,hibernate入门Demo,hibernate配置文件详解(全局配置,实体类映射配置),配置实体规则,核心API详解(Configuration,sessionFactory,session,Transaction),hibernate中的对象状态以及刷新能缓存机制 ...

    马士兵hibernate学习笔记(原版)

    《马士兵Hibernate学习笔记》是一份深入浅出的教程,旨在帮助初学者掌握Hibernate这一流行的Java持久化框架。Hibernate是一个对象关系映射(ORM)工具,它允许开发者用面向对象的方式来操作数据库,从而减少了传统...

    hibernate学习笔记文档

    ### Hibernate 学习笔记知识点概览 #### 一、Hibernate 概述 - **定义**:Hibernate 是一款开源的对象关系映射(ORM)框架,它实现了将 Java 应用程序中的对象模型映射到关系型数据库中的记录。通过 ORM 技术,...

    JDBC Hibernate学习笔记

    ### JDBC与Hibernate学习笔记 #### 一、JDBC概述 **1.1 ODBC与JDBC的区别** - **ODBC(Open Database Connectivity)**: 开放式数据库连接是一种开放标准的应用程序接口(API),用于实现数据库应用程序与不同...

    hibernate 学习笔记3

    标题:Hibernate学习笔记3 描述:本篇笔记深入探讨了Hibernate框架中一对多关系的映射及持久化对象状态管理,结合个人理解与实践经验,旨在为读者提供一份详实的学习资料。 ### 一、一对多关系映射详解 在...

    尚学堂hibernate学习笔记(原版整理)

    【尚学堂Hibernate学习笔记】是一份详尽的学习资料,旨在帮助初学者理解并掌握Hibernate这一流行的Java对象关系映射(ORM)框架。该笔记由作者根据马士兵老师的教程整理而成,其中包含了个人的学习注解,使得内容...

Global site tag (gtag.js) - Google Analytics