??xml version="1.0" encoding="utf-8" standalone="yes"?>网络捕鱼游戏机http://www.oiklr.tw/alex/category/16525.html不求多得,只求一? about java,hibernate,spring,design,database,linux,etc. <br/><br/> 最q关心的内容关键?web快速开发方案,建模,workshop studio,Ajax zh-cnSun, 13 May 2007 10:31:01 GMTSun, 13 May 2007 10:31:01 GMT60单就是美 -- 化hibernate,化daohttp://www.oiklr.tw/alex/archive/2007/05/13/117118.htmlAlexAlexSun, 13 May 2007 08:41:00 GMThttp://www.oiklr.tw/alex/archive/2007/05/13/117118.htmlhttp://www.oiklr.tw/alex/comments/117118.htmlhttp://www.oiklr.tw/alex/archive/2007/05/13/117118.html#Feedback1http://www.oiklr.tw/alex/comments/commentRss/117118.htmlhttp://www.oiklr.tw/alex/services/trackbacks/117118.html阅读全文

Alex 2007-05-13 16:41 发表评论
]]>
[zt] Hibernate+Spring 对DAO的处理实?http://www.oiklr.tw/alex/archive/2007/01/25/95839.htmlAlexAlexThu, 25 Jan 2007 01:24:00 GMThttp://www.oiklr.tw/alex/archive/2007/01/25/95839.htmlhttp://www.oiklr.tw/alex/comments/95839.htmlhttp://www.oiklr.tw/alex/archive/2007/01/25/95839.html#Feedback0http://www.oiklr.tw/alex/comments/commentRss/95839.htmlhttp://www.oiklr.tw/alex/services/trackbacks/95839.html阅读全文

Alex 2007-01-25 09:24 发表评论
]]>
MiddleGen中配|hibernate的many to many属?/title><link>http://www.oiklr.tw/alex/archive/2006/12/07/86159.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Thu, 07 Dec 2006 12:26:00 GMT</pubDate><guid>http://www.oiklr.tw/alex/archive/2006/12/07/86159.html</guid><wfw:comment>http://www.oiklr.tw/alex/comments/86159.html</wfw:comment><comments>http://www.oiklr.tw/alex/archive/2006/12/07/86159.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.oiklr.tw/alex/comments/commentRss/86159.html</wfw:commentRss><trackback:ping>http://www.oiklr.tw/alex/services/trackbacks/86159.html</trackback:ping><description><![CDATA[key words: MiddleGen,hibernate,many to many,多对?br /><br />如果你有如下表结?br /><br />user(user_id,user_name)<br />role(role_id,role_name)<br /><br />user_role(id,user_id,role_id)<br /><br />那么默认MiddleGen生成的是两个一对多Q但我们更多的情冉|用many to many<br /><br />需要修改middlegen的build.xml文g<br /><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);"><</span><span style="color: rgb(128, 0, 0);">many2many</span><span style="color: rgb(0, 0, 255);">></span><span style="color: rgb(0, 0, 0);"><br />            </span><span style="color: rgb(0, 0, 255);"><</span><span style="color: rgb(128, 0, 0);">tablea </span><span style="color: rgb(255, 0, 0);">generate</span><span style="color: rgb(0, 0, 255);">="true"</span><span style="color: rgb(255, 0, 0);"> name</span><span style="color: rgb(0, 0, 255);">="user"</span><span style="color: rgb(0, 0, 255);">/></span><span style="color: rgb(0, 0, 0);"><br />            </span><span style="color: rgb(0, 0, 255);"><</span><span style="color: rgb(128, 0, 0);">jointable </span><span style="color: rgb(255, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">="user_role"</span><span style="color: rgb(255, 0, 0);"> generate</span><span style="color: rgb(0, 0, 255);">="false"</span><span style="color: rgb(0, 0, 255);">/></span><span style="color: rgb(0, 0, 0);"><br />            </span><span style="color: rgb(0, 0, 255);"><</span><span style="color: rgb(128, 0, 0);">tableb </span><span style="color: rgb(255, 0, 0);">generate</span><span style="color: rgb(0, 0, 255);">="true"</span><span style="color: rgb(255, 0, 0);"> name</span><span style="color: rgb(0, 0, 255);">="role"</span><span style="color: rgb(0, 0, 255);">/></span><span style="color: rgb(0, 0, 0);"><br />         </span><span style="color: rgb(0, 0, 255);"></</span><span style="color: rgb(128, 0, 0);">many2many</span><span style="color: rgb(0, 0, 255);">></span></div><br /><img src ="http://www.oiklr.tw/alex/aggbug/86159.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.oiklr.tw/alex/" target="_blank">Alex</a> 2006-12-07 20:26 <a href="http://www.oiklr.tw/alex/archive/2006/12/07/86159.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate的Fetchhttp://www.oiklr.tw/alex/archive/2006/12/01/84808.htmlAlexAlexFri, 01 Dec 2006 05:01:00 GMThttp://www.oiklr.tw/alex/archive/2006/12/01/84808.htmlhttp://www.oiklr.tw/alex/comments/84808.htmlhttp://www.oiklr.tw/alex/archive/2006/12/01/84808.html#Feedback2http://www.oiklr.tw/alex/comments/commentRss/84808.htmlhttp://www.oiklr.tw/alex/services/trackbacks/84808.html我想告诉各位的是Q掌握hibernate可能比你预期的难多了Q当你轻杄告诉我,hibernate很简单的时候该是你自己多反省了. Q只有一U情况例外,你是一个牛人)

