`
uule
  • 浏览: 6359010 次
  • 性别: Icon_minigender_1
  • 来自: 一片神奇的土地
社区版块
存档分类
最新评论

Hibernate学习笔记!

阅读更多

Hibernate 是一个开放源代码的对象关系映射框架,它对 JDBC 进行了轻量级的对象封装,使 Java 程序员可以随心所欲的使用对象编程思维来操纵数据库。它不仅提供了从 Java 类到数据表之间的映射,也提供了数据查询和恢复机制。相对于使用 JDBC 和 SQL 来手工操作数据库,Hibernate 可以大大减少操作数据库的工作量。 另外 Hibernate 可以利用代理模式来简化载入类的过程,这将大大减少利用 Hibernate QL 从数据库提取数据的代码的编写量,从而节约开发时间和开发成本 Hibernate 可以和多种Web 服务器或者应用服务器良好集成,如今已经支持几乎所有的流行的数据库服务器。

 

Hibernate 简单介绍与图示原理

http://hi.baidu.com/verdana/blog/item/1eddd43f73dbbac27d1e71c1.html

 

 简单说说 hibernate 的原理

http://www.21jn.net/html/80/n-1180.html

 

Hibernate 与传统 Java 软件架构的对比

http://hi.baidu.com/verdana/blog/item/796033fa56c5b81ea8d311c0.html

 

 

 

 

1、SessionFactory:

 

 Configuration的实例会根据当前的配置信息,构造SessionFactory实例。SessionFactory是线程安全的,一般情况下一个应用中一个数据库共享一个SessionFactory实例。

构建SessionFactory
Hibernate 的SessionFactory接口提供Session类的实例,Session类用于完成对数据库的操作。由于SessionFactory实例是线程安全的(而Session实例不是线程安全的) ,所以每个操作都可以共用同一个SessionFactory来获取Session。

从XML文件读取配置信息构建SessionFactory:
(1)创建一个Configuration对象,并通过该对象的configura()方法加载Hibernate配置文件,代码如下。
Configuration config = new Configuration().configure();

configure() 方法:用于告诉Hibernate加载hibernate.cfg.xml文件。Configuration在实例化时默认加载classpath中的 hibernate.cfg.xml,当然也可以加载名称不是hibernate.cfg.xml的配置文件,例如 wghhibernate.cfg.xml,可以通过以下代码实现。
Configuration config = new Configuration().configure("wghhibernate.cfg.xml");

public class AppManager extends ContextLoaderListener implements
		ServletContextListener {

	private ServletContext context;
	private WebApplicationContext webApplicationContext;

	public void contextDestroyed(ServletContextEvent sce) {
		Enumeration<String> enumeration = this.context.getAttributeNames();
		while (enumeration.hasMoreElements()) {
			context.removeAttribute(enumeration.nextElement());
		}
	}

	public void contextInitialized(ServletContextEvent sce) {
		this.context = sce.getServletContext();
		this.webApplicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
		this.context.setAttribute("WEBAPPLICATIONCONTEXT", webApplicationContext);
		
		String path = this.context.getRealPath(this.context.getInitParameter("configUrl"));
		ConfigurationFactory factory = new ConfigurationFactory(path);
		Configuration config = factory.getConfiguration();
		this.context.setAttribute(MyConstants.CONFIGURATION_KEY, config);
	}
}

 
(2)完成配置文件和映射文件的加载后,将得到一个包括所有Hibernate运行期参数的Configuration实例,通过Configuration实例的buildSessionFactory()方法可以构建一个惟一的SessionFactory,代码如下。

SessionFactory sessionFactory = config.buildSessionFactory();

构建SessionFactory要放在静态代码块中,因为它只在该类被加载时执行一次。 一个典型的构建SessionFactory的代码如下。

 

 

 

public class HibernateUtil {

private static SessionFactory sessionFactory = null;

static {
    try {
             Configuration cfg = new Configuration().configure();
              sessionFactory = cfg.buildSessionFactory();
         } catch (Exception e) {
              System.out.println(e.getMessage());
        }
       }
}

   

2、 了解 get和load的区别?

    * get不支持lazy,load支持lazy
    * 采用get加载数据,如果没有匹配的数据,返回null,而load则抛出异常
   

3、hibernate中Java对象的三种状态
临时状态transient:
    * 在数据库中没有与之匹配的数据
    * 没有纳入session的管理
   
持久状态persistent:
    * 在数据库中有与对应的数据
    * 纳入了session的管理
    * 在清理缓存(脏数据检查)的时候,会和数据库同步
   

持久的实例在数据库中有对应的记录,并拥有一个持久化标识 (identifier).

持久对象总是与 SessionTransaction 相关联,在一个 Session 中,对持久对象的改变不会马上对数据库进行变更,而必须在 Transaction 终止,也就是执行 commit() 之后,才在数据库中真正运行 SQL 进行变更,持久对象的状态才会与数据库进行同步。在同步之前的持久对象称为脏 (dirty) 对象


 

游离(脱管状态)detached:
    *
在数据库中还可能存在一条与它对应的记录
    * 不再纳入session的管理


 

与持久对象关联的 Session 被关闭后,对象就变为脱管对象。对脱管对象的引用依然有效,对象可继续被修改。

脱管对象特点:

(1) 本质上和瞬时对象相同

(2) 只是比瞬时对象多了一个数据库记录标识值 id.

 

 

 

持久对象转为脱管对象:
当执行 close() 或 clear(),evict() 之后,持久对象会变为脱管对象。

瞬时(临时)对象转为持久对象:
(1) 通过 Session 的 save() 和 saveOrUpdate() 方法把一个瞬时对象与数据库相关联,这个瞬时对象就成为持久化对象。
(2) 使用 find(),get(),load() 和 iterater() 待方法查询到的数据对象,将成为持久化对象。

 

上述 3 个状态之间是可以相互转化的,而且 我们所说的状态都是针对某一个session实例而言的 ,比方说,对象 A 对于 session1 而言是处于持久化状态的,因为它处于 session1 的缓存中,但是对于 session2 而言对象 A 并不在它的缓存中,因此它是处于游离状态的。

 

持久状态的对象发生变化会自动同步到数据库:

结合 save(),update(),saveOrUpdate() 方法说明对象的状态

(1)Save() 方法将瞬时对象保存到数据库,对象的临时状态将变为持久化状态。当对象在持久化状态时,它一直位于 Session 的缓存中,对它的任何操作在事务提交时都将同步到数据库,因此,对一个已经持久的对象调用 save() update() 方法是没有意义的。如:

Student stu = new Strudnet();

stu.setCarId(“200234567”);

stu.setId(“100”);

// 打开 Session, 开启事务

session.save(stu);

stu.setCardId(“20076548”);

session.save(stu); // 无效

session.update(stu); // 无效

// 提交事务,关闭 Session

(2)update() 方法两种用途重新关联脱管对象为持久化状态对象,显示调用 update() 以更新对象。调用 update() 只为了关联一个脱管对象到持久状态,当对象已经是持久状态时,调用 update() 就没有多大意义了。如:

// 打开 session ,开启事务

stu = (Student)session.get(Student.class,”123456”);

stu.setName(“Body”);

session.update(stu); // 由于 stu 是持久对象,必然位于 Session 缓冲中,对 stu 所做的变更将

// 被同步到数据库中。所以 update() 是没有意义的,可以不要这句效果一样的。


 

对于脱管对象而言,Hibernate 总是执行 update 语句,不管这个脱管对象在离开 Session 之后有没有更改过,在清理缓存时 Hibernate 总是发送一条 update 语句,以确保脱管对象和数据库记录的数据一致 ,如:

Student stu = new Strudnet();

stu.setCarId(“1234”);

// 打开 Session1, 开启事务

session1.save(stu);

// 提交事务,关闭 Session1

stu.set(“4567”); // 对脱管对象进行更改

// 打开 Session2, 开启事务

session2.update(stu);

// 提交事务,关闭 Session2

注:即使把 session2.update(stu); 这句去掉,提交事务时仍然会执行一条 update() 语句。

如果希望只有脱管对象改变了, Hibernate 才生成 update 语句,可以把映射文件中 <class> 标签的 select-before-update 设为 true, 这种会先发送一条 select 语句取得数据库中的值,判断值是否相同,如果相同就不执行 update 语句。不过这种做法有一定的缺点,每次 update 语句之前总是要发送一条多余的 select 语句,影响性能。对于偶尔更改的类,设置才是有效的,对于经常要更改的类这样做是影响效率的。

(3)saveOrUpdate() 方法兼具 save() update() 方法的功能,对于传入的对象, saveOrUpdate() 首先判断其是脱管对象还是临时对象,然后调用合适的方法。


 

关于Session接口的update方法主要有如下几点要注意:
1.输入参数
一般而言,传递给update的对象要是处于游离状态的对象。如果传一个持久化对象,那么update方法就是多余的 ,因为Hibernate的脏检查机制会自动根据对象属性值的变化向数据库发送一条update语句;如果传入的对象处于临时状态,那么此时Hibernate应该会抛出异常。因为Hibernate在更新数据时会根据对象的OID去数据库查找相应的记录并更新之,而在数据库中是没有记录与这个临时对象相关联的 ,因此Hibernate会抛出异常,当然如果你人为的给临时对象指定一个OID就该另当别论了,如下所示代码片段:

Customer customer=new Customer();
customer.setId(3L);
customer.setName(“Cindyelf”);
session.update(customer);

这段代码会导致如下的sql:update Customer set name=’Cindyelf’ where  id=3;当然如果数据库不存在id为3的那行记录,Hibernate就会抛出异常。而给临时对象指定OID是不合规范的操作,应尽量避免。也就是说不管传入是什么状态对象,数据库中必须要有一条记录与这个对象的OID相对应,否则抛出异常。

2.操作
执行update方法的时候,Hibernate会首先把传入的对象放入Session的缓存中,使之持久化,然后计划执行一个update语句。Hibernate在生成sql语句的时候会根据对象的当前属性值来组装sql语句,也就是说,不管程序中修改了多少次属性值,在执行时只会执行一条update一句。
此外,在update的官方API中特意强调了一点,“如果在session的缓存中有一个持久化对象和所要更新的对象具有相同的OID,那么Hibernate会抛出异常”。下面的代码片段演示了这个错误:

Customer customer=new Customer();
session1.save(customer);

Customer customer1=(Customer)session.load(Customer.class,new Long(6))
session2.update(customer);

如上所示,我在session1中持久化了一个Customer对象,它的OID是6,然后我在session2中load一个OID为6的对象customer1,然后在session2中update之前的customer,注意,对于session2而已,customer1是处于游离状态的,因为它不处于session2的缓存中。此时程序会报如下错误:a different object with the same identifier value was already associated with the session。

 

session.flush与transaction.commit:

以session的save方法为例来看一个简单、完整的事务流程,如下是代码片段:

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
session.save(customer);//之前已实例化好了的一个对象
tx.commit();

示例很简单,就是向数据库中插入一条顾客信息,这是一个最简单的数据库事务。在这个简单的过程中,Hibernate为我们做了一些什么事情呢?为了更好的观察,我们将Hibernate的”show_sql”属性设置为true,然后运行我们的程序,控制台打印出如下信息:

Hibernate: select max(ID) from CUSTOMER
Hibernate: insert into CUSTOMER (NAME, EMAIL, PASSWORD, PHONE, ADDRESS, SEX, IS_MARRIED, description, BIRTHDAY, REGISTERED_TIME, ID) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)

这里也许看不出什么端倪来,现在在session.save(customer)后面加一行代码,输出这个customer的OID,System.out.println(customer.getId()),再次运行程序,控制台输出为:

Hibernate: select max(ID) from CUSTOMER
22
Hibernate: insert into CUSTOMER (NAME, EMAIL, PASSWORD, PHONE, ADDRESS, SEX, IS_MARRIED, description, BIRTHDAY, REGISTERED_TIME, ID) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)

OID在insert语句之前输出,这可以说明两个问题:1.insert语句并不是在执行save的时候发送给数据库的;2.insert语句是在执行commit的时候发送给数据库的 。结合前面我们所说过的:执行save的时候,Hibernate会首先把对象放入缓存,然后计划一条insert语句。一个基本的插入流程就出来了:

1.  判断所要保存的实例是否已处于持久化状态,如果不是,则将其置入缓存;
2.  根据所要保存的实例计划一条insert sql语句,注意只是计划,并不执行;
3.  事务提交时执行之前所计划的insert语句;

后台还打印出了select max(ID) from CUSTOMER,这主要是为了给customer赋予一个OID,因为一般情况下临时对象的OID是NULL。

接着我们做两个测试:
1.  将tx.commit();注释掉,此时控制台没有打印出insert语句;
2.  将tx.commit()换成session.flush,此时控制太打印出了insert语句,但是数据库中并没有添加新的记录;

通过查阅Hibernate的API可以知道flush方法的主要作用就是清理缓存,强制数据库与Hibernate缓存同步,以保证数据的一致性。它的主要动作就是向数据库发送一系列的sql语句,并执行这些sql语句,但是不会向数据库提交 。而commit方法则会首先调用flush方法,然后提交事务。这就是为什么我们仅仅调用flush的时候记录并未插入到数据库中的原因,因为只有提交了事务,对数据库所做的更新才会被保存下来。因为commit方法隐式的调用了flush,所以一般我们都不会显示的调用flush方法。

 

http://blog.csdn.net/CMTobby/archive/2007/08/11/1738392.aspx

 

4、单向关联与双向关联的区别:

单向:
只能通过A查询B,或者B查询A
双向:
既可以通过A查询B,也可以通过B查询A


 

如果只单向关联~A one to many B~

         当hibernate查询A的时候回自动加载相关的B~ 用A.getBorder()之类的就能得到B~(看你设置的方法是什么就是什么~打比方是getBorder())

         当查询B的时候~不会加载A~也就是说从B中是读不到A的~没有B.getAorder()之类的方法在B类里~

双向关联就是~查询A会自动加载B~用A类相应方法得到A类相应的B类~

         同时查询B也会自动加载A类~用B类相应方法得到B类相应的A类~


 

5、延迟加载:

当真正使用的时候,才发出SQL语句

lazy只有 session打开状态下才有效


 

使用缓存的一个很明显的好处就是可以减少数据库访问的频率,提高应用程序的性能,因为从内存中读取数据显然要比从数据库中查询快多了。

 

Hibernate与延迟加载

  Hibernate对象关系映射提供延迟的与非延迟的对象初始化。非延迟加载在读取一个对象的时候会将与这个对象所有相关的其他对象一起读取出来 。这有时会导致成百的(如果不是成千的话)select语句在读取对象的时候执行。这个问题有时出现在使用双向关系的时候,经常会导致整个数据库都在初始化的阶段被读出来了。当然,你可以不厌其烦地检查每一个对象与其他对象的关系,并把那些最昂贵的删除,但是到最后,我们可能会因此失去了本想在ORM工具中获得的便利。  

一个明显的解决方法是使用Hibernate提供的延迟加载机制 。这种初始化策略只在一个对象调用它的一对多或多对多关系时才将关系对象读取出来 。这个过程对开发者来说是透明的,而且只进行了很少的数据库操作请求,因此会得到比较明显的性能提升。这项技术的一个缺陷是延迟加载技术要求一个Hibernate会话要在对象使用的时候一直开着。这会成为通过使用DAO模式将持久层抽象出来时的一个主要问题。为了将持久化机制完全地抽象出来,所有的数据库逻辑,包括打开或关闭会话,都不能在应用层出现。最常见的是,一些实现了简单接口的DAO实现类将数据库逻辑完全封装起来了。一种快速但是笨拙的解决方法是放弃DAO模式,将数据库连接逻辑加到应用层中来。这可能对一些小的应用程序有效,但是在大的系统中,这是一个严重的设计缺陷,妨碍了系统的可扩展性。

 

spring的容器是提供了lazy-load的,即默认的缺省设置是bean没有lazy-load,该属性处于false状态,这样导致spring 在启动过程导致在启动时候,会默认加载整个对象实例图,从初始化ACTION配置、到service配置到dao配置、乃至到数据库连接、事务等等。
把beans的default-lazy-init改为true的话,spring在启动的时候并没有真正实例化对象,而只是用一个代理来实现。当真正需要调用该类的时候,才会去实例化   
不是说有的beans都能设置default-lazy-init成为true.对于scheduler的bean不能用lazy-init

 

 

Hibernate习题总结:

一、Hibernate工作原理:

   1. 读取并解析配置文件
   2. 读取并解析映射信息,创建SessionFactory
   3. 打开Sesssion
   4. 创建事务Transation
   5. 持久化操作
   6. 提交事务
   7. 关闭Session
   8. 关闭SesstionFactory

二、Hibernate有什么好处:

    * 对JDBC访问数据库的代码做了封装 ,大大简化了数据访问层繁琐的重复性代码。
    * Hibernate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现。他很大程度的简化DAO层的编码工作
    * hibernate使用Java反射机制,而不是字节码增强程序来实现透明性。
    * hibernate的性能非常好,因为它是个轻量级框架。映射的灵活性很出色。它支持各种关系数据库,从一对一到多对多的各种复杂关系。 

三、Hibernate是如何延迟加载的:

  Hibernate2延迟加载实现:a)实体对象 b)集合(Collection)
  Hibernate3 提供了属性的延迟加载功能


四、Hibernate的查询方式:

Sql、Criteria,object comptosition
Hql:
    * 属性查询
    * 参数查询、命名参数查询
    * 关联查询
    * 分页查询
    * 统计函数 

五、说下Hibernate的缓存机制:
1. 内部缓存存在Hibernate中又叫一级缓存,属于应用事物级缓存 
2. 二级缓存: 
a) 应用及缓存 
b) 分布式缓存 
条件:数据不会被第三方修改、数据大小在可接受范围、数据更新频率低、同一数据被系统频繁使用、非 关键数据 
c) 第三方缓存的实现  

六、如何优化Hibernate:
1.使用双向一对多关联,不使用单向一对多 
2.灵活使用单向一对多关联 
3.不用一对一,用多对一取代 
4.配置对象缓存,不使用集合缓存 
5.一对多集合使用Bag,多对多集合使用Set 
6. 继承类使用显式多态 
7. 表字段要少,表关联不要怕多,有二级缓存撑腰

 

 

  • 大小: 18.6 KB
分享到:
评论

相关推荐

    Hibernate学习笔记!

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

    Struts+spring+hibernate学习笔记! - Struts原理与实践 - JavaEye知识库.files

    Struts、Spring 和 Hibernate 是Java开发中非常著名的三个开源框架,它们在企业级应用开发中起着关键作用。...学习 SSH 可以帮助开发者更好地掌握企业级应用的构建方法,对于提升技能和理解框架间的协作具有重要意义。

    Hibernate学习笔记

    Hibernate学习笔记 Hibernate学习笔记 Hibernate学习笔记 Hibernate学习笔记

    Hibernate学习笔记整理

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

    Hibernate学习笔记特别详细

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

    传智播客 汤阳光 Hibernate 学习笔记

    传智播客 汤阳光 Hibernate 学习笔记,非常详细的hibernate学习资料!

    hibernate 学习笔记精要

    hibernate 学习笔记精要hibernate 学习笔记精要hibernate 学习笔记精要hibernate 学习笔记精要

    hibernate学习笔记

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

    Hibernate 学习笔记(全套)

    这套笔记是我学习Hibernate,进行相关技术点训练时记录下来的,其中包括技术点说明与相关事例,拿出来与大家分享。

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

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

    hibernate学习笔记mashibing

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

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

    ### 马士兵Hibernate学习笔记知识点总结 #### 一、课程内容概览 - **HelloWorld**:通过简单的示例程序介绍如何启动一个基于Hibernate的Java项目。 - **Hibernate原理模拟**:解释O/R Mapping的概念及其重要性。 -...

    Hibernate学习笔记与总结

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

    Hibernate学习笔记和资料

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

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

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

    hibernate学习笔记文档

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

    hibernate学习笔记第二天的源码

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

Global site tag (gtag.js) - Google Analytics