﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-舞影凌乱-随笔分类-hibernate</title><link>http://www.blogjava.net/lovefeel2004/category/37179.html</link><description>&lt;a href="http://www.blogjava.net/lovefeel2004"&gt;
&lt;h2&gt;
好好学习,努力工作,做个快乐的猪!!!
&lt;/h2&gt;
&lt;/a&gt;</description><language>zh-cn</language><lastBuildDate>Thu, 08 Jan 2009 06:46:38 GMT</lastBuildDate><pubDate>Thu, 08 Jan 2009 06:46:38 GMT</pubDate><ttl>60</ttl><item><title>Hibernate API(转载)</title><link>http://www.blogjava.net/lovefeel2004/archive/2009/01/08/250466.html</link><dc:creator>幽梦新影</dc:creator><author>幽梦新影</author><pubDate>Thu, 08 Jan 2009 04:04:00 GMT</pubDate><guid>http://www.blogjava.net/lovefeel2004/archive/2009/01/08/250466.html</guid><wfw:comment>http://www.blogjava.net/lovefeel2004/comments/250466.html</wfw:comment><comments>http://www.blogjava.net/lovefeel2004/archive/2009/01/08/250466.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lovefeel2004/comments/commentRss/250466.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lovefeel2004/services/trackbacks/250466.html</trackback:ping><description><![CDATA[
		<p>提供访问数据库操作的接口：Session接口，Transation接口，Query接口</p>
		<p>用于配置Hibernate的接口：Configuration接口</p>
		<p>Hibernate核心接口</p>
		<p>Configuration接口：配置Hibernate,Hibernate应用通过Configuration实例来指定对象-关系映射文件的位置或动态配置Hibernate的属性，然后创建SessionFactory对象实例。</p>
		<p>SessionFactory接口：初始化Hibernate,充当数据存储源的代理、创建Session对象。</p>
		<p>一个SessionFactory实例对应一个数据存储源，Hibernate应用从SessionFactory中获得Session对象实例。</p>
		<p>特定：它是线程安全的，意味着同一个实例可以被应用的多个线程共享，它是重量级的，意味着不能随意创建或销毁实例，一个数据库访问只需创建一个实例。</p>
		<p>Session接口：负责保存、更新、删除、加载、查询对象</p>
		<p>Session接口被称做持久化管理器，每个Session实例都有自已的缓存，用来存放被当前工作单元加载的对象且只能被当前工作单元访问。</p>
		<p>特性，它不是线程安全的，应该避免多个线程共享同一个Session实例，它是轻量级的，意味着创建或销毁实例不需要消耗太多的资源，可以为每个请求分配单独的Session实例，或者为每个工作单元分配单独的Session实例。</p>
		<p>Transation接口：Hibernate的数据库事务接口，对底层的事务接口做了封装。</p>
		<p>封装的底层事务接口：</p>
		<p>JDBC API、JTA（Java Transation）API、CORBA（Common Object Request Broker Architecture）API</p>
		<p>通过一致的Transation接口来声明事务边界，有利于应用在不同环境或容器中移植。</p>
		<p>Query接口和Criteria接口：执行数据库查询，控制执行查询的过程。</p>
		<p>Query接口封装了一个面向对象的查询语句（Hibernate Query Language, HQL）</p>
		<p>Criteria接口封装了基于字符串形式的查询语句，擅长于执行动态查询。</p>
		<p>回调接口：Interceptor接口、Lifecycle接口、Validatable接口</p>
		<p>当一个对象发生了特定的事件（如加载、保存、更新、删除），Hibernate应用可以通过回调来响应事件。</p>
		<p>回调接口按实现方式可分为：</p>
		<p>Lifecycle接口和Validatable接口：由持久化类来实现接口。</p>
		<p>Lifecycle接口，使持久化类的实例能响应被加载、保存、删除的事件。</p>
		<p>Validatable接口，使持久化类的实例在被保存前进行数据验证。</p>
		<p>Interceptor接口：不必由持久化类来实现接口。Interceptor实现类负责响应持久化类的实例被加载、保存、更新、删除的事件。</p>
		<p>映射类型接口：Type接口、UserType接口、CompositeUserType接口</p>
		<p>Type接口，表示Hibernate映射类型，用于把域对象映射为数据库的关系数据。</p>
		<p>Type接口的实现类：PrimitiveType类，映射Java基本类型。DateType类，映射Java日期类型。</p>
		<p>扩展接口：</p>
		<p>定制主键的生成策略：IndentifierGenerator接口</p>
		<p>定制本地SQL方言：Dialect抽象类</p>
		<p>定制缓存机制：Cache接口、CacheProvider接口</p>
		<p>定制JDBC连接管理：ConnectionProvider接口</p>
		<p>定制事务管理：TransationFactory接口、Transation接口、TransationManagerLookup接口</p>
		<p>定制ORM策略：ClassPersister接口及其子接口</p>
		<p>定制属性访问策略：PropertyAccesser接口</p>
		<p>创建代理：ProxyFactory接口</p>
		<p>定制客户化映射类型：UserType接口、CompositeUserType接口。</p>
		<p>在Hibernate中处理批量更新和批量删除</p>
		<p>批量更新是指在一个事务中更新大批量数据，批量删除是指在一个事务中删除大批量数据，以下程序直接通过Hibernate API批量更新</p>
		<p>tx = session.beginTransaction();<br />Iterator customers=session.find("from Customer c where c.age&gt;0").iterator();<br />while(customers.hasNext()){<br />Customer customer=(Customer)customers.next();<br />customer.setAge(customer.getAge()+1);<br />}<br />tx.commit();<br />session.close();<br />如果CUSTOMERS表中有1万条年龄大于零的记录，那么Session的find()方法会一下子加载1万个Customer对象到内存。当执行tx.commit()方法时，会清理缓存，Hibernate执行1万条更新CUSTOMERS表的update语句：</p>
		<p>update CUSTOMERS set AGE=? …. where ID=i;<br />update CUSTOMERS set AGE=? …. where ID=j;<br />……<br />update CUSTOMERS set AGE=? …. where ID=k;<br />以上批量更新方式有两个缺点：</p>
		<p>(1) 占用大量内存，必须把1万个Customer对象先加载到内存，然后一一更新它们。</p>
		<p>(2) 执行的update语句的数目太多，每个update语句只能更新一个Customer对象，必须通过1万条update语句才能更新一万个Customer对象，频繁的访问数据库，会大大降低应用的性能。</p>
		<p>为了迅速释放1万个Customer对象占用的内存，可以在更新每个Customer对象后，就调用Session的evict()方法立即释放它的内存：</p>
		<p>tx = session.beginTransaction();<br />Iterator customers=session.find("from Customer c where c.age&gt;0").iterator();<br />while(customers.hasNext()){<br />Customer customer=(Customer)customers.next();<br />customer.setAge(customer.getAge()+1);<br />session.flush();<br />session.evict(customer);<br />} <br />tx.commit();<br />session.close();</p>
		<p>在以上程序中，修改了一个Customer对象的age属性后，就立即调用Session的flush()方法和evict()方法，flush()方法使Hibernate立刻根据这个Customer对象的状态变化同步更新数据库，从而立即执行相关的update语句；evict()方法用于把这个Customer对象从缓存中清除出去，从而及时释放它占用的内存。</p>
		<p>但evict()方法只能稍微提高批量操作的性能，因为不管有没有使用evict()方法，Hibernate都必须执行1万条update语句，才能更新1万个Customer对象，这是影响批量操作性能的重要因素。假如Hibernate能直接执行如下SQL语句：</p>
		<p>update CUSTOMERS set AGE=AGE+1 where AGE&gt;0;</p>
		<p>那么以上一条update语句就能更新CUSTOMERS表中的1万条记录。但是Hibernate并没有直接提供执行这种update语句的接口。应用程序必须绕过Hibernate API，直接通过JDBC API来执行该SQL语句：</p>
		<p>tx = session.beginTransaction();<br />Connection con=session.connection();<br />PreparedStatement stmt=con.prepareStatement("update CUSTOMERS set AGE=AGE+1 "<br />+"where AGE&gt;0 ");<br />stmt.executeUpdate();<br />tx.commit();<br />以上程序演示了绕过Hibernate API，直接通过JDBC API访问数据库的过程。应用程序通过Session的connection()方法获得该Session使用的数据库连接，然后通过它创建PreparedStatement对象并执行SQL语句。值得注意的是，应用程序仍然通过Hibernate的Transaction接口来声明事务边界。</p>
		<p>如果底层数据库（如Oracle）支持存储过程，也可以通过存储过程来执行批量更新。存储过程直接在数据库中运行，速度更加快。在Oracle数据库中可以定义一个名为batchUpdateCustomer()的存储过程，代码如下：</p>
		<p>create or replace procedure batchUpdateCustomer(p_age in number) as<br />begin<br />update CUSTOMERS set AGE=AGE+1 where AGE&gt;p_age;<br />end;<br />以上存储过程有一个参数p_age，代表客户的年龄，应用程序可按照以下方式调用存储过程：</p>
		<p>tx = session.beginTransaction();<br />Connection con=session.connection();<br />String procedure = "{call batchUpdateCustomer(?) }";<br />CallableStatement cstmt = con.prepareCall(procedure);<br />cstmt.setInt(1,0); //把年龄参数设为0<br />cstmt.executeUpdate();<br />tx.commit();<br />从上面程序看出，应用程序也必须绕过Hibernate API，直接通过JDBC API来调用存储过程。</p>
		<p>Session的各种重载形式的update()方法都一次只能更新一个对象，而delete()方法的有些重载形式允许以HQL语句作为参数，例如：</p>
		<p>session.delete("from Customer c where c.age&gt;0"); <br />如果CUSTOMERS表中有1万条年龄大于零的记录，那么以上代码能删除一万条记录。但是Session的delete()方法并没有执行以下delete语句：</p>
		<p>delete from CUSTOMERS where AGE&gt;0;</p>
		<p>Session的delete()方法先通过以下select语句把1万个Customer对象加载到内存中：</p>
		<p>select * from CUSTOMERS where AGE&gt;0; <br />接下来执行一万条delete语句，逐个删除Customer对象：</p>
		<p>delete from CUSTOMERS where ID=i;<br />delete from CUSTOMERS where ID=j;<br />……<br />delete from CUSTOMERS where ID=k;<br />由此可见，直接通过Hibernate API进行批量更新和批量删除都不值得推荐。而直接通过JDBC API执行相关的SQL语句或调用相关的存储过程，是批量更新和批量删除的最佳方式，这两种方式都有以下优点：</p>
		<p>(1) 无需把数据库中的大批量数据先加载到内存中，然后逐个更新或修改它们，因此不会消耗大量内存。</p>
		<p>(2) 能在一条SQL语句中更新或删除大批量的数据。</p>
		<p>在hibernate中，最核心的概念就是对PO的状态管理，一个PO有三种状态：</p>
		<p>未被持久化的VO</p>
		<p>此时就是一个内存对象VO，由JVM管理生命周期</p>
		<p>已被持久化的PO，并且在Session使命周期内</p>
		<p>此时映射数据库数据，由数据库管理生命周期</p>
		<p>曾被持久化过，但现在和Session已经detached了，以VO的身份在运行。</p>
		<p>这种和Session已经detached的PO还能够进入别一个Session，继续进行PO状态状管，此时它就成为PO的第二种状态了。</p>
		<p>
				<span style="COLOR: red">这种PO实际上是跨了Session进行了状态维护的。</span>
				<br />
				<br />在传统的JDO1.x中，PO只有前面两种状态，一个PO一旦脱离PM，就丧失了状态了，不再和数据库数据关联，成为一个纯粹的内存VO，它即使进入一个新的PM，也不能恢复它的状态了。 <br /><br />Hibernate强的地方就在于，一个PO脱离Session之后，还能保持状态，再进入一个新的Session之后，就恢复状态管理的能力，但此时状态管理需要使用session.update或者session.saveOrUpdate，这就是Hibernate Reference中提到的“requires a slightly different programming model ”</p>
<img src ="http://www.blogjava.net/lovefeel2004/aggbug/250466.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lovefeel2004/" target="_blank">幽梦新影</a> 2009-01-08 12:04 <a href="http://www.blogjava.net/lovefeel2004/archive/2009/01/08/250466.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>