好了Q一个引子废话那么多Q其实今天只是想先说一说hibernate里的Fetch的作?

大家都知道,在hibernate里ؓ了性能考虑Q引q了lazy的概念,q里我们以Parent和Child为模型来说明Q?br />
public class Parent implements Serializable {

    
/** identifier field */
    
private Long id;

    
/** persistent field */
    
private List childs;

    
//skip all getter/setter method

  
}  



public class Child implements Serializable {

    
/** identifier field */
    
private Long id;

    
/** persistent field */
    
private net.foxlog.model.Parent parent;

    //skip all getter/setter method

}

在我们查询Parent对象的时候,默认只有Parent的内容,q不包含childs的信息,如果在Parent.hbm.xml里设|lazy="false"的话才同时取出关联的所有childs内容.

问题是我既想要hibernate默认的性能又想要时的灉|性该怎么办?  q就是fetch的功能。我们可以把fetch与lazy="true"的关pȝ比ؓ事务当中的编E式事务与声明式事务,不太准确Q但是大概是q个意思?br />
d|fetch是在代码这一层给你一个主动抓取得Z.

Parent parent = (Parent)hibernateTemplate.execute(new HibernateCallback() {
            
public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Query q 
= session.createQuery(
                        
"from Parent as parent "+
                                
" left outer join fetch parent.childs " +
                                
" where parent.id = :id"
                );
                q.setParameter(
"id",new Long(15));
                
return (Parent)q.uniqueResult();
            }

        });

        Assert.assertTrue(parent.getChilds().size() 
> 0);


你可以在lazy="true"的情况下把fetchLQ就会报异常. 当然Q如果lazy="false"׃需要fetch?br />

有一个问?使用Fetch会有重复记录的现象发?我们可以理解为Fetch实际上不是ؓParent服务?而是为Child服务?所以直接取Parent会有不匹配的问题.



参考一下下面的q篇文章
Hibernate集合初始?/a>

======================================================================

update:以上有些l论错误Q实际上在hibernate3.2.1版本下测试,可以不出现重复记录,

public void testNPlusOne() throws Exception{
        List list 
= (List)hibernateTemplate.execute(new HibernateCallback() {
            
public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Query q 
= session.createQuery(
                        
"select distinct p from net.foxlog.model.Parent p inner join fetch p.childs"
                );
                
return q.list();
            }

        });

        
