J2EE中最大的一个观念就是分?.
session是持久层的东?不可H到别的?.
你的q个问题其实是延迟加蝲的问?
从理论的角度?最好是用一个就关一?防止资源消?
但由于hibernate中的延迟加蝲,所以出C你的关闭session的话,无法读取到学生c里的classes值问?
q个问题可以用Hibernate.initialize()来解?也可׃用opensessionview的方?spring中提供了q样的filter
不知道这在用中有没有用spring.用了比较方?也不会出C所说的
对于后两U情况,用标{N历时不太方便Q因为无法直接{换成实体cȝ对象。比较简单的解决Ҏ(gu)是:
の:在hql中?span style="color: rgb(255,0,0)">select new 包名.cd(属?Q属?……) from 实体c,同时在实体类中添加带参的构造方法,参数的个数和序与(属?Q属?……) 保持一?/span>Q这h们得到的list中存攄依然是实体类的对象,所查询到的属性得C填充Q用v来更为方ѝ?br />の:hql查询多表部分字段Q?span style="color: rgb(255,0,0)">select new 包名.?实体cd(?.属?Q表2.属?……) from ?实体c??实体c?where ?.ID=?.IDQ即相关联的字段Q?/span>Q同时在要返回的?实体cMd?的属性和带参的构造方法,参数的个数和序与(?.属?Q表2.属?2……) 保持一?/span>
例如要查询Problem 中的pidQscoreQtitleQtotalAccept,totalSubmission,unSee
感谢glamey兄弟的文章,正好解决了当前遇到的问题。原文链接如下:http://glamey.iteye.com/blog/721019
假设我们现在有一个DTOQ其属性包括两张表的属性,我们现在需要将sql语句查询得到的内容{Z个DTO对象Q其解决Ҏ(gu)如下Q?nbsp;
public class UserBean implements java.io.Serializable {
// Fields
private String id1;
private String name1;
private java.util.Date createtime1;
private String address;
// Constructors
/** default constructor */
public UserBean() {
}
/** minimal constructor */
public UserBean(String id1) {
this.id1 = id1;
}
/** full constructor */
public UserBean(String id1, String name1, java.util.Date createtime1, String address) {
this.id1 = id1;
this.name1 = name1;
this.createtime1 = createtime1;
this.address = address;
}
// Property accessors
public String getId1() {
return this.id1;
}
public void setId1(String id1) {
this.id1 = id1;
}
public String getName1() {
return this.name1;
}
public void setName1(String name1) {
this.name1 = name1;
}
public java.util.Date getCreatetime1() {
return this.createtime1;
}
public void setCreatetime1(java.util.Date createtime1) {
this.createtime1 = createtime1;
}
public String getAddress() {
return this.address;
}
public void setAddress(String address) {
this.address = address;
}
}
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"<!--
Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
<class name="com.lcdbtsf.air.po.UserBean" table="ABIN5" schema="ABIN" dynamic-update="true">
<id name="id1" type="string">
<column name="ID1" precision="0" />
<generator class="assigned" />
</id>
<property name="name1" type="string">
<column name="NAME1" default="defaultname1"/>
</property>
<property name="createtime1" type="java.util.Date">
<column name="CREATETIME1" length="19" />
</property>
<property name="address" type="string" update="true" access="field" insert="true">
<column name="ADDRESS" default="defaultaddress" />
</property>
</class>
<query name="getUserBeanByAddress">
<![CDATA[select o from UserBean o where o.address=:address order by o.createtime1 desc]]>
</query>
<!-- 命名查询中用sqlQ不推荐使用Q媄响跨数据?br /> <sql-query name="getUserBeanByAddress">
<![CDATA[select o from UserBean o where o.address=:address order by o.createtime1 desc]]>
</sql-query>
-->
</hibernate-mapping>
package com.abin.lee.hibernate;
import java.util.List;
import junit.framework.TestCase;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.Order;
import com.lcdbtsf.air.po.UserBean;
public class UserDao extends TestCase {
public List<UserBean> getAll(){
Configuration cfg = new Configuration().configure(); // 获取hibernate的配|信?br /> SessionFactory sf = cfg.buildSessionFactory(); // Ҏ(gu)config建立sessionFactory
Session session = sf.openSession(); // factory用于建立sessionQ开启SessionQ相当于开启JDBC的Connection
Transaction ts = session.beginTransaction(); // 创徏事务的对象ts
List<UserBean> list=null;
try {
Criteria criteria=session.createCriteria(UserBean.class);
criteria.addOrder(Order.desc("createtime1"));
list=criteria.list();
ts.commit();
} catch (HibernateException he) {
he.printStackTrace();
ts.rollback();
}
return list;
}
public List<UserBean> getAllByAddress(String address){
Configuration cfg = new Configuration().configure(); // 获取hibernate的配|信?br /> SessionFactory sf = cfg.buildSessionFactory(); // Ҏ(gu)config建立sessionFactory
Session session = sf.openSession(); // factory用于建立sessionQ开启SessionQ相当于开启JDBC的Connection
Transaction ts = session.beginTransaction(); // 创徏事务的对象ts
List<UserBean> list=null;
try {
Query query=session.getNamedQuery("getUserBeanByAddress");
query.setParameter("address", address);
list=query.list();
ts.commit();
} catch (HibernateException he) {
he.printStackTrace();
ts.rollback();
}
return list;
}
}
package com.abin.lee.hibernate;
import java.util.List;
import junit.framework.TestCase;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import com.lcdbtsf.air.po.UserBean;
public class UserDaoTest extends TestCase {
public void test() {
List<UserBean> list=new UserDao().getAllByAddress("shanghai");
try {
if(list.size()>0){
UserBean user =list.get(0);
System.out.println(list.get(0).getId1());
}
} catch (HibernateException he) {
he.printStackTrace(); }
}
}
/**
* Userbean entity. @author MyEclipse Persistence Tools
*/
public class UserBean implements java.io.Serializable {
// Fields
private String id;
private String username;
private String password;
// Constructors
/** default constructor */
public UserBean() {
}
/** minimal constructor */
public UserBean(String id) {
this.id = id;
}
/** full constructor */
public UserBean(String id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
// Property accessors
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
public String getUsername() {
return this.username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
}
package com.abin.lee.dao;
import java.sql.SQLException;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
public class UserDao {
private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
private static SessionFactory sessionFactory;
static {
sessionFactory=new Configuration().configure().buildSessionFactory();
}
public static Session GetSession(){
Session session=(Session)threadLocal.get();
if(null == session|| !session.isOpen()){
if(null==sessionFactory){
sessionFactory=new Configuration().configure().buildSessionFactory();
}
session=(sessionFactory!=null)?sessionFactory.openSession():null;
threadLocal.set(session);
}
return session;
}
public static int insert(String id,String usr,String pwd) throws SQLException{
UserDao UserDao=new UserDao();
Session session=UserDao.GetSession();
Transaction tx=session.beginTransaction();
SQLQuery sqlQuery = session.createSQLQuery("{call insertObj(?,?,?)}");
sqlQuery.setParameter(0, id);
sqlQuery.setParameter(1, usr);
sqlQuery.setParameter(2, pwd);
int result=sqlQuery.executeUpdate();
System.out.println("result="+result);
return result;
}
}
package com.abin.lee.test;
import java.sql.SQLException;
import junit.framework.TestCase;
import com.abin.lee.dao.UserDao;
public class UserTest extends TestCase{
public void test() throws SQLException{
UserDao user=new UserDao();
int success=user.insert("abin","abing","bing");
System.out.println("success="+success);
}
}
<?xml version='1.0' encoding='UTF-8'?> <!-- Generated by MyEclipse Hibernate Tools. --> <session-factory> </hibernate-configuration>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"
<hibernate-configuration>
<property name="dialect">
org.hibernate.dialect.OracleDialect
</property>
<property name="connection.url">
jdbc:oracle:thin:@localhost:1521:xe
</property>
<property name="connection.username">abing</property>
<property name="connection.password">abing</property>
<property name="connection.driver_class">
oracle.jdbc.driver.OracleDriver
</property>
<property name="myeclipse.connection.profile">
OracleConnection
</property>
<mapping resource="com/abin/lee/bean/UserBean.hbm.xml" />
</session-factory>
]]>
在spring下配|用二U缓存:
<property name="hibernateProperties">
<props>
........
<prop key="hibernate.cache.provider_class">${hibernate.cache.provider_class}</prop>
<prop key="hibernate.cache.use_query_cache">${hibernate.cache.use_query_cache}</prop>
</props>
</property>
其中${hibernate.cache.provider_class}为net.sf.ehcache.hibernate.EhCacheProviderQ?{hibernate.cache.use_query_cache}属性gؓtrueQ对l常使用的List查询方式Q只有在使用查询~存Ӟ才会从缓存中通过id去get~存的|查询~存一般缓存查询语句和查询l果的idQ?/p>
A的持久化映射文g中加上cache元素Qusage属性的取值根据自q情况自己指定相应的?/p>
<cache usage="read-write"/>
配置spring的HibernateTemplateҎ(gu)询语句和l果~存QcacheQueriesgؓtrue)Q?/p>
<bean id="hibernateTemplate"
<property name="sessionFactory"><ref bean="sessionFactory"/></property>
<property name="cacheQueries" value="${hibernate.cache.use_query_cache}"></property>
</bean>
开发的spring daoQ集成HibernateDaoSupportQ应该配|实用这个hibernateTemplateQ?/p>
<bean id="myDao" of HibernateDaoSupport">
<property name="hibernateTemplate" ref="hibernateTemplate" />
<property name="jdbcTemplate" ref="jdbcTemplate" />
</bean>
在src下新建ehcache.xml文gQ文件内容如下:
<ehcache>
<diskStore path="java.io.tmpdir"/>
<!--
eternal:元素是否怹?
MemoryStoreEvictionPolicy:default is LRU
-->
<defaultCache maxElementsInMemory="10000"
eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120"
overflowToDisk="true" diskPersistent="false" diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"/>
<cache name="cn.hnisi.persistence.mmedia.Dmtjbxx"
maxElementsInMemory="500" eternal="false"
timeToIdleSeconds="2400" timeToLiveSeconds="3600"
overflowToDisk="false"/>
<cache name="org.hibernate.cache.StandardQueryCache"
maxElementsInMemory="50" eternal="false" timeToIdleSeconds="600"
timeToLiveSeconds="1200" overflowToDisk="false"/>
<cache name="org.hibernate.cache.UpdateTimestampsCache"
maxElementsInMemory="500" eternal="true" overflowToDisk="false"/>
</ehcache>
然后你可以用HQL查询对象了,比如"from A where name=Q?Q?/p>
跟踪查询的sql日志可以看出第一ơ是查询数据库,W二ơ是从缓存中get(见Hibernate ReadWriteCachecȝgetҎ(gu)Q?/p>
问题Q什么样的数据适合存放到第二~存中?
1 很少被修改的数据
2 不是很重要的数据Q允许出现偶ƈ发的数据
3 不会被ƈ发访问的数据
4 参考数?指的是供应用参考的帔R数据Q它的实例数目有限,它的实例会被许多其他cȝ实例引用Q实例极或者从来不会被修改?/p>
本文来自CSDN博客Q{载请标明出处Q?a rel="nofollow">http://blog.csdn.net/selley/archive/2008/03/13/2177479.aspx
在applicationContext.xml中有如下配置Q?/span>
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
也可以:
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
两种实现方式其实没有区别Q尤其是W二U不要自己去关闭sessionQsession在事务结束后都会自动关闭?但是一定要注意延迟加蝲的问题,当对象在session关闭前没有从数据库中取得Q而jsp中需要展C对象时Q会提示LazyInitializationExceptionQ你可以通过OpenSessionInViewFilter来保证gq加载不会出现错误,卻I
<filter>
<filter-name>opensession</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>opensession</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
~存是介于应用程序和物理数据源之_其作用是Z降低应用E序对物理数据源讉K的频ơ,从而提高了应用的运行性能。缓存内的数据是对物理数据源中的数据的复Ӟ应用E序在运行时从缓存读写数据,在特定的时刻或事件会同步~存和物理数据源的数据?/p>
~存的介质一般是内存Q所以读写速度很快。但如果~存中存攄数据量非常大Ӟ也会用硬盘作为缓存介质。缓存的实现不仅仅要考虑存储的介质,q要考虑到管理缓存的q发讉K和缓存数据的生命周期?/p>
Hibernate的缓存包括Session的缓存和SessionFactory的缓存,其中SessionFactory的缓存又可以分ؓ两类Q内|缓存和外置~存。Session的缓存是内置的,不能被卸载,也被UCؓHibernate的第一U缓存。SessionFactory的内|缓存和Session的缓存在实现方式上比较相|前者是SessionFactory对象的一些集合属性包含的数据Q后者是指Session的一些集合属性包含的数据。SessionFactory的内|缓存中存放了映元数据和预定义SQL语句Q映元数据是映文件中数据的拷贝,而预定义SQL语句是在Hibernate初始化阶D|据映元数据推导出来QSessionFactory的内|缓存是只读的,应用E序不能修改~存中的映射元数据和预定义SQL语句Q因此SessionFactory不需要进行内|缓存与映射文g的同步。SessionFactory的外|缓存是一个可配置的插件。在默认情况下,SessionFactory不会启用q个插g。外|缓存的数据是数据库数据的拷贝,外置~存的介质可以是内存或者硬盘。SessionFactory的外|缓存也被称为Hibernate的第二~存?/p>
Hibernate的这两~存都位于持久化层,存放的都是数据库数据的拷贝,那么它们之间的区别是什么呢Qؓ了理解二者的区别Q需要深入理解持久化层的~存的两个特性:~存的范围和~存的ƈ发访问策略?/p>
持久化层的缓存的范围
~存的范围决定了~存的生命周期以及可以被谁访问。缓存的范围分ؓ三类?/p>
1 事务范围Q缓存只能被当前事务讉K。缓存的生命周期依赖于事务的生命周期Q当事务l束Ӟ~存也就l束生命周期。在此范围下Q缓存的介质是内存。事务可以是数据库事务或者应用事务,每个事务都有独自的缓存,~存内的数据通常采用怺兌的的对象形式?/p>
2 q程范围Q缓存被q程内的所有事务共享。这些事务有可能是ƈ发访问缓存,因此必须对缓存采取必要的事务隔离机制。缓存的生命周期依赖于进E的生命周期Q进E结束时Q缓存也q束了生命周期。进E范围的~存可能会存攑֤量的数据Q所以存攄介质可以是内存或盘。缓存内的数据既可以是相互关联的对象形式也可以是对象的松散数据Ş式。松散的对象数据形式有点cM于对象的序列化数据,但是对象分解为松散的法比对象序列化的算法要求更快?/p>
3 集群范围Q在集群环境中,~存被一个机器或者多个机器的q程׃n。缓存中的数据被复制到集环境中的每个进E节点,q程间通过q程通信来保证缓存中的数据的一致性,~存中的数据通常采用对象的松散数据Ş式?/p>
对大多数应用来说Q应该慎重地考虑是否需要用集范围的~存Q因问的速度不一定会比直接访问数据库数据的速度快多?/p>
持久化层可以提供多种范围的缓存。如果在事务范围的缓存中没有查到相应的数据,q可以到q程范围或集范围的~存内查询,如果q是没有查到Q那么只有到数据库中查询。事务范围的~存是持久化层的W一U缓存,通常它是必需的;q程范围或集范围的~存是持久化层的W二U缓存,通常是可选的?/p>
持久化层的缓存的q发讉K{略
当多个ƈ发的事务同时讉K持久化层的缓存的相同数据Ӟ会引起ƈ发问题,必须采用必要的事务隔L施?/p>
在进E范围或集群范围的缓存,即第二~存Q会出现q发问题。因此可以设定以下四U类型的q发讉K{略Q每一U策略对应一U事务隔ȝ别?/p>
事务型:仅仅在受理环境中适用。它提供了Repeatable Read事务隔离U别。对于经常被M很少修改的数据,可以采用q种隔离cdQ因为它可以防止脏读和不可重复读q类的ƈ发问题?/p>
d型:提供了Read Committed事务隔离U别。仅仅在非集的环境中适用。对于经常被M很少修改的数据,可以采用q种隔离cdQ因为它可以防止脏读q类的ƈ发问题?/p>
非严D写型Q不保证~存与数据库中数据的一致性。如果存在两个事务同时访问缓存中相同数据的可能,必须数据配置一个很短的数据q期旉Q从而尽量避免脏诅R对于极被修改Qƈ且允许偶脏ȝ数据Q可以采用这Uƈ发访问策略? 只读型:对于从来不会修改的数据,如参考数据,可以使用q种q发讉K{略?/p>
事务型ƈ发访问策略是事务隔离U别最高,只读型的隔离U别最低。事务隔ȝ别越高,q发性能p低?/p>
什么样的数据适合存放到第二~存中?
1、很被修改的数?/p>
2、不是很重要的数据,允许出现偶尔q发的数?/p>
3、不会被q发讉K的数?/p>
4、参考数?/p>
不适合存放到第二~存的数据?
1、经常被修改的数?/p>
2、胦务数据,l对不允许出现ƈ?/p>
3、与其他应用׃n的数据?/p>
Hibernate的二U缓?/p>
如前所qͼHibernate提供了两U缓存,W一U是Session的缓存。由于Session对象的生命周期通常对应一个数据库事务或者一个应用事务,因此它的~存是事务范围的~存。第一U缓存是必需的,不允许而且事实上也无法比卸除。在W一U缓存中Q持久化cȝ每个实例都具有唯一的OID?/p>
W二U缓存是一个可插拔的的~存插gQ它是由SessionFactory负责理。由于SessionFactory对象的生命周期和应用E序的整个过E对应,因此W二U缓存是q程范围或者集范围的~存。这个缓存中存放的对象的松散数据。第二对象有可能出现ƈ发问题,因此需要采用适当的ƈ发访问策略,该策略ؓ被缓存的数据提供了事务隔ȝ别。缓存适配器用于把具体的缓存实现Y件与Hibernate集成。第二~存是可选的Q可以在每个cL每个集合的粒度上配置W二U缓存?/p>
Hibernate的二U缓存策略的一般过E如下:
1) 条g查询的时候,L发出一条select * from table_name where …. Q选择所有字D)q样的SQL语句查询数据库,一ơ获得所有的数据对象?/p>
2) 把获得的所有数据对象根据ID攑օ到第二~存中?/p>
3) 当HibernateҎ(gu)ID讉K数据对象的时候,首先从Session一U缓存中查;查不刎ͼ如果配置了二U缓存,那么从二U缓存中查;查不刎ͼ再查询数据库Q把l果按照ID攑օ到缓存?/p>
4) 删除、更新、增加数据的时候,同时更新~存?/p>
Hibernate的二U缓存策略,是针对于ID查询的缓存策略,对于条g查询则毫无作用。ؓ此,Hibernate提供了针Ҏ(gu)件查询的Query~存?/p>
Hibernate的Query~存{略的过E如下:
1) Hibernate首先Ҏ(gu)q些信息l成一个Query KeyQQuery Key包括条g查询的请求一般信息:SQL, SQL需要的参数Q记录范_起始位置rowStartQ最大记录个数maxRows)Q等?/p>
2) HibernateҎ(gu)q个Query Key到Query~存中查扑֯应的l果列表。如果存在,那么q回q个l果列表Q如果不存在Q查询数据库Q获取结果列表,把整个结果列表根据Query Key攑օ到Query~存中?/p>
3) Query Key中的SQL涉及C些表名,如果q些表的M数据发生修改、删除、增加等操作Q这些相关的Query Key都要从缓存中清空?/p>
U联保存和更?/font>
当Hibernate持久化一个时对象时Q在默认情下Q他不会自动持久化所兌的其他时对象,如果希望当持久化对象时把他所兌的所有时对象进行持久化的话Q可以把
?nbsp;all Q表CZQ何情况下都会q行U联操作Q即对一个对象进行操作,也会对和他关联的其他对象q行同样的操?br />?nbsp;delete Q表C在执行deleteӞq行U联操作Q删除和他关联的对象
?nbsp;none Q表CZQ何情况下Q都不会q行U联操作
<set>元素的inverse属?/font>
在运行上面的E序Ӟ如果hibernate?show-sql"讄为trueӞ׃看到Hibernate会生成很多sql语句Q其实很多sql语句都是重复?br />egQ?nbsp;
insert into test.order(o_name,c_id)values(?,?)
insert into test.order(o_name,c_id)values(?,?)
insert into test order set c_id=? where id=?
insert into test order set c_id=? where id=?
Z解决q个问题Q我们可以利用在<set>标签中加上inverse属性。术语:inverse是指反{的意思,?Hibernate中,表示兌关系中的方向兌关系中,inverse="false"的主控方Q由d方负责维护对象关pL?nbsp;在customer对象的对象配|文件中加上
<set name="orders" cascade="save-update" inverse="true">
<key column="c_id" > </key>
<one-to-many class="net.mbs.mypack.Order " />
</set>
声明在Customer和Order的双向关联关pMQCustomer端的兌只是Order端关联的镜象Q即Order端是ȝ端,负责l护 Customer和order对象之间的关联关p)Q当hibernate探测到持久化对象Customer或Order的状态发生变化时(主要是关联关pȝ改变),仅按照Order对象的状态的变化来同步更新数据库?br />按次配置Q如果在E序中,我们仅仅使用Customer.getOrder().add(order)Q涉及了和Order的关联关pȝ改变Q,是不能让数据库跟对象的变化来q行数据库同步更新的Q只有利用Order对象的方法改变的Order对象状?(egQorder.setCustomer(customer)----涉及C和Customer的关联关pȝ改变)Ӟ数据库才会根据变化来同步更新数据库,卛_有主控方的状态(涉及C和另一斚w的关联关pȝ改变Q发生了变化后,才会触发对象和数据库的同步更新?/p>
映射一对多双向兌关系
当类与类之间建立了关联,可以方便的从一个对象导航到另一个对象或一l与他关联的对象当中Q根据上面的E序Q对于一个给定的Order对象Q如果想获取与他兌的Customer对象Q我们只需要调用入下方法:
Customer c=order.geCustomer(); 那么当我们得C个Customer对象后,x出和q个Customer对象兌的所有Order对象Ӟ应该怎么办呢Q由于在Customer中没有徏立对Order对象的关联,所以,不能通过加蝲Customer对象来自动加载和他关联的所有Order对象Q唯一的方法只能通过JDBC或SQL语言人工写出代码来查询数据库Order表来q回所需要的信息
上面的问题虽然解冻I但不能算是最好,因ؓq样性能会有所下降Q对象位于内存中Q在内存中从一个对象导航到另一个对象显然比到数据库中查询数据要快得?br />
具体实现<br>
1Q由于Customer和Order是一对多Q即一个Customer要对应多个OrderQ所以在Customer中应该徏立一个Set对象Q用于存攑֒本Customer对象兌的所有Order对象?br />2Q在customer.hbm.xml通过<one-to-many>建立对Order表的兌关系
注意Q?lt;one-to-many>应该攄?lt;set>标签?nbsp;
我们先来看看Customercȝ设计和customer.hbm.xml文g的内?br /><br><br><br>------------------------------------------------------
Customer Order 双向一对多
1QCustomercM建立一个容器对象,包含兌的所有Order对象
2QOrdercM建立一个Customer对象Q关联Customer
inverse="true"表示维护关联的权利交给引vHibernate语句的生?/p>
customer.getOrders().add(order);
customer.setName("dddddd");
inverse="true"Q设|此属性的一?---是被控方Q?br />当主控方修改对象之间的关联关pLQ让Hibernate生成sql语句
延迟加蝲Q?/p>
延迟加蝲机制是ؓ了避免一些无谓的性能开销而提出来的,所谓gq加载就是当在真正需要数据的时候,才真正执行数据加载操作。在Hibernate中提供了对实体对象的延迟加蝲以及寚w合的延迟加蝲Q另外在Hibernate3中还提供了对属性的延迟加蝲。下面我们就分别介绍q些U类的gq加载的l节?/p>
A、实体对象的延迟加蝲Q?/p>
如果惛_实体对象使用延迟加蝲Q必要在实体的映射配置文g中进行相应的配置Q如下所C:
<hibernate-mapping>
<class name=”com.neusoft.entity.User” table=”user” lazy=”true”>
……
</class>
</hibernate-mapping>
通过class的lazy属性设|ؓtrueQ来开启实体的延迟加蝲Ҏ(gu)。如果我们运行下面的代码Q?/p>
User user=(User)session.load(User.class,”1”);Q?Q?/p>
System.out.println(user.getName());Q?Q?/p>
当运行到(1)处时QHibernateq没有发起对数据的查询,如果我们此时通过一些调试工?比如JBuilder2005的Debug工具)Q观察此时user对象的内存快照,我们会惊奇的发现Q此时返回的可能是User$EnhancerByCGLIB$$bede8986cd的对象,而且其属性ؓ null,q是怎么回事Q还记得前面我曾讲过session.load()Ҏ(gu)Q会q回实体对象的代理类对象Q这里所q回的对象类型就是User对象的代理类对象。在Hibernate中通过使用CGLIB,来实现动态构造一个目标对象的代理cd象,q且在代理类对象中包含目标对象的所有属性和Ҏ(gu)Q而且所有属性均被赋gؓnull。通过调试器显C的内存快照Q我们可以看出此时真正的User对象Q是包含在代理对象的 CGLIB$CALBACK_0.target属性中Q当代码q行刎ͼ2Q处Ӟ此时调用user.getName()Ҏ(gu)Q这旉过CGLIB赋予的回调机Ӟ实际上调用CGLIB$CALBACK_0.getName()Ҏ(gu)Q当调用该方法时QHibernate会首先检?CGLIB$CALBACK_0.target属性是否ؓnullQ如果不为空Q则调用目标对象的getNameҎ(gu)Q如果ؓI,则会发v数据库查询,生成cMq样的SQL语句Qselect * from user where id=’1’;来查询数据,q构造目标对象,q且它赋值到CGLIB$CALBACK_0.target属性中?/p>
q样Q通过一个中间代理对象,Hibernate实现了实体的延迟加蝲Q只有当用户真正发v获得实体对象属性的动作Ӟ才真正会发v数据库查询操作。所以实体的延迟加蝲是用通过中间代理cd成的Q所以只有session.load()Ҏ(gu)才会利用实体延迟加蝲Q因为只有session.load()Ҏ(gu)才会q回实体cȝ代理cd象?/p>
B?nbsp; 集合cd的gq加载:
在Hibernate的gq加载机制中Q针寚w合类型的应用Q意义是最为重大的Q因有可能性能得到大幅度的提高Qؓ此Hibernateq行了大量的努力Q其中包括对JDK Collection的独立实玎ͼ我们在一对多兌中,定义的用来容U_联对象的Set集合Qƈ不是java.util.Setcd或其子类型,而是 net.sf.hibernate.collection.SetcdQ通过使用自定义集合类的实玎ͼHibernate实现了集合类型的延迟加蝲。ؓ了对集合cd使用延迟加蝲Q我们必d下配|我们的实体cȝ关于兌的部分:
<hibernate-mapping>
<class name=”com.neusoft.entity.User” table=”user”>
…..
<set name=”addresses” table=”address” lazy=”true” inverse=”true”>
<key column=”user_id”/>
<one-to-many class=”com.neusoft.entity.Arrderss”/>
</set>
</class>
</hibernate-mapping>
通过?lt;set>元素的lazy属性设|ؓtrue来开启集合类型的延迟加蝲Ҏ(gu)。我们看下面的代码:
User user=(User)session.load(User.class,”1”);
Collection addset=user.getAddresses(); (1)
Iterator it=addset.iterator(); (2)
while(it.hasNext()){
Address address=(Address)it.next();
System.out.println(address.getAddress());
}
当程序执行到(1)处时Q这时ƈ不会发v对关联数据的查询来加载关联数据,只有q行?2)处时Q真正的数据d操作才会开始,q时Hibernate会根据缓存中W合条g的数据烦引,来查扄合条件的实体对象?/p>
q里我们引入了一个全新的概念——数据索引Q下面我们首先将接一下什么是数据索引。在Hibernate中对集合cdq行~存Ӟ是分两部分进行缓存的Q首先缓存集合中所有实体的id列表Q然后缓存实体对象,q些实体对象的id列表Q就是所谓的数据索引。当查找数据索引Ӟ如果没有扑ֈ对应的数据烦引,q时׃一条select SQL的执行,获得W合条g的数据,q构造实体对象集合和数据索引Q然后返回实体对象的集合Qƈ且将实体对象和数据烦引纳入Hibernate的缓存之中。另一斚wQ如果找到对应的数据索引Q则从数据烦引中取出id列表Q然后根据id在缓存中查找对应的实体,如果扑ֈ׃~存中返回,如果没有扑ֈQ在发vselect SQL查询。在q里我们看出了另外一个问题,q个问题可能会对性能产生影响Q这是集合cd的缓存策略。如果我们如下配|集合类型:
<hibernate-mapping>
<class name=”com.neusoft.entity.User” table=”user”>
…..
<set name=”addresses” table=”address” lazy=”true” inverse=”true”>
<cache usage=”read-only”/>
<key column=”user_id”/>
<one-to-many class=”com.neusoft.entity.Arrderss”/>
</set>
</class>
</hibernate-mapping>
q里我们应用?lt;cache usage=”read-only”/>配置Q如果采用这U策略来配置集合cdQHibernate只会对数据索引q行~存Q而不会对集合中的实体对象q行~存。如上配|我们运行下面的代码Q?/p>
User user=(User)session.load(User.class,”1”);
Collection addset=user.getAddresses();
Iterator it=addset.iterator();
while(it.hasNext()){
Address address=(Address)it.next();
System.out.println(address.getAddress());
}
System.out.println(“Second query……”);
User user2=(User)session.load(User.class,”1”);
Collection it2=user2.getAddresses();
while(it2.hasNext()){
Address address2=(Address)it2.next();
System.out.println(address2.getAddress());
}
q行q段代码Q会得到cM下面的输出:
Select * from user where id=’1’;
Select * from address where user_id=’1’;
Tianjin
Dalian
Second query……
Select * from address where id=’1’;
Select * from address where id=’2’;
Tianjin
Dalian
我们看到Q当W二ơ执行查询时Q执行了两条对address表的查询操作Qؓ什么会q样Q这是因为当W一ơ加载实体后Q根据集合类型缓存策略的配置Q只寚w合数据烦引进行了~存Q而ƈ没有寚w合中的实体对象进行缓存,所以在W二ơ再ơ加载实体时QHibernate扑ֈ了对应实体的数据索引Q但是根据数据烦引,却无法在~存中找到对应的实体Q所以HibernateҎ(gu)扑ֈ的数据烦引发起了两条select SQL的查询操作,q里造成了对性能的浪费,怎样才能避免q种情况呢?我们必须寚w合类型中的实体也指定~存{略Q所以我们要如下寚w合类型进行配|:
<hibernate-mapping>
<class name=”com.neusoft.entity.User” table=”user”>
…..
<set name=”addresses” table=”address” lazy=”true” inverse=”true”>
<cache usage=”read-write”/>
<key column=”user_id”/>
<one-to-many class=”com.neusoft.entity.Arrderss”/>
</set>
</class>
</hibernate-mapping>
此时Hibernate会对集合cd中的实体也进行缓存,如果Ҏ(gu)q个配置再次q行上面的代码,会得到cM如下的输出:
Select * from user where id=’1’;
Select * from address where user_id=’1’;
Tianjin
Dalian
Second query……
Tianjin
Dalian
q时不会再有根据数据烦引进行查询的SQL语句Q因为此时可以直接从~存中获得集合类型中存放的实体对象?/p>
C?nbsp; 属性gq加载:
在Hibernate3中,引入了一U新的特?#8212;—属性的延迟加蝲Q这个机制又取高性能查询提供了有力的工具。在前面我们讲大数据对象dӞ?User对象中有一个resume字段Q该字段是一个java.sql.ClobcdQ包含了用户的简历信息,当我们加载该对象Ӟ我们不得不每一ơ都要加载这个字D,而不论我们是否真的需要它Q而且q种大数据对象的d本n会带来很大的性能开销。在Hibernate2中,我们只有通过我们前面讲过的面性能的粒度细分,来分解Userc,来解册个问题(请参照那一节的Q,但是在Hibernate3中,我们可以通过属性gq加载机Ӟ来我们获得只有当我们真正需要操作这个字D|Q才去读取这个字D|据的能力Qؓ此我们必d下配|我们的实体c:
<hibernate-mapping>
<class name=”com.neusoft.entity.User” table=”user”>
……
<property name=”resume” type=”java.sql.Clob” column=”resume” lazy=”true”/>
</class>
</hibernate-mapping>
通过?lt;property>元素的lazy属性设|true来开启属性的延迟加蝲Q在Hibernate3中ؓ了实现属性的延迟加蝲Q用了cd强器来对实体cȝClass文gq行强化处理Q通过增强器的增强Q将CGLIB的回调机刉辑Q加入实体类Q这里我们可以看出属性的延迟加蝲Q还是通过 CGLIB来实现的。CGLIB是Apache的一个开源工E,q个cd可以操纵javacȝ字节码,Ҏ(gu)字节码来动态构造符合要求的cd象。根据上面的配置我们q行下面的代码:
String sql=”from User user where user.name=’zx’ ”;
Query query=session.createQuery(sql); (1)
List list=query.list();
for(int i=0;i<list.size();i++){
User user=(User)list.get(i);
System.out.println(user.getName());
System.out.println(user.getResume()); (2)
}
当执行到(1)处时Q会生成cM如下的SQL语句Q?/p>
Select id,age,name from user where name=’zx’;
q时Hibernate会检索User实体中所有非延迟加蝲属性对应的字段数据Q当执行?2)处时Q会生成cM如下的SQL语句Q?/p>
Select resume from user where id=’1’;
q时会发起对resume字段数据真正的读取操作?/p>