//((Parent)(list.get(0))).getChilds();
        System.out.println("list size = " + list.size());
        
for(int i=0;i<list.size();i++){
            Parent p 
= (Parent)list.get(i);
            System.out.println(
"===parent = " + p);
            System.out.println(
"===parent's child's length = " + p.getChilds().size());
        }

    }


打印l果如下:
Hibernate: select distinct parent0_.id as id2_0_, childs1_.id as id0_1_, childs1_.parent_id as parent2_0_1_, childs1_.parent_id as parent2_0__, childs1_.id as id0__ from parent parent0_ inner join child childs1_ on parent0_.id=childs1_.parent_id
list size 
= 3
===parent = net.foxlog.model.Parent@1401d28[id=14]
===parent's child's length = 1
===parent = net.foxlog.model.Parent@14e0e90[id=15]
===parent's child's length = 2
===parent = net.foxlog.model.Parent@62610b[id=17]
===parent's child's length = 3

另外Q如果用open session in view模式的话一般不用fetch,但首先推荐fetch,如果非用的话因ؓ有N+1的现象,所以可以结合batch模式来改善下性能.




Alex 2006-12-01 13:01 发表评论
]]>
[zt]hibernate复合主键http://www.oiklr.tw/alex/archive/2006/11/09/80231.htmlAlexAlexThu, 09 Nov 2006 11:22:00 GMThttp://www.oiklr.tw/alex/archive/2006/11/09/80231.htmlhttp://www.oiklr.tw/alex/comments/80231.htmlhttp://www.oiklr.tw/alex/archive/2006/11/09/80231.html#Feedback0http://www.oiklr.tw/alex/comments/commentRss/80231.htmlhttp://www.oiklr.tw/alex/services/trackbacks/80231.html


Z业务需求,您会需要用两个字D|作复合主键,例如?span lang="EN-US">User数据表中Q您也许会?span lang="EN-US">"name"?span lang="EN-US">"phone"两个字段来定义复合主键?span lang="EN-US">

假设您这么徏?span lang="EN-US">User表格Q?span lang="EN-US">

CREATE TABLE user (

    name 
VARCHAR(100NOT NULL,

    phone 
VARCHAR(50NOT NULL,

    age 
INT,

    
PRIMARY KEY(name, phone)

);

在表gQ?span lang="EN-US">"name"?span lang="EN-US">"age"被定义ؓ复合主键Q在映像Ӟ您可以让Usercd直接带有"name"?span lang="EN-US">"age"q两个属性,?span lang="EN-US">Hibernate要求复合主键cd要实?span lang="EN-US">Serializable接口Qƈ定义equals()?span lang="EN-US">hashCode()ҎQ?span lang="EN-US">

User.java

package onlyfun.caterpillar;

 

import java.io.Serializable;

import org.apache.commons.lang.builder.EqualsBuilder;

import org.apache.commons.lang.builder.HashCodeBuilder;

 

// 复合主键cȝ对应cd必须实作Serializable接口

public class User implements Serializable {

    
private String name;

    
private String phone;

    
private Integer age;

   

    
public User() {

    }

 

    
public Integer getAge() {

        
return age;

    }

 

    
public void setAge(Integer age) {

        
this.age = age;

    }

 

    
public String getName() {

        
return name;

    }

 

    
public void setName(String name) {

        
this.name = name;

    }

 

    
public String getPhone() {

        
return phone;

    }

 

    
public void setPhone(String phone) {

        
this.phone = phone;

    }

   

    
// 必须重新定义equals()与hashCode()

    
public boolean equals(Object obj) {

        
if(obj == this) {

            
return true;

        }

       

        
if(!(obj instanceof User)) {

            
return false;

        }

       

        User user 
= (User) obj;

        
return new EqualsBuilder()

                 .append(
this.name, user.getName())

                 .append(
this.phone, user.getPhone())

                 .isEquals();

       

    }

   

    
public int hashCode() {

        
return new HashCodeBuilder()

                 .append(
this.name)

                 .append(
this.phone)

                 .toHashCode();

    }

}

equals()?span lang="EN-US">hashCode()Ҏ被用作两W不同数据的识别依据Q接着您可以?span lang="EN-US"><composite-id>在映文件中定义复合主键与对象的属性对应:

User.hbm.xml

<?xml version="1.0" encoding="utf-8"?>

<!DOCTYPE hibernate-mapping

    PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"
>

 

<hibernate-mapping>

 

    
<class name="onlyfun.caterpillar.User" table="user">

        
<composite-id>

            
<key-property name="name"

                          column
="name"

                          type
="java.lang.String"/>

            
<key-property name="phone"

                          column
="phone"

                          type
="java.lang.String"/>

        
</composite-id>

 

        
<property name="age" column="age" type="java.lang.Integer"/>

   

    
</class>

</hibernate-mapping>

在储存数据方面,复合主键的储存没什么区别,现在的问题在于如何依据复合主键来查询数据Q例如?span lang="EN-US">load()ҎQ您可以创徏一?span lang="EN-US">User实例Qƈ讑֮复合主键对应的属性,接着再透过load()查询对应的数据,例如Q?span lang="EN-US">

User user = new User();

user.setName(
"bush");

user.setPhone(
"0970123456");

       

Session session 
= sessionFactory.openSession();

// 以实例设定复合主键ƈ加蝲对应的数?/span>

user 
= (User) session.load(User.class, user);

       

System.out.println(user.getAge() 
+ "\t" +

                                  user.getName() 
+ "\t" +

                                  user.getPhone());

session.close();

 

 

可以主键的信息独立Z个类别,例如Q?span lang="EN-US">

UserPK.java

package onlyfun.caterpillar;

 

import java.io.Serializable;

 

import org.apache.commons.lang.builder.EqualsBuilder;

import org.apache.commons.lang.builder.HashCodeBuilder;

 

public class UserPK implements Serializable {

    
private String name;

    
private String phone;

 

    
public String getName() {

        
return name;

    }

 

    
public void setName(String name) {

        
this.name = name;

    }

 

    
public String getPhone() {

        
return phone;

    }

 

    
public void setPhone(String phone) {

        
this.phone = phone;

    }

   

    
public boolean equals(Object obj) {

        
if(obj == this) {

            
return true;

        }

       

        
if(!(obj instanceof User)) {

            
return false;

        }

       

        UserPK pk 
= (UserPK) obj;

        
return new EqualsBuilder()

                 .append(
this.name, pk.getName())

                 .append(
this.phone, pk.getPhone())

                 .isEquals();

       

    }

   

    
public int hashCode() {

        
return new HashCodeBuilder()

                 .append(
this.name)

                 .append(
this.phone)

                 .toHashCode();

    }

}

现在Usercd的主键信息被分离出来了,例如Q?span lang="EN-US">

User.java

package onlyfun.caterpillar;

 

import java.io.Serializable;

 

public class User implements Serializable {

    
private UserPK userPK; // 主键

    
private Integer age;

   

    
public User() {

    }

 

    
public UserPK getUserPK() {

        
return userPK;

    }

 

    
public void setUserPK(UserPK userPK) {

        
this.userPK = userPK;

    }

 

    
public Integer getAge() {

        
return age;

    }

 

    
public void setAge(Integer age) {

        
this.age = age;

    }

}

在映像文件方面,需要指定主键类的信息,例如Q?span lang="EN-US">

User.hbm.xml

<?xml version="1.0" encoding="utf-8"?>

<!DOCTYPE hibernate-mapping

    PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"
>

 

<hibernate-mapping>

 

    
<class name="onlyfun.caterpillar.User" table="user">

        
<composite-id name="userPK"

                      class
="onlyfun.caterpillar.UserPK"

                      unsaved-value
="any">

            
<key-property name="name"

                          column
="name"

                          type
="java.lang.String"/>

            
<key-property name="phone"

                          column
="phone"

                          type
="java.lang.String"/>

        
</composite-id>

       

        
<property name="age" column="age" type="java.lang.Integer"/>

   

    
</class>

 

</hibernate-mapping>

在查询数据时Q必L定主键信息,例如Q?span lang="EN-US">

UserPK pk = new UserPK();

pk.setName(
"bush");

pk.setPhone(
"0970123456");

      

Session session 
= sessionFactory.openSession();

// 以主键类实例讑֮复合主键q加载对应的数据

User user 
= (User) session.load(User.class, pk);

      

System.out.println(user.getAge() 
+ "\t" +

                                  user.getUserPK().getName() 
+ "\t" +

                                  user.getUserPK().getPhone());

session.close();

 


=================================================
再参考robbin的一文?br />一个简单的复合主键的做兌cȝ例子  


Alex 2006-11-09 19:22 发表评论
]]>
Hibernate的load错误Q你到q这L问题?http://www.oiklr.tw/alex/archive/2006/11/07/79675.htmlAlexAlexTue, 07 Nov 2006 11:28:00 GMThttp://www.oiklr.tw/alex/archive/2006/11/07/79675.htmlhttp://www.oiklr.tw/alex/comments/79675.htmlhttp://www.oiklr.tw/alex/archive/2006/11/07/79675.html#Feedback3http://www.oiklr.tw/alex/comments/commentRss/79675.htmlhttp://www.oiklr.tw/alex/services/trackbacks/79675.html
public class Parent implements Serializable {

    
/** identifier field */
    
private Long id;

    
/** persistent field */
    
private List childs;

    
/** full constructor */
    
public Parent(Long id, List childs) {
        
this.id = id;
        
this.childs = childs;
    }

    
/** default constructor */
    
public Parent() {
    }

    
/** 
     *            @hibernate.id
     *             generator-class="assigned"
     *             type="java.lang.Long"
     *             column="id"
     *
     
*/
    
public Long getId() {
        
return this.id;
    }

    
public void setId(Long id) {
        
this.id = id;
    }

    
/**
     *            @hibernate.set
     *             lazy="true"
     *             inverse="true"
     *             cascade="none"
     *            @hibernate.collection-key
     *             column="parent_id"
     *            @hibernate.collection-one-to-many
     *             class="net.foxlog.model.Child"
     *         
     
*/
    
public List getChilds() {
        
return this.childs;
    }

    
public void setChilds(List childs) {
        
this.childs = childs;
    }

    
public String toString() {
        
return new ToStringBuilder(this)
            .append(
"id", getId())
            .toString();
    }

    
public boolean equals(Object other) {
        
if ( !(other instanceof Parent) ) return false;
        Parent castOther 
= (Parent) other;
        
return new EqualsBuilder()
            .append(
this.getId(), castOther.getId())
            .isEquals();
    }

    
public int hashCode() {
        
return new HashCodeBuilder()
            .append(getId())
            .toHashCode();
    }

}


Parent parent = (Parent)session.load(Parent.class,new Integer(7));

q行提示出错Q?can't get Entity.."

知道是什么低U错误么?  其实很弱智的东西Q但是不注意q就会出玎ͼ呵呵Q答案如?




Alex 2006-11-07 19:28 发表评论
]]>
[zt]hibernate二~存ȝhttp://www.oiklr.tw/alex/archive/2006/10/23/76750.htmlAlexAlexMon, 23 Oct 2006 06:30:00 GMThttp://www.oiklr.tw/alex/archive/2006/10/23/76750.htmlhttp://www.oiklr.tw/alex/comments/76750.htmlhttp://www.oiklr.tw/alex/archive/2006/10/23/76750.html#Feedback1http://www.oiklr.tw/alex/comments/commentRss/76750.htmlhttp://www.oiklr.tw/alex/services/trackbacks/76750.htmljavaEye


很多人对二~存都不太了解,或者是有错误的认识Q我一直想写一文章介l一下hibernate的二U缓存的Q今天终于忍不住了?
我的l验主要来自hibernate2.1版本Q基本原理和3.0?.1是一LQ请原谅我的固不化?/p>

hibernate的session提供了一U缓存,每个sessionQ对同一个idq行两次loadQ不会发送两条sqll数据库Q但是session关闭的时候,一U缓存就失效了?/p>

二~存是SessionFactoryU别的全局~存Q它底下可以使用不同的缓存类库,比如ehcache、oscache{,需要设|hibernate.cache.provider_classQ我们这里用ehcacheQ在2.1中就?
hibernate.cache.provider_class=net.sf.hibernate.cache.EhCacheProvider
如果使用查询~存Q加?
hibernate.cache.use_query_cache=true

~存可以单的看成一个MapQ通过key在缓存里面找value?/p>

Class的缓?/b>
对于一条记录,也就是一个PO来说Q是ҎID来找的,~存的key是IDQvalue是POJO。无论listQloadq是 iterateQ只要读Z个对象,都会填充~存。但是list不会使用~存Q而iterate会先取数据库select id出来Q然后一个id一个id的loadQ如果在~存里面有,׃~存取,没有的话去数据库load。假设是d~存Q需要设|:
<cache usage="read-write"/>
如果你用的二~存实现是ehcache的话Q需要配|ehcache.xml
<cache name="com.xxx.pojo.Foo" maxElementsInMemory="500" eternal="false" timeToLiveSeconds="7200" timeToIdleSeconds="3600" overflowToDisk="true" />
其中eternal表示~存是不是永q不时QtimeToLiveSeconds是缓存中每个元素Q这里也是一个POJOQ的时旉Q如 果eternal="false"Q超q指定的旉Q这个元素就被移C。timeToIdleSeconds是发呆时_是可选的。当往~存里面put 的元素超q?00个时Q如果overflowToDisk="true"Q就会把~存中的部分数据保存在硬盘上的时文仉面?
每个需要缓存的class都要q样配置。如果你没有配置Qhibernate会在启动的时候警告你Q然后用defaultCache的配|,q样多个class会共享一个配|?
当某个ID通过hibernate修改Ӟhibernate会知道,于是U除~存?
q样大家可能会想Q同L查询条gQ第一ơ先listQ第二次再iterateQ就可以使用到缓存了。实际上q是很难的,因ؓ你无法判断什么时? 是第一ơ,而且每次查询的条仉常是不一LQ假如数据库里面?00条记录,id??00Q第一ơlist的时候出了前50个idQ第二次 iterate的时候却查询?0?0号idQ那?0-50是从~存里面取的Q?1?0是从数据库取的,共发?+20条sql。所以我一直认? iterate没有什么用QL会有1+N的问题?
Q题外话Q有说法说大型查询用list会把整个l果集装入内存,很慢Q而iterate只select id比较好,但是大型查询L要分|的,谁也不会真的把整个结果集装进来,假如一?0条的话,iterate共需要执?1条语句,list虽然选择 若干字段Q比iterateW一条select id语句慢一些,但只有一条语句,不装入整个结果集hibernateq会Ҏ数据库方a做优化,比如使用mysql的limitQ整体看来应该还? list快。)
如果惌对list或者iterate查询的结果缓存,p用到查询~存?/p>

查询~存
首先需要配|hibernate.cache.use_query_cache=true
如果用ehcacheQ配|ehcache.xmlQ注意hibernate3.0以后不是net.sf的包名了
<cache name="net.sf.hibernate.cache.StandardQueryCache"
maxElementsInMemory="50" eternal="false" timeToIdleSeconds="3600"
timeToLiveSeconds="7200" overflowToDisk="true"/>
<cache name="net.sf.hibernate.cache.UpdateTimestampsCache"
maxElementsInMemory="5000" eternal="true" overflowToDisk="true"/>
然后
query.setCacheable(true);//ȀzL询缓?
query.setCacheRegion("myCacheRegion");//指定要用的cacheRegionQ可?
W二行指定要使用的cacheRegion是myCacheRegionQ即你可以给每个查询~存做一个单独的配置Q用setCacheRegion来做q个指定Q需要在ehcache.xml里面配置它:
<cache name="myCacheRegion" maxElementsInMemory="10" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="7200" overflowToDisk="true" />
如果省略W二行,不设|cacheRegion的话Q那么会使用上面提到的标准查询缓存的配置Q也是net.sf.hibernate.cache.StandardQueryCache

对于查询~存来说Q缓存的key是根据hql生成的sqlQ再加上参数Q分늭信息Q可以通过日志输出看到Q不q它的输Z是很可读Q最好改一下它的代码)?
比如hqlQ?
from Cat c where c.name like ?
生成大致如下的sqlQ?
select * from cat c where c.name like ?
参数?tiger%"Q那么查询缓存的key*大约*是这L字符Ԍ我是凭记忆写的,q不_Q不q看了也该明白了Q:
select * from cat c where c.name like ? , parameter:tiger%
q样Q保证了同样的查询、同L参数{条件下h一Lkey?
现在说说~存的valueQ如果是list方式的话Qvalue在这里ƈ不是整个l果集,而是查询出来的这一串ID。也是_不管是list? 法还是iterateҎQ第一ơ查询的时候,它们的查询方式很它们qx的方式是一LQlist执行一条sqlQiterate执行1+N条,多出来的 行ؓ是它们填充了~存。但是到同样条gW二ơ查询的时候,都和iterate的行Z样了Q根据缓存的keyȝ存里面查CvalueQvalue? 一串idQ然后在到class的缓存里面去一个一个的load出来。这样做是ؓ了节U内存?
可以看出来,查询~存需要打开相关cȝclass~存。list和iterateҎW一ơ执行的时候,都是既填充查询缓存又填充class~存的?
q里q有一个很Ҏ被忽视的重要问题Q即打开查询~存以后Q即使是listҎ也可能遇?+N的问题!相同条gW一ơlist? 时候,因ؓ查询~存中找不到Q不class~存是否存在数据QL发送一条sql语句到数据库获取全部数据Q然后填充查询缓存和class~存。但是第 二次执行的时候,问题来了,如果你的class~存的超时时间比较短Q现在class~存都超时了Q但是查询缓存还在,那么listҎ在获取id串以 后,会一个一个去数据库loadQ因此,class~存的超时时间一定不能短于查询缓存设|的时旉Q如果还讄了发呆时间的话,保证class~存 的发呆时间也大于查询的缓存的生存旉。这里还有其他情况,比如class~存被程序强制evict了,q种情况p自己注意了?/p>

另外Q如果hql查询包含select字句Q那么查询缓存里面的value是整个l果集了?/p>

当hibernate更新数据库的时候,它怎么知道更新哪些查询~存呢?
hibernate在一个地方维护每个表的最后更新时_其实也就是放在上面net.sf.hibernate.cache.UpdateTimestampsCache所指定的缓存配|里面?
当通过hibernate更新的时候,hibernate会知道这ơ更新媄响了哪些表。然后它更新q些表的最后更新时间。每个缓存都有一个生成时 间和q个~存所查询的表Q当hibernate查询一个缓存是否存在的时候,如果~存存在Q它q要取出~存的生成时间和q个~存所查询的表Q然后去查找q? 些表的最后更新时_如果有一个表在生成时间后更新q了Q那么这个缓存是无效的?
可以看出Q只要更新过一个表Q那么凡是涉及到q个表的查询~存失效了Q因此查询缓存的命中率可能会比较低?/p>

Collection~存
需要在hbm的collection里面讄
<cache usage="read-write"/>
假如class是CatQcollection叫childrenQ那么ehcache里面配置
<cache name="com.xxx.pojo.Cat.children"
maxElementsInMemory="20" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="7200"
overflowToDisk="true" />
Collection的缓存和前面查询~存的list一P也是只保持一串idQ但它不会因个表更新q就失效Q一个collection~存仅在q个collection里面的元素有增删时才失效?
q样有一个问题,如果你的collection是根据某个字D|序的Q当其中一个元素更C该字D|Q导致顺序改变时Qcollection~存里面的顺序没有做更新?/p>

~存{略
只读~存Qread-onlyQ:没有什么好说的
?写缓存(read-writeQ?E序可能要的更新数据
不严格的?写缓存(nonstrict-read-writeQ:需要更新数据,但是两个事务更新同一条记录的可能性很,性能比读写缓存好
事务~存QtransactionalQ:~存支持事务Q发生异常的时候,~存也能够回滚,只支持jta环境Q这个我没有怎么研究q?/p>

d~存和不严格d~存在实C的区别在于,d~存更新~存的时候会把缓存里面的数据换成一个锁Q其他事务如果去取相应的~存数据Q发现被锁住了,然后q接取数据库查询?
在hibernate2.1的ehcache实现中,如果锁住部分~存的事务发生了异常Q那么缓存会一直被锁住Q直?0U后时?
不严D写缓存不锁定~存中的数据?/p>

使用二~存的前|条?/b>
你的hibernateE序Ҏ据库有独占的写访问权Q其他的q程更新了数据库Qhibernate是不可能知道的。你操作数据库必需直接通过 hibernateQ如果你调用存储q程Q或者自׃用jdbc更新数据库,hibernate也是不知道的。hibernate3.0的大扚w更新和删 除是不更CU缓存的Q但是据?.1已经解决了这个问题?
q个限制相当的棘手,有时候hibernate做批量更新、删除很慢,但是你却不能自己写jdbc来优化,很郁闷吧?
SessionFactory也提供了U除~存的方法,你一定要自己写一些JDBC的话Q可以调用这些方法移除缓存,q些Ҏ是:
void evict(Class persistentClass)
Evict all entries from the second-level cache.
void evict(Class persistentClass, Serializable id)
Evict an entry from the second-level cache.
void evictCollection(String roleName)
Evict all entries from the second-level cache.
void evictCollection(String roleName, Serializable id)
Evict an entry from the second-level cache.
void evictQueries()
Evict any query result sets cached in the default query cache region.
void evictQueries(String cacheRegion)
Evict any query result sets cached in the named query cache region.
不过我不q样做,因ؓq样很难l护。比如你现在用JDBC扚w更新了某个表Q有3个查询缓存会用到q个表,用evictQueries (String cacheRegion)U除?个查询缓存,然后用evict(Class persistentClass)U除了class~存Q看上去好像完整了。不q哪天你d了一个相x询缓存,可能会忘记更新这里的U除代码。如果你? jdbc代码到处都是Q在你添加一个查询缓存的时候,q知道其他什么地方也要做相应的改动吗Q?/p>

----------------------------------------------------

ȝQ?/b>
不要惛_然的以ؓ~存一定能提高性能Q仅仅在你能够驾驭它q且条g合适的情况下才是这L。hibernate的二U缓存限制还是比较多的,不方便用jdbc可能会大大的降低更新性能。在不了解原理的情况下ؕ用,可能会有1+N的问题。不当的使用q可能导致读数据?
如果受不了hibernate的诸多限Ӟ那么q是自己在应用程序的层面上做~存吧?
在越高的层面上做~存Q效果就会越好。就好像管盘有缓存,数据库还是要实现自己的缓存,管数据库有~存Q咱们的应用E序q是要做~存。因? 底层的缓存它q不知道高层要用q些数据q什么,只能做的比较通用Q而高层可以有针对性的实现~存Q所以在更高的别上做缓存,效果也要好些吧?/p>

l于写完了,好篏…?/p>

Alex 2006-10-23 14:30 发表评论
]]>
2013粶Ϸ ѡ178 īڿ׬Ǯƽ̨ ڲƱƽ̨ץסм ȷֱ500Ʊ 컶Фͼ 99ʰ׿ ֿͼ ǿϷ ɷ йƱн 3 pk10ţţ淨 ʷ ʮһ˶©246810