??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲精品无码永久在线观看你懂的,亚洲色图校园春色,日韩亚洲综合精品国产http://m.tkk7.com/lanxin1020/category/38968.htmlzh-cnMon, 25 May 2009 09:50:55 GMTMon, 25 May 2009 09:50:55 GMT60hibernate 自定义数据类型映(转)http://m.tkk7.com/lanxin1020/archive/2009/05/24/277716.htmllanxin1020lanxin1020Sun, 24 May 2009 11:57:00 GMThttp://m.tkk7.com/lanxin1020/archive/2009/05/24/277716.htmlhttp://m.tkk7.com/lanxin1020/comments/277716.htmlhttp://m.tkk7.com/lanxin1020/archive/2009/05/24/277716.html#Feedback0http://m.tkk7.com/lanxin1020/comments/commentRss/277716.htmlhttp://m.tkk7.com/lanxin1020/services/trackbacks/277716.htmlHibernate中提供的用户cd自定义接口。根据这个接口,可以实现自定义的数据cd?nbsp;

最q看<<深入出Hibernate>>,作者在书中介绍?span class="hilite1">Hibernate 提供的用戯定义数据cdQ于是效仿书中的ҎQ在数据库表中添加一个字D는于记录所有好友的useridQ每个userid之间?;"加以分隔Q同时将该字D|ؓ一个特D的List集合Q利用UserType interface实现String解析后将各个userid装在List中,List中的记录装成以";"分隔的String?
使用UserType接口Q实C较好的设计风|以及更好的重用性?
/*
* 用户自定义的数据cdQ对应数据库中的一个字D,在该字段中,保存?
* 多个用户需要的信息Q之间用";"加以分隔.
* @Author:Paul
* @Date:April 18th,2008
*/
package com.globalhands.hibernate.userTypes;

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.sql.Types;

import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;

public class SpecialList implements UserType {
private List specialList;

private static final char SPLITTER = ';';

private static final int[] TYPES = new int[] { Types.VARCHAR };

public String assemble(Serializable arg0, Object arg1)
throws HibernateException {
return null;
}

/*
* List装Z个String对象
*/
public String assemble(List specialList) throws HibernateException {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < specialList.size() - 1; i++) {
sb.append(specialList.get(i)).append(this.SPLITTER);
}
sb.append(specialList.get(specialList.size() - 1));
return sb.toString();
}

/*
* 创徏一个新的List实例Q包含原有的List实例中的所有元?
*/
public Object deepCopy(Object value) throws HibernateException {
List sourceList = (List) value;
List targetList = new ArrayList();
targetList.addAll(sourceList);
return targetList;
}

public Serializable disassemble(Object arg0) throws HibernateException {
return null;
}

/*
* 判断specialList是否发生变化
*/
public boolean equals(Object x, Object y) throws HibernateException {
if (x == y) {
return true;
}
if (x != null && y != null) {
List xList = (List) x;
List yList = (List) y;

if (xList.size() != yList.size()) {
return false;
}

for (int i = 0; i <= xList.size() - 1; i++) {
String str1 = (String) xList.get(i);
String str2 = (String) yList.get(i);
if (!xList.equals(yList)) {
return false;
}
}
return true;
}
return false;
}

public int hashCode(Object arg0) throws HibernateException {
return 0;
}

public boolean isMutable() {
return false;
}

/*
* 从resultset中取出email字段Qƈ其解析为Listcd后返?
*/
public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
throws HibernateException, SQLException {
String value = (String) Hibernate.STRING.nullSafeGet(rs, names[0]);
if (value != null) {
return parse(value);
} else {
return null;
}
}

/*
* 以";"分隔的字W串解析Z个字W串数组
*/
private List parse(String value) {
String[] strs = value.split(";");
List specialList = new ArrayList();
for (int i = 0; i <= strs.length - 1; i++) {
specialList.add(strs[i]);
}
return specialList;
}

/*
* List型的email信息l装成字W串之后保存到email字段
*/
public void nullSafeSet(PreparedStatement st, Object value, int index)
throws HibernateException, SQLException {
if (value != null) {
String str = assemble((List) value);
Hibernate.STRING.nullSafeSet(st, str, index);
} else {
Hibernate.STRING.nullSafeSet(st, value, index);
}
}

public Object replace(Object arg0, Object arg1, Object arg2)
throws HibernateException {
return null;
}

public Class returnedClass() {
return List.class;
}

public int[] sqlTypes() {
return TYPES;
}

}
同时Q修改相应的[ormapping_filename].hbm.xml中相应字D늚映射信息
<property name="buddy" type="com.globalhands.hibernate.userTypes.SpecialList">
            <column name="buddy" length="2000" not-null="true" />
        </property>
之后Q修改POJOcM该字D늚q回cd为List?
使用JUnit试E序?


lanxin1020 2009-05-24 19:57 发表评论
]]>
Hibernate悲观锁和乐观??http://m.tkk7.com/lanxin1020/archive/2009/04/12/265131.htmllanxin1020lanxin1020Sun, 12 Apr 2009 08:12:00 GMThttp://m.tkk7.com/lanxin1020/archive/2009/04/12/265131.htmlhttp://m.tkk7.com/lanxin1020/comments/265131.htmlhttp://m.tkk7.com/lanxin1020/archive/2009/04/12/265131.html#Feedback0http://m.tkk7.com/lanxin1020/comments/commentRss/265131.htmlhttp://m.tkk7.com/lanxin1020/services/trackbacks/265131.html
Q{Q?span class="hilite1">Hibernate支持两种锁机Ӟ
即通常所说的“悲观锁(Pessimistic LockingQ?#8221;?
“乐观锁(OptimisticLockingQ?#8221;?
悲观锁的实现Q往往依靠数据库提供的锁机Ӟ也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则Q即使在本系l中实现了加锁机Ӟ也无法保证外部系l不会修Ҏ据)?
Hibernate的加锁模式有Q?
Ø LockMode.NONE Q?无锁机制?
Ø LockMode.WRITE Q?span class="hilite1">Hibernate在Insert和Update记录的时候会自动
获取?
Ø LockMode.READ Q?Hibernate在读取记录的时候会自动获取?
以上q三U锁机制一般由Hibernate内部使用Q如HibernateZ保证Update
q程中对象不会被外界修改Q会在saveҎ实现中自动ؓ目标对象加上WRITE锁?
Ø LockMode.UPGRADE Q利用数据库的for update子句加锁?
Ø LockMode. UPGRADE_NOWAIT QOracle的特定实玎ͼ利用Oracle的for
update nowait子句实现加锁?
乐观锁,大多是基于数据版本(VersionQ记录机制实现。何谓数据版本?即ؓ数据增加一个版本标识,在基于数据库表的版本解决Ҏ中,一般是通过为数据库表增加一?#8220;version”字段来实现。读取出数据Ӟ此版本号一同读出,之后更新ӞҎ版本号加一。此Ӟ提交数据的版本数据与数据库表对应记录的当前版本信息q行比对Q如果提交的数据版本号大于数据库表当前版本号Q则予以更新Q否则认为是q期数据?
悲观锁与乐观锁的比较:
悲观锁大多数情况下依靠数据库的锁机制实现Q以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销Q特别是寚w事务而言Q这L开销往往无法承受;
相对悲观锁而言Q乐观锁机制采取了更加宽杄加锁机制。乐观锁机制往往Zpȝ中的数据存储逻辑Q因此也具备一定的局限性,如在上例中,׃乐观锁机制是在我们的pȝ中实玎ͼ来自外部pȝ的更新操作不受我们系l的控制Q因此可能会造成脏数据被更新到数据库中。在
pȝ设计阶段Q我们应该充分考虑到这些情况出现的可能性,q进行相应调_如将乐观锁策略在数据库存储过E中实现Q对外只开攑֟于此存储q程的数据更新途径Q而不是将数据库表直接对外公开Q?
Hibernate 在其数据讉K引擎中内|了乐观锁实现。如果不用考虑外部pȝҎ据库的更新操作,利用Hibernate提供的透明化乐观锁实现Q将大大提升我们的生产力?
Hibernate中可以通过class描述W的optimistic-lock属性结合version描述W指定?
optimistic-lock属性有如下可选取|
Ø none
无乐观锁
Ø version
通过版本机制实现乐观?
Ø dirty
通过查发生变动过的属性实C观锁
Ø all
通过查所有属性实C观锁
其中通过version实现的乐观锁机制?span class="hilite1">Hibernate官方推荐的乐观锁实现Q同时也?span class="hilite1">Hibernate中,目前唯一在数据对象脱?Session发生修改的情况下依然有效的锁机制。因此,一般情况下Q我们都选择version方式作ؓHibernate乐观锁实现机制?


lanxin1020 2009-04-12 16:12 发表评论
]]>
使用 SchemaExport 自动 http://m.tkk7.com/lanxin1020/archive/2009/04/11/265021.htmllanxin1020lanxin1020Sat, 11 Apr 2009 08:31:00 GMThttp://m.tkk7.com/lanxin1020/archive/2009/04/11/265021.htmlhttp://m.tkk7.com/lanxin1020/comments/265021.htmlhttp://m.tkk7.com/lanxin1020/archive/2009/04/11/265021.html#Feedback0http://m.tkk7.com/lanxin1020/comments/commentRss/265021.htmlhttp://m.tkk7.com/lanxin1020/services/trackbacks/265021.html使用 SchemaExport 自动

使用Hibernate自带的工?em>hbm2ddlQ徏立根据你的对象徏立数据库:

首先建好POJO object, XML Mapping File(也可以用工h据POJO class建立)Q配|文?hibernate.cfg.xml)

Java代码


import org.hibernate.cfg.Configuration;
import org.hibernate.tool.hbm2ddl.SchemaExport;

public class SchemaUtil {
public static void main(String[] args) {

Configuration cfg = new Configuration().configure(); SchemaExport schemaExport= new SchemaExport(cfg); schemaExport.create(false, true); } }


lanxin1020 2009-04-11 16:31 发表评论
]]>
SchemaExportTask(转自 良葛?http://m.tkk7.com/lanxin1020/archive/2009/04/11/265001.htmllanxin1020lanxin1020Sat, 11 Apr 2009 03:37:00 GMThttp://m.tkk7.com/lanxin1020/archive/2009/04/11/265001.htmlhttp://m.tkk7.com/lanxin1020/comments/265001.htmlhttp://m.tkk7.com/lanxin1020/archive/2009/04/11/265001.html#Feedback0http://m.tkk7.com/lanxin1020/comments/commentRss/265001.htmlhttp://m.tkk7.com/lanxin1020/services/trackbacks/265001.html在您撰寫?.hbm.xml映射文g之後Q您可以使用 net.sf.hibernate.tool.hbm2ddl.SchemaExportTask來自動徏立資料n表格Q這邊所使用的方式是i合Ant進行自動化徏構,首先我們假a將使用以下的User.hbm.xmlQ?

User.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

<hibernate-mapping>
<class name="onlyfun.caterpillar.User" table="USER">
<id name="id" type="string" unsaved-value="null">
<column name="user_id" sql-type="char(32)"/>
<generator class="uuid.hex"/>
</id>
<property name="name" type="string" not-null="true">
<column name="name" length="16" not-null="true"/>
</property>
<property name="sex" type="char" />
<property name="age" type="int"/>
</class>
</hibernate-mapping>

 在這個映文件中Q?lt;column/>標籤用於指定建立表格時的一些資a,例如映射的表格欄位名E,或是sql-type?length{屬性,如果不指定這些資訊時,SchemaExportTask自動用Hibernate的類型至SQL型{資a來建立表格Qsql -type用於指定表格Ƅ位型態Qnot-null表示Ƅ位不能為nullQlength則用於指定表格文字欄位長度,這些屬性的說明Q都可以?Hibernate參考手冊的?5.1扑ֈ?/p>

 下面的build.xml用於Ant自動化徏構時Q生成資料n表格之用Q?/p>

build.xml
<project name="Hibernate" default="schema" basedir=".">
<property name="source.root" value="src"/>
<property name="class.root" value="classes"/>
<property name="lib.dir" value="lib"/>
<property name="data.dir" value="data"/>
<path id="project.class.path">
<!-- Include our own classes, of course -->
<pathelement location="${class.root}" />
<!-- Include jars in the project library directory -->
<fileset dir="${lib.dir}">
<include name="*.jar"/>
</fileset>
<pathelement path ="${classpath}"/>
</path>
<target name="schema" description="Generate DB schema from the O/R mapping files">
<!-- Teach Ant how to use Hibernate's schema generation tool -->
<taskdef name="schemaexport"
classname="net.sf.hibernate.tool.hbm2ddl.SchemaExportTask"
classpathref="project.class.path"/>
<schemaexport properties="${source.root}/hibernate.properties"
quiet="no" text="no" drop="no" delimiter=";">
<fileset dir="${source.root}">
<include name="**/*.hbm.xml"/>
</fileset>
</schemaexport>
</target>
</project>

 <taskdef/>標籤定義一個新的Q務schemaexportQ相關的屬性設定是Ҏ參考手冊的a定的,我們在這邊使用 hibernate.properties來告aSchemaExportTask盔R的JDBC資訊Qquiet、text{屬性的定義Q可以看參考手冊的?5.2?/p>

 這個Ant建構檔案Q會扑ְsrc目錄下包括子目錄中有?.hbm.xmlQ並自動Ҏ映射資訊建立表格Q我們還必須提供hibernate.propertiesQ置於src下)來告知JDBC連接的相關訊息:

hibernate.properties
hibernate.dialect=net.sf.hibernate.dialect.MySQLDialect
hibernate.connection.driver_class=com.mysql.jdbc.Driver
hibernate.connection.url=jdbc:mysql://localhost/HibernateTest
hibernate.connection.username=caterpillar
hibernate.connection.password=123456

 這邊使用的是MySQLQ請實際Ҏ您所使用的資料na定dialect、驅動程式等資訊Q在開始運行Ant使用SchemaExportTask進行自動表格建立之前Q您要先建立資料庫,這邊的例子則是在MySQL中先建立HibernateTestQ?/p>

mysql> create database HibernateTest;
Query OK, 1 row affected (0.03 sec)

 接著可以運行Ant了,埯i果如下Q?/p>

ant
Buildfile: build.xml
schema:
[schemaexport] log4j:WARN No appenders could be found for logger (net.sf.hiberna
te.cfg.Environment).
[schemaexport] log4j:WARN Please initialize the log4j system properly.
[schemaexport] drop table if exists USER;
[schemaexport] create table USER (
[schemaexport]    user_id char(32) not null,
[schemaexport]    name varchar(16) not null,
[schemaexport]    sex char(1),
[schemaexport]    age integer,
[schemaexport]    primary key (user_id)
[schemaexport] );
BUILD SUCCESSFUL
Total time: 5 seconds

 運行的過E中Q我們可以看到徏立表格的SQL語句Q而自動徏立好的資料n表格資訊如下Q?/p>

mysql> DESCRIBE user;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| user_id | varchar(32) |      | PRI |         |       |
| name    | varchar(16) |      |     |         |       |
| sex     | char(1)     | YES  |     | NULL    |       |
| age     | int(11)     | YES  |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+
4 rows in set (0.04 sec)

更多有關SchemaExportTask的資a,可以看看參考手冊的W?5章工L指南的部份?/p>

lanxin1020 2009-04-11 11:37 发表评论
]]>
Hibernate延迟加蝲机制(?http://m.tkk7.com/lanxin1020/archive/2009/04/11/264987.htmllanxin1020lanxin1020Sat, 11 Apr 2009 02:35:00 GMThttp://m.tkk7.com/lanxin1020/archive/2009/04/11/264987.htmlhttp://m.tkk7.com/lanxin1020/comments/264987.htmlhttp://m.tkk7.com/lanxin1020/archive/2009/04/11/264987.html#Feedback0http://m.tkk7.com/lanxin1020/comments/commentRss/264987.htmlhttp://m.tkk7.com/lanxin1020/services/trackbacks/264987.html   延迟加蝲机制是ؓ了避免一些无谓的性能开销而提出来的,所谓gq加载就是当在真正需要数据的时候,才真正执行数据加载操作。在Hibernate中提供了对实体对象的延迟加蝲以及寚w合的延迟加蝲Q另外在Hibernate3中还提供了对属性的延迟加蝲。下面我们就分别介绍q些U类的gq加载的l节?
A、实体对象的延迟加蝲Q?/span>
如果惛_实体对象使用延迟加蝲Q必要在实体的映射配置文g中进行相应的配置Q如下所C:
<hibernate-mapping>
<class name=”com.neusoft.entity.User” table=”user” lazy=”true”>
   ……
</class>
</hibernate-mapping>
通过class的lazy属性设|ؓtrueQ来开启实体的延迟加蝲Ҏ。如果我们运行下面的代码Q?
User user=(User)session.load(User.class,”1”);Q?Q?
System.out.println(user.getName());Q?Q?
当运行到(1)处时QHibernateq没有发起对数据的查询,如果我们此时通过一些调试工?比如JBuilder2005的Debug工具)Q观察此时user对象的内存快照,我们会惊奇的发现Q此时返回的可能是User$EnhancerByCGLIB$$bede8986cd的对象,而且其属性ؓnull,q是怎么回事Q还记得前面我曾讲过session.load()ҎQ会q回实体对象的代理类对象Q这里所q回的对象类型就是User对象的代理类对象。在Hibernate中通过使用CGLIB,来实现动态构造一个目标对象的代理cd象,q且在代理类对象中包含目标对象的所有属性和ҎQ而且所有属性均被赋gؓnull。通过调试器显C的内存快照Q我们可以看出此时真正的User对象Q是包含在代理对象的CGLIB$CALBACK_0.target属性中Q当代码q行刎ͼ2Q处Ӟ此时调用user.getName()ҎQ这旉过CGLIB赋予的回调机Ӟ实际上调用CGLIB$CALBACK_0.getName()ҎQ当调用该方法时QHibernate会首先检查CGLIB$CALBACK_0.target属性是否ؓnullQ如果不为空Q则调用目标对象的getNameҎQ如果ؓI,则会发v数据库查询,生成cMq样的SQL语句Qselect * from user where id=’1’;来查询数据,q构造目标对象,q且它赋值到CGLIB$CALBACK_0.target属性中?
   q样Q通过一个中间代理对象,Hibernate实现了实体的延迟加蝲Q只有当用户真正发v获得实体对象属性的动作Ӟ才真正会发v数据库查询操作。所以实体的延迟加蝲是用通过中间代理cd成的Q所以只有session.load()Ҏ才会利用实体延迟加蝲Q因为只有session.load()Ҏ才会q回实体cȝ代理cd象?
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来开启集合类型的延迟加蝲Ҏ。我们看下面的代码:
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的数据烦引,来查扄合条件的实体对象?
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?
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Ҏ扑ֈ的数据烦引发起了两条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中的实体也进行缓存,如果Ҏ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因为此时可以直接从~存中获得集合类型中存放的实体对象?
C?nbsp;      属性gq加载:
  在Hibernate3中,引入了一U新的特性——属性的延迟加蝲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ȝ字节码,Ҏ字节码来动态构造符合要求的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?
Select id,age,name from user where name=’zx’;
q时Hibernate会检索User实体中所有非延迟加蝲属性对应的字段数据Q当执行?2)处时Q会生成cM如下的SQL语句Q?
Select resume from user where id=’1’;
q时会发起对resume字段数据真正的读取操作?


lanxin1020 2009-04-11 10:35 发表评论
]]>
Hibernate~存机制Q{Q?/title><link>http://m.tkk7.com/lanxin1020/archive/2009/04/11/264983.html</link><dc:creator>lanxin1020</dc:creator><author>lanxin1020</author><pubDate>Sat, 11 Apr 2009 02:24:00 GMT</pubDate><guid>http://m.tkk7.com/lanxin1020/archive/2009/04/11/264983.html</guid><wfw:comment>http://m.tkk7.com/lanxin1020/comments/264983.html</wfw:comment><comments>http://m.tkk7.com/lanxin1020/archive/2009/04/11/264983.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/lanxin1020/comments/commentRss/264983.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/lanxin1020/services/trackbacks/264983.html</trackback:ping><description><![CDATA[1.1.1.         基本的缓存原?<br /> Hibernate~存分ؓ二Q第一U存放于session中称ZU缓存,默认带有且不能卸载?<br /> <br /> <br /> <br /> W二U是由sessionFactory控制的进E~存。是全局׃n的缓存,凡是会调用二U缓存的查询Ҏ ?<br /> <br /> 会从中受益。只有经正确的配|后二~存才会发挥作用。同时在q行条g查询时必M用相应的Ҏ <br /> <br /> 才能从缓存中获取数据。比如Query.iterate()Ҏ、load、getҎ{。必L意的是session.find?<br /> <br /> 法永q是从数据库中获取数据,不会从二U缓存中获取数据Q即便其中有其所需要的数据也是如此?<br /> <br /> <br /> <br /> 查询时用缓存的实现q程为:首先查询一U缓存中是否h需要的数据Q如果没有,查询二~存Q?<br /> <br /> 如果二~存中也没有Q此时再执行查询数据库的工作。要注意的是Q此3U方式的查询速度是依ơ降?<br /> <br /> 的?<br /> <br /> 1.2.   存在的问?<br /> 1.2.1.      一U缓存的问题以及使用二~存的原?<br />      因ؓSession的生命期往往很短Q存在于Session内部的第一U最快缓存的生命期当然也很短Q所?<br /> <br /> W一U缓存的命中率是很低的。其对系l性能的改善也是很有限的。当Ӟq个Session内部~存的主?<br /> <br /> 作用是保持Session内部数据状态同步。ƈ非是hibernateZ大幅提高pȝ性能所提供的?<br /> <br /> Z提高使用hibernate的性能Q除了常规的一些需要注意的Ҏ比如Q?<br /> <br /> 使用延迟加蝲、迫切外q接、查询过滤等以外Q还需要配|hibernate的二U缓存。其对系l整体性能?<br /> <br /> 改善往往h立竿见媄的效果! <br /> <br /> Q经q自׃前作目的经验,一般会?~4倍的性能提高Q?<br /> <br /> <br /> <br /> 1.2.2.      N+1ơ查询的问题 <br /> 执行条g查询ӞiterateQ)Ҏh著名?“n+1”ơ查询的问题Q也是说在W一ơ查询时 <br /> <br /> iterateҎ会执行满x件的查询l果数再加一ơ(n+1Q的查询。但是此问题只存在于W一ơ查询时 <br /> <br /> Q在后面执行相同查询时性能会得到极大的改善。此Ҏ适合于查询数据量较大的业务数据?<br /> <br /> 但是注意Q当数据量特别大Ӟ比如水U数据等Q需要针Ҏ持久化对象配|其具体的缓存策略,?<br /> <br /> 如设|其存在于缓存中的最大记录数、缓存存在的旉{参敎ͼ以避免系l将大量的数据同时装载入?<br /> <br /> 存中引v内存资源的迅速耗尽Q反而降低系l的性能Q!Q?<br /> <br /> <br /> <br /> 1.3.   使用hibernate二~存的其他注意事: <br /> 1.3.1.      关于数据的有效?<br /> 另外Qhibernate会自行维护二U缓存中的数据,以保证缓存中的数据和数据库中的真实数据的一致性! <br /> <br /> 无论何时Q当你调用save()、update()?saveOrUpdate()Ҏ传递一个对象时Q或使用load()?get() <br /> <br /> 、list()、iterate() 或scroll()Ҏ获得一个对象时, 该对象都被加入到Session的内部缓存中?<br /> <br /> 当随后flush()Ҏ被调用时Q对象的状态会和数据库取得同步?<br /> <br /> <br /> <br /> 也就是说删除、更新、增加数据的时候,同时更新~存。当然这也包括二U缓存! <br /> <br /> <br /> <br /> 只要是调用hibernate API执行数据库相关的工作。hibernate都会Z自动保证 ~存数据的有效性!Q?<br /> <br /> <br /> <br /> 但是Q如果你使用了JDBCl过hibernate直接执行Ҏ据库的操作。此ӞHibernate不会/也不可能自行 <br /> <br /> 感知到数据库被进行的变化改动Q也׃能再保证~存中数据的有效性!Q?<br /> <br /> <br /> <br /> q也是所有的ORM产品共同h的问题。幸q的是,Hibernate为我们暴露了Cache的清除方法,q给我们 <br /> <br /> 提供了一个手动保证数据有效性的ZQ! <br /> <br /> 一U缓存,二~存都有相应的清除方法?<br /> <br /> <br /> <br /> 其中二~存提供的清除方法ؓQ?<br /> <br /> 按对象class清空~存 <br /> <br />                 按对象class和对象的主键id清空~存 <br /> <br />                 清空对象的集合中的缓存数据等?<br /> <br />     <br /> <br /> 1.3.2.      适合使用的情?<br /> q所有的情况都适合于用二U缓存,需要根据具体情冉|军_。同时可以针Ҏ一个持久化对象?<br /> <br /> |其具体的缓存策略?<br /> <br /> <br /> <br /> 适合于用二U缓存的情况Q?<br /> <br /> 1、数据不会被W三方修改; <br /> <br /> <br /> <br /> 一般情况下Q会被hibernate以外修改的数据最好不要配|二U缓存,以免引v不一致的数据。但是如?<br /> <br /> 此数据因为性能的原因需要被~存Q同时又有可能被W?Ҏ如SQL修改Q也可以为其配置二~存。只 <br /> <br /> 是此旉要在sql执行修改后手动调用cache的清除方法。以保证数据的一致?<br /> <br /> <br /> <br />   2、数据大在可接收范围之内; <br /> <br /> <br /> <br />      如果数据表数据量特别巨大Q此时不适合于二U缓存。原因是~存的数据量q大可能会引起内存资 <br /> <br /> 源紧张,反而降低性能?<br /> <br /> <br /> <br /> 如果数据表数据量特别巨大Q但是经怋用的往往只是较新的那部分数据。此Ӟ也可为其配置二~?<br /> <br /> 存。但是必d独配|其持久化类的缓存策略,比如最大缓存数、缓存过期时间等Q将q些参数降低?<br /> <br /> 一个合理的范围Q太高会引v内存资源紧张Q太低了~存的意义不大)?<br /> <br /> <br /> <br />   3、数据更新频率低Q?<br /> <br /> <br /> <br />      对于数据更新频率q高的数据,频繁同步~存中数据的代h可能?查询~存中的数据从中获得?<br /> <br /> 好处相当Q坏处益处相抉|。此时缓存的意义也不大?<br /> <br /> <br /> <br /> <br /> <br />   4、非关键数据Q不是胦务数据等Q?<br /> <br /> <br /> <br />   财务数据{是非常重要的数据,l对不允许出现或使用无效的数据,所以此时ؓ了安全v见最好不?<br /> <br /> 使用二~存?<br /> <br />   因ؓ此时 “正确?#8221;的重要性远q大?“高性能”的重要性?<br /> <br /> <br /> <br /> 2.     目前pȝ中用hibernate~存的徏?<br /> 1.4.   目前情况 <br /> 一般系l中有三U情况会l开hibernate执行数据库操作: <br /> <br /> 1、多个应用系l同时访问一个数据库 <br /> <br />    此种情况使用hibernate二~存会不可避免的造成数据不一致的问题Q?<br /> <br />    此时要进行详l的设计。比如在设计上避免对同一数据表的同时的写入操作, <br /> <br />    使用数据库各U别的锁定机制{?<br /> <br /> <br /> <br /> 2、动态表相关 <br /> <br />    所?#8220;动态表”是指在系l运行时Ҏ用户的操作系l自动徏立的数据表?<br /> <br />    比如“自定义表?#8221;{属于用戯定义扩展开发性质的功能模块,因ؓ此时数据表是q行时徏立的Q?<br /> <br /> 所以不能进行hibernate的映。因此对它的操作只能是绕开hibernate的直接数据库JDBC操作?<br /> <br />       如果此时动态表中的数据没有设计~存Q就不存在数据不一致的问题?<br /> <br /> <img src ="http://m.tkk7.com/lanxin1020/aggbug/264983.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/lanxin1020/" target="_blank">lanxin1020</a> 2009-04-11 10:24 <a href="http://m.tkk7.com/lanxin1020/archive/2009/04/11/264983.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate ~存机制(?http://m.tkk7.com/lanxin1020/archive/2009/04/11/264973.htmllanxin1020lanxin1020Sat, 11 Apr 2009 02:18:00 GMThttp://m.tkk7.com/lanxin1020/archive/2009/04/11/264973.htmlhttp://m.tkk7.com/lanxin1020/comments/264973.htmlhttp://m.tkk7.com/lanxin1020/archive/2009/04/11/264973.html#Feedback0http://m.tkk7.com/lanxin1020/comments/commentRss/264973.htmlhttp://m.tkk7.com/lanxin1020/services/trackbacks/264973.html~存是介于应用程序和物理数据源之_其作用是Z降低应用E序对物理数据源讉K的频ơ,从而提高了应用的运行性能。缓存内的数据是对物理数据源中的数据的复Ӟ应用E序在运行时从缓存读写数据,在特定的时刻或事件会同步~存和物理数据源的数据?

  ~存的介质一般是内存Q所以读写速度很快。但如果~存中存攄数据量非常大Ӟ也会用硬盘作为缓存介质。缓存的实现不仅仅要考虑存储的介质,q要考虑到管理缓存的q发讉K和缓存数据的生命周期?

  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的第二~存?

  Hibernate的这两~存都位于持久化层,存放的都是数据库数据的拷贝,那么它们之间的区别是什么呢Qؓ了理解二者的区别Q需要深入理解持久化层的~存的两个特性:~存的范围和~存的ƈ发访问策略?

持久化层的缓存的范围

  ~存的范围决定了~存的生命周期以及可以被谁访问。缓存的范围分ؓ三类?

  1 事务范围Q缓存只能被当前事务讉K。缓存的生命周期依赖于事务的生命周期Q当事务l束Ӟ~存也就l束生命周期。在此范围下Q缓存的介质是内存。事务可以是数据库事务或者应用事务,每个事务都有独自的缓存,~存内的数据通常采用怺兌的的对象形式?

  2 q程范围Q缓存被q程内的所有事务共享。这些事务有可能是ƈ发访问缓存,因此必须对缓存采取必要的事务隔离机制。缓存的生命周期依赖于进E的生命周期Q进E结束时Q缓存也q束了生命周期。进E范围的~存可能会存攑֤量的数据Q所以存攄介质可以是内存或盘。缓存内的数据既可以是相互关联的对象形式也可以是对象的松散数据Ş式。松散的对象数据形式有点cM于对象的序列化数据,但是对象分解为松散的法比对象序列化的算法要求更快?

  3 集群范围Q在集群环境中,~存被一个机器或者多个机器的q程׃n。缓存中的数据被复制到集环境中的每个进E节点,q程间通过q程通信来保证缓存中的数据的一致性,~存中的数据通常采用对象的松散数据Ş式?

  对大多数应用来说Q应该慎重地考虑是否需要用集范围的~存Q因问的速度不一定会比直接访问数据库数据的速度快多?

  持久化层可以提供多种范围的缓存。如果在事务范围的缓存中没有查到相应的数据,q可以到q程范围或集范围的~存内查询,如果q是没有查到Q那么只有到数据库中查询。事务范围的~存是持久化层的W一U缓存,通常它是必需的;q程范围或集范围的~存是持久化层的W二U缓存,通常是可选的?

持久化层的缓存的q发讉K{略

  当多个ƈ发的事务同时讉K持久化层的缓存的相同数据Ӟ会引起ƈ发问题,必须采用必要的事务隔L施?

  在进E范围或集群范围的缓存,即第二~存Q会出现q发问题。因此可以设定以下四U类型的q发讉K{略Q每一U策略对应一U事务隔ȝ别?

  事务型:仅仅在受理环境中适用。它提供了Repeatable Read事务隔离U别。对于经常被M很少修改的数据,可以采用q种隔离cdQ因为它可以防止脏读和不可重复读q类的ƈ发问题?

  d型:提供了Read Committed事务隔离U别。仅仅在非集的环境中适用。对于经常被M很少修改的数据,可以采用q种隔离cdQ因为它可以防止脏读q类的ƈ发问题?

  非严D写型Q不保证~存与数据库中数据的一致性。如果存在两个事务同时访问缓存中相同数据的可能,必须数据配置一个很短的数据q期旉Q从而尽量避免脏诅R对于极被修改Qƈ且允许偶脏ȝ数据Q可以采用这Uƈ发访问策略?

  只读型:对于从来不会修改的数据,如参考数据,可以使用q种q发讉K{略?

  事务型ƈ发访问策略是事务隔离U别最高,只读型的隔离U别最低。事务隔ȝ别越高,q发性能p低?

lanxin1020 2009-04-11 10:18 发表评论
]]>
Hibernate 体系l构与工作原??http://m.tkk7.com/lanxin1020/archive/2009/04/09/264745.htmllanxin1020lanxin1020Thu, 09 Apr 2009 15:54:00 GMThttp://m.tkk7.com/lanxin1020/archive/2009/04/09/264745.htmlhttp://m.tkk7.com/lanxin1020/comments/264745.htmlhttp://m.tkk7.com/lanxin1020/archive/2009/04/09/264745.html#Feedback0http://m.tkk7.com/lanxin1020/comments/commentRss/264745.htmlhttp://m.tkk7.com/lanxin1020/services/trackbacks/264745.html1.Hibernate 的初始化.
dHibernate 的配|信?〉创建Session Factory
1)创徏Configerationcȝ实例?br /> 它的构造方法:配|信?Hibernate config.xml)d到内存?br /> 一个Configeration 实例代表Hibernate 所有JavacdSql数据库映的集合?br /> 2)创徏SessionFactory实例
把Configeration 对象中的所有配|信息拷贝到SessionFactory的缓存中?br /> SessionFactory的实例代表一个数据库存储员源Q创建后不再与Configeration 对象兌?br /> ~存(cache):指Java对象的属?通常是一些集合类型的属性-Q占用内存空间?br />      SessionFactory的缓存中QHibernate 配置信息。OR映射元数据?br /> ~存Q大Q重量对象 :轻量U对?br /> 3)调用SessionFactory创徏Session的方?br /> 1】用戯行提供JDBCq接?br />    Connection con=dataSource.getConnection();
   Session s=sessionFactory.openSession(con);
2】让SessionFactory提供q接
   Session s=sessionFactory.openSession();
4)通过Session 接口提供的各U方法来操纵数据库访问?

Hibernate 的缓存体p?br /> 一U缓存:
Session 有一个内|的~存Q其中存放了被当前工作单元加载的对象?br /> 每个Session 都有自己独立的缓存,且只能被当前工作单元讉K?br /> 二~存Q?br /> SessionFactory的外|的可插拔的~存插g。其中的数据可被多个Session׃n讉K?br /> SessionFactory的内|缓存:存放了映元数据Q预定义的Sql语句?/p>

Hibernate 中Java对象的状?br /> 1.临时状?(transient)
特征Q?br />    1】不处于Session ~存?br />    2】数据库中没有对象记?br /> Java如何q入临时状?br />    1】通过new语句刚创Z个对象时
   2】当调用Session 的delete()ҎQ从Session ~存中删除一个对象时?/p>

2.持久化状?persisted)
特征Q?br />    1】处于Session ~存?br />    2】持久化对象数据库中设有对象记录
   3】Session 在特定时M保持二者同?br /> Java如何q入持久化状?br />    1】Session 的save()把Ӟ》持久化状?br />    2】Session 的load(),get()Ҏq回的对?br />    3】Session 的find()q回的list集合中存攄对象
   4】Session 的update(),saveOrupdate()使游-》持久化
3.游离状?detached)
特征Q?br />    1】不再位于Session ~存?br />    2】游d象由持久化状态{变而来Q数据库中可能还有对应记录?br /> Java如何q入持久化状态-》游ȝ?br />    1】Session 的close()Ҏ
   2】Session 的evict()ҎQ从~存中删除一个对象。提高性能。少用?/p>

lanxin1020 2009-04-09 23:54 发表评论
]]>
Hibernate 的原理与配置(?http://m.tkk7.com/lanxin1020/archive/2009/04/09/264744.htmllanxin1020lanxin1020Thu, 09 Apr 2009 15:50:00 GMThttp://m.tkk7.com/lanxin1020/archive/2009/04/09/264744.htmlhttp://m.tkk7.com/lanxin1020/comments/264744.htmlhttp://m.tkk7.com/lanxin1020/archive/2009/04/09/264744.html#Feedback0http://m.tkk7.com/lanxin1020/comments/commentRss/264744.htmlhttp://m.tkk7.com/lanxin1020/services/trackbacks/264744.html
  看完本文后,我相信你对什么是ORMQ对?关系映射Q以及它的优点会有一个深ȝ认识Q我们先通过一个简单的例子开始来展现它的威力?

  正如一些传l的l典计算机文章大都会通过一?#8220;hello,world”的例子开始讲解一P我们也不例外Q我们也从一个相对简单的例子来阐qHibernate的开发方法,但如果要真正阐述Hibernate的一些重要思想Q仅仅靠在屏q上打印一些字W是q远不够的,在我们的CZE序中,我们创Z些对象,q将其保存在数据库中Q然后对它们q行更新和查询?

  阅读D

  “Hello World”“Hello world”CZE序让您对Hibernate有一个简单的认识?
  理解Hibernate的架构介lHibernate接口的主要功能?
  核心接口Hibernate?个核心接口,通过q几个接口开发h员可以存储和获得持久对象Qƈ且能够进行事务控?
  一个重要的术语QTypeType是Hibernate发明者发明的一个术语,它在整个构架中是一个非常基、有着强大功能的元素,一个Type对象能将一个Javacd映射到数据库中一个表的字D中厅R?
  {略接口Hibernate与某些其它开源Y件不同的q有一点――高度的可扩展性,q通过它的内置{略机制来实现?
  基础配置Hibernate可以配置成可在Q何Java环境中运行,一般说来,它通常被用?Q?层的C/S模式的项目中Qƈ被部|在服务端?
  创徏一个SessionFactory对象要创Z个SessionFactory对象Q必dHibernate初始化时创徏一个Configurationcȝ实例Qƈ已写好的映文件交由它处理?

  “Hello World”

  Hibernate应用E序定义了一些持久类Qƈ且定义了q些cM数据库表格的映射关系。在我们q个“Hello world”CZE序中包含了一个类和一个映文件。让我们看看q个单的持久cd含有一些什么?映射文g是怎样定义的?另外Q我们该怎样用Hibernate来操作这个持久类?

  我们q个单示例程序的目的是将一些持久类存储在数据库中,然后从数据库取出来,q将其信息正文显C给用户。其中Message正是一个简单的持久c:Q它包含我们要显C的信息Q其源代码如下:

  列表1 Message.Java 一个简单的持久c?

  package hello;
  public class Message {
  private Long id;
  private String text;
  private Message nextMessage;
  private Message() {}
  public Message(String text) {
  this.text = text;
  }
  public Long getId() {
  return id;
  }
  private void setId(Long id) {
  this.id = id;
  }
  public String getText() {
  return text;
  }
  public void setText(String text) {
  this.text = text;
  }
  public Message getNextMessage() {
  return nextMessage;
  }
  public void setNextMessage(Message nextMessage) {
  this.nextMessage = nextMessage;
  }
  }

  MessagecL三个属性:Message的id 、消息正文、以及一个指向下一条消息的指针。其中id属性让我们的应用程序能够唯一的识别这条消息,通常它等同于数据库中的主键,如果多个Messagecȝ实例对象拥有相同的idQ那它们代表数据库某个表的同一个记录。在q里我们选择了长整型作ؓ我们的id|但这不是必需的。Hibernate允许我们使用L的类型来作ؓ对象的id|在后面我们会Ҏ作详l描q?

  你可能注意到Messagecȝ代码cM于JavaBean的代码风|q且它有一个没有参数的构造函敎ͼ在我们以后的代码中我l用这U风格来~写持久cȝ代码?

  Hibernate会自动管理Messagecȝ实例Qƈ通过内部机制使其持久化,但实际上Message对象q没有实CQ何关于Hibernate的类或接口,因此我们也可以将它作Z个普通的JavacL使用Q?

  Message message = new Message("Hello World");
  System.out.println( message.getText() );

  以上q段代码正是我们所期望的结果:它打?#8220;hello world”到屏q上。但qƈ不是我们的最l目标;实际上Hibernate与诸如EJB容器q样的环境在持久层实现的方式上有很大的不同。我们的持久c?Messagec?可以用在与容器无关的环境中,不像EJB必须要有EJB容器才能执行。ؓ了能更清楚地表现q点Q以下代码将我们的一个新消息保存到数据库中去Q?

  Session session = getSessionFactory().openSession();
  Transaction tx = session.beginTransaction();
  Message message = new Message("Hello World");
  session.save(message);
  tx.commit();
  session.close();

  以上q段代码调用了Hibernate的Session和Transaction接口Q关于getSessionFactory()Ҏ我们会马上提到Q。它相当于我们执行了以下SQL语句Q?

  insert into MESSAGES (MESSAGE_ID, MESSAGE_TEXT, NEXT_MESSAGE_ID)
  values (1, 'Hello World', null)

  在以上的SQL语句中,MESSAGE_ID字段到底被初始化成了什么值呢Q由于我们ƈ没有在先前的代码中ؓmessage对象的id属性赋与初始|那它是否为null呢?实际上Hibernate对id属性作了特D处理:׃它是一个对象的唯一标识Q因此当我们q行save()调用ӞHibernate会ؓ它自动赋予一个唯一的|我们在后面内容中讲q它是如何生成这个值的Q?

  我们假设你已l在数据库中创徏了一个名为MESSAGE的表Q那么既然前面这D代码让我们Message对象存入了数据库中,那么现在我们p它们一一取出来。下面这D代码将按照字母序Q将数据库中的所有Message对象取出来,q将它们的消息正文打印到屏幕上:

  Session newSession = getSessionFactory().openSession();
  Transaction newTransaction = newSession.beginTransaction();
  List messages =newSession.find("from Message as m order by m.text asc");
  System.out.println( messages.size() + " message(s) found:" );
  for ( Iterator iter = messages.iterator(); iter.hasNext(); ) {
  Message message = (Message) iter.next();
  System.out.println( message.getText() );
  }
  newTransaction.commit();
  newSession.close();

  在以上这D代码中Q你可能被find()Ҏ的这个参数困扰着Q?from Message as m order by m.text asc"Q其实它是Hibernate自己定义的查询语aQ全U叫Hibernate Query Language(HQL)。通俗地讲HQL与SQL的关pd不多是方言与普通话之间的关p,咋一看,你会觉得它有点类gSQL语句。其实在find()调用ӞHibernate会将q段HQL语言译成如下的SQL语句Q?

  select m.MESSAGE_ID, m.MESSAGE_TEXT, m.NEXT_MESSAGE_ID
  from MESSAGES m
  order by m.MESSAGE_TEXT asc

  以下是q行l果Q?

  1 message(s) found:
  Hello World

  如果你以前没有ORMQ对象-关系映射Q的开发经验,那你可能惛_代码的某个地方去Lq段SQL语句Q但在Hibernate中你可能会失望:它根本不存在Q所有就SQL语句都是Hibernate动态生成的?

  也许你会觉得q缺点什么,对!仅凭以上代码Hibernate是无法将我们的MessagecL久化的。我们还需要一些更多的信息Q这是映射定义表!q个表在Hibernate中是以XML格式来体现的Q它定义了Messagecȝ属性是怎样与数据库中的MESSAGES表的字段q行一一对应的,列表2是这个示例程序的映射配置文g清单Q?

  列表2Q示例程序的对象Q关pL表

  Q?xml version="1.0"?Q?
  Q?DOCTYPE hibernate-mapping PUBLIC
  "-//Hibernate/Hibernate Mapping DTD//EN"
  "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"Q?
  Qhibernate-mappingQ?
  Qclass name="hello.Message" table="MESSAGES"Q?
  Qid name="id" column="MESSAGE_ID"Q?
  Qgenerator class="increment"/Q?
  Q?idQ?
  Qproperty name="text" column="MESSAGE_TEXT"/Q?
  Qmany-to-one name="nextMessage" cascade="all" column="NEXT_MESSAGE_ID"/Q?
  Q?classQ?
  Q?hibernate-mappingQ?

  以上q个文档告诉Hibernate怎样MessagecL到MESSAGES表中Q其中Messagecȝid属性与表的MESSAGE_ID字段对应Qtext属性与表的MESSAGE_TEXT字段对应QnextMessage属性是一个多对一的关p,它与表中的NEXT_MESSAGE_ID相对应?

  相对于有些开源项目来_Hibernate的配|文件其实是很容易理解的。你可以LC改与l护它。只要你定义好了持久cM数据库中表字D늚对应关系p了,Hibernate会自动帮你生成SQL语句来对Message对象q行插入、更新、删除、查扑ַ作,你可以不写一句SQL语句Q甚至不需要懂得SQL语言Q?

  现在让我们做一个新的试验,我们先取出第一个Message对象Q然后修改它的消息正文,最后我们再生成一个新的Message对象Qƈ它作ؓW一个Message对象的下一条消息,其代码如下:

  列表3 更新一条消?

  Session session = getSessionFactory().openSession();
  Transaction tx = session.beginTransaction();
  // 1 is the generated id of the first message
  Message message =(Message) session.load( Message.class, new Long(1) );
  message.setText("Greetings Earthling");
  Message nextMessage = new Message("Take me to your leader (please)");
  message.setNextMessage( nextMessage );
  tx.commit();
  session.close();

  以上q段代码在调用时QHibernate内部自动生成如下的SQL语句Q?

  select m.MESSAGE_ID, m.MESSAGE_TEXT, m.NEXT_MESSAGE_ID
  from MESSAGES m
  where m.MESSAGE_ID = 1

  insert into MESSAGES (MESSAGE_ID, MESSAGE_TEXT, NEXT_MESSAGE_ID)
  values (2, 'Take me to your leader (please)', null)

  update MESSAGES
  set MESSAGE_TEXT = 'Greetings Earthling', NEXT_MESSAGE_ID = 2
  where MESSAGE_ID = 1

  当第一个Message对象的text属性和nextMessage被程序修ҎQ请注意Hibernate是如何检到q种变化Qƈ如何在数据库中自动对它更新的。这实际上是Hibernate的一个很有h值的特色Q我们把它称?#8220;自动脏数据检?#8221;QHibernate的这个特色得当我们修改一个持久对象的属性后Q不必显式地通知Hibernated它在数据库中q行更新。同LQ当W一个Message对象调用setNextMessage()Ҏ第二个Message对象作ؓ它的下一条消息的引用ӞW二条消息会无需调用save()ҎQ便可以自动C存在数据库中。这U特色被UCؓ“U联保存”Q它也免M我们昑ּ地对W二个Message对象调用save()Ҏ之苦?

  如果我们再运行先前的那段数据库中所有的Message对象都打印出来的代码Q那它的q行l果如下Q?

  2 message(s) found:
  Greetings Earthling
  Take me to your leader (please)


  “Hello world”CZE序现在介绍完毕。我们ȝ对Hibernate有了一个简单的认识Q下面我们将回过头来Q对Hibernate的主要API调用作一下简要的介绍Q?
  

  理解Hibernate的架?/strong>

  当你想用Hibernate开发自qZ持久层的应用ӞW一件事情应当是熟悉它的~程接口。Hibernate的API接口设计得尽量简z明了,以方便开发h员。然而实际上׃ORM的复杂性,它的API一般都不可能设计得很简单。但是别担心Q你没有必要一下子了解所有的Hibernate的API接口?br />
  我们应用层攑֜了持久层的上部,实际上在传统的项目中Q应用层充当着持久层的一个客L角色。但对于一些简单的目来说Q应用层和持久层q没有区分得那么清楚Q这也没什么,在这U情况下你可以将应用层和持久层合q成了一层?

  Hibernate的接口大致可以分Z下几U类型:

  · 一些被用户的应用程序调用的Q用来完成基本的创徏、读取、更新、删除操作以及查询操作的接口。这些接口是Hibernate实现用户E序的商业逻辑的主要接口,它们包括Session、Transaction和Query?

  · Hibernate用来d诸如映射表这c配|文件的接口Q典型的代表有ConfigurationcR?

  · 回调(Callback)接口。它允许应用E序能对一些事件的发生作出相应的操作,例如Interceptor、Lifecycle和Validatable都是q一cL口?

  · 一些可以用来扩展Hibernate的映机制的接口Q例如UserType、CompositeUserType和IdentifierGenerator。这些接口可qL序来实现Q如果有必要Q?

  Hibernate使用了J2EE架构中的如下技术:JDBC、JTA、JNDI。其中JDBC是一个支持关pL据库操作的一个基层;它与JNDI和JTA一L合,使得Hibernate可以方便地集成到J2EE应用服务器中厅R?

  在这里,我们不会详细地去讨论Hibernate API接口中的所有方法,我们只简要讲一下每个主要接口的功能Q如果你想了解得更多的话Q你可以在Hibernate的源码包中的net.sf.hibernate子包中去查看q些接口的源代码。下面我们依ơ讲一下所有的主要接口Q?

  核心接口

  以下5个核心接口几乎在M实际开发中都会用到。通过q些接口Q你不仅可以存储和获得持久对象,q且能够q行事务控制?

  Session接口

  Session接口对于Hibernate 开发h员来说是一个最重要的接口。然而在Hibernate中,实例化的Session是一个轻量的类Q创建和销毁它都不会占用很多资源。这在实际项目中实很重要,因ؓ在客L序中Q可能会不断地创Z及销毁Session对象Q如果Session的开销太大Q会l系l带来不良媄响。但值得注意的是Session对象是非U程安全的,因此在你的设计中Q最好是一个线E只创徏一个Session对象?

  在Hibernate的设计者的头脑中,他们session看作介于数据q接与事务管理一U中间接口。我们可以将session惌成一个持久对象的~冲区,Hibernate能检到q些持久对象的改变,q及时刷新数据库。我们有时也USession是一个持久层理器,因ؓ它包含这一些持久层相关的操作,诸如存储持久对象x据库Q以及从数据库从获得它们。请注意QHibernate 的session不同于JSP应用中的HttpSession。当我们使用sessionq个术语Ӟ我们指的是Hibernate中的sessionQ而我们以后会HttpSesion对象UCؓ用户session?

  SessionFactory 接口

  q里用到了一个设计模式――工厂模式,用户E序从工厂类SessionFactory中取得Session的实例?

  令你感到奇怪的是SessionFactoryq不是轻量的!实际上它的设计者的意图是让它能在整个应用中׃n。典型地来说Q一个项目通常只需要一个SessionFactory够了,但是当你的项目要操作多个数据库时Q那你必Mؓ每个数据库指定一个SessionFactory?
  SessionFactory在Hibernate中实际vC一个缓冲区的作用,它缓冲了Hibernate自动生成的SQL语句和一些其它的映射数据Q还~冲了一些将来有可能重复利用的数据?

  Configuration 接口

  Configuration接口的作用是对Hibernateq行配置Q以及对它进行启动。在Hibernate的启动过E中QConfigurationcȝ实例首先定位映射文档的位|,dq些配置Q然后创Z个SessionFactory对象?

  虽然Configuration接口在整个Hibernate目中只扮演着一个很的角色Q但它是启动hibernate时你所遇到的每一个对象?

  Transaction 接口

  Transaction接口是一个可选的APIQ你可以选择不用这个接口,取而代之的是Hibernate的设计者自己写的底层事务处理代码?Transaction接口是对实际事务实现的一个抽象,q些实现包括JDBC的事务、JTA中的UserTransaction、甚臛_以是CORBA事务。之所以这栯计是能让开发者能够用一个统一事务的操作界面,使得自己的项目可以在不同的环境和容器之间方便地移倹{?

  Query和Criteria接口

  Query接口让你方便地对数据库及持久对象q行查询Q它可以有两U表达方式:HQL语言或本地数据库的SQL语句。Queryl常被用来绑定查询参数、限制查询记录数量,q最l执行查询操作?

  Criteria接口与Query接口非常cMQ它允许你创建ƈ执行面向对象的标准化查询?

  值得注意的是Query接口也是轻量U的Q它不能在Session之外使用?

  Callback 接口

  当一些有用的事g发生时――例如持久对象的载入、存储、删除时QCallback接口会通知HibernateL收一个通知消息。一般而言QCallback接口在用L序中q不是必ȝQ但你要在你的项目中创徏审计日志Ӟ你可能会用到它?

   一个重要的术语QType

  Hibernate的设计者们发明了一个术语:TypeQ它在整个构架中是一个非常基、有着强大功能的元素。一个Type对象能将一个Javacd映射到数据库中一个表的字D中去(实际上,它可以映到表的多个字段中去Q。持久类的所有属性都对应一个type。这U设计思想使用Hibernate有着高度的灵zL和扩展性?

  Hibernate内置很多typecdQ几乎包括所有的Java基本cdQ例如Java.util.Currency、Java.util.calendar、byte[]和Java.io.Serializable?

  不仅如此QHibernateq支持用戯定义的typeQ通过实现接口UserType和接口CompositeUserTypeQ你可以加入自己的type。你可以利用q种特色让你的项目中使用自定义的诸如Address、Nameq样的typeQ这样你可以获得更大的便利Q让你的代码更优雅。自定义type在Hibernate中是一Ҏ心特Ԍ它的设计者鼓׃多多使用它来创徏一个灵zR优雅的目Q?

  {略接口

  Hibernate与某些其它开源Y件不同的q有一点――高度的可扩展性,q通过它的内置{略机制来实现。当你感觉到Hibernate的某些功能不I或者有某些~陷Ӟ你可以开发一个自q{略来替换它Q而你所要做的仅仅只是承它的某个策略接口,然后实现你的新策略就可以了,以下是它的策略接口:

  · 主键的生?(IdentifierGenerator 接口)

  · 本地SQL语言支持 (Dialect 抽象c?

  · ~冲机制 (Cache 和CacheProvider 接口)

  · JDBC q接理 (ConnectionProvider接口)

  · 事务理 (TransactionFactory, Transaction, ?TransactionManagerLookup 接口)

  · ORM {略 (ClassPersister 接口)

  · 属性访问策?(PropertyAccessor 接口)

  · 代理对象的创?(ProxyFactory接口)

  HibernateZ上所列的机制分别创徏了一个缺省的实现Q因此如果你只是要增强它的某个策略的功能的话Q只需单地l承q个cd可以了,没有必要从头开始写代码?

  以上是Hibernate的一些核心接口,但当我们真正开始用它进行开发时Q你的脑里可能M有一个疑问:我是通过什么方式,q从哪里取得Session的呢Q以下我们就解答q个问题?

  基础配置

  现在回顾一下我们先前的内容Q我们写Z一个示例程序,q简要地讲解了Hibernate的一些核心类。但要真正你的目q行hQ还有一件事必须要做Q配|。Hibernate可以配置成可在Q何Java环境中运行,一般说来,它通常被用?Q?层的C/S模式的项目中Qƈ被部|在服务端。在q种目中,Web览器、或Java GUIE序充当者客L。尽我们的焦点主要是集中在多层web应用Q但实际上在一些基于命令行的应用中也可以用Hibernate。ƈ且,对Hibernate的配|在不同的环境下都会不同QHibernateq行在两U环境下Q可理环境和不可管理环?

  · 可管理环境――这U环境可理如下资源Q池资源理Q诸如数据库q接池和Q还有事务管理、安全定义。一些典型的J2EE服务器(JBoss、Weblogic、WebSphereQ已l实Cq些?

  · 不可理环境――只是提供了一些基本的功能Q诸如像Jetty或Tomcatq样的servlet容器环境。一个普通的Java桌面应用或命令行E序也可以认为是处于q种环境下。这U环境不能提供自动事务处理、资源管理或安全理Q这些都必须由应用程序自己来定义?

  Hibernate的设计者们这两种环境设计了一个统一的抽象界面,因此对于开发者来说只有一U环境:可管理环境。如果实际项目是建立在诸如Tomcatq类不可理的环境中Ӟ那Hibernate会使用它自q事务处理代码和JDBCq接池,使其变ؓ一个可理环境?
  对于可管理的环境而言QHibernate会将自己集成在这U环境中。对于开发者而言Q你所要做的工作非常简单:只需从一个ConfigurationcM创徏一个SessionFactorycd可以了?
   创徏一个SessionFactory对象

  Z能创Z个SessionFactory对象Q你必须在Hibernate初始化时创徏一个Configurationcȝ实例Qƈ已写好的映文件交由它处理。这PConfiguration对象可以创Z个SessionFactory对象Q当SessionFactory对象创徏成功后,Configuration对象没有用了,你可以简单地抛弃它。如下是CZ代码Q?

  Configuration cfg = new Configuration();
  cfg.addResource("hello/Message.hbm.xml");
  cfg.setProperties( System.getProperties() );
  SessionFactory sessions = cfg.buildSessionFactory();

  在以上代码中QMessage.hb.xmlq个映射文g的位|比较特D,它与当前的classpath相关。例如classpath包含当前目录Q那在上qC码中的Message.hbm.xml映射文g可以保存在当前目录下的hello目录中?

  作ؓ一U约定,Hibernate的映文仉认以.htm.xml作ؓ其扩展名。另一个约定是坚持为每一个持久类写一个配|文Ӟ想一惛_果你所有持久类的映写入一个单独的配置文g中的话,那这个配|文件肯定非常庞大,不易l护。但q里又出C一个新问题Q如果ؓ每个cd一个配|文件的话,q么多的配置文g应该存放在哪里呢Q?

  Hibernate推荐你将每个映射文g保存在与持久cȝ同的目录下,q且与持久类同名。例如我们第一个示例程序中的Message持久cL在hello目录下,那你必须在这个目录下存放名ؓMessage.hbm.xml的映文件。这样一个持久类都有自己的一个映文Ӟ避免了出现像struts目中的“struts-config.xml地狱”的情c如果你不遵循这U规定,那你必须手动地用addResource()Ҏ一个个的映文件蝲入;但你如果遵@q种规定Q那你可以方便地用addClass()Ҏ同时持久类和它的映文件蝲入,以下是体现这U便利性的CZ代码Q?

  SessionFactory sessions = new Configuration()
  .addClass(org.hibernate.auction.model.Item.class)
  .addClass(org.hibernate.auction.model.Category.class)
  .addClass(org.hibernate.auction.model.Bid.class)
  .setProperties( System.getProperties() )
  .buildSessionFactory();

  当然QHibernate的映文件还有很多其它的配置选项Q比如数据库q接的设定,或是能够改变Hibernateq行时行为的一些设定。所有的讄可能是非常庞杂的Q以让你喘不过气来Q但是不必担心,因ؓHibernate为绝大多数值都讑֮了一个合理缺省|你只需要修改这些配|文件中的极一部分倹{?

  你可以通过以下几种方式来修改Hibernate的系l配|参敎ͼ

  · 一个Java.util.Properties实例作ؓ参数传给ConfigurationcȝsetProperties()Ҏ?

  · 在Hibernate启动时用Java –Dproperty=value的方式设|倹{?

  · 在classpath可以扑ֈ的\径下创徏一个名为hibernate.properties的配|文件?

  · 在classpath可以扑ֈ的\径下创徏一个名为hibernate.cfg.xml的文Ӟq在ӞpropertyQ标{中定义属性倹{?

  以上是对Hibernate的一个大致介l,如果你想知道得更多,那本文还是远q不够的Q我陆l推出更多关于Hibernate的资料。但有一Ҏ毫无疑问的:它的是一个非怼U的持久层解决ҎQ?/p>


lanxin1020 2009-04-09 23:50 发表评论
]]>
Hibernate实体对象的生命周期(转)http://m.tkk7.com/lanxin1020/archive/2009/04/08/264425.htmllanxin1020lanxin1020Wed, 08 Apr 2009 04:02:00 GMThttp://m.tkk7.com/lanxin1020/archive/2009/04/08/264425.htmlhttp://m.tkk7.com/lanxin1020/comments/264425.htmlhttp://m.tkk7.com/lanxin1020/archive/2009/04/08/264425.html#Feedback0http://m.tkk7.com/lanxin1020/comments/commentRss/264425.htmlhttp://m.tkk7.com/lanxin1020/services/trackbacks/264425.htmlHibernate实体对象的生命周?/a> 关键? hibernate学习W记
在用Hibernate的时候,时不时会因ؓ没有处理好实体对象的状态而犯一些莫名其妙的异常Q在q里对实体对象的各种状态整理一下,希望能有所帮助?

Hibernate实体对象Q即指Hibernate O/R影射关系中的域对?即O/R中的"O"。在Hibrenate实体对象的生命周期中存在着三中状态,卻I
1Q自q态(TransientQ?
2Q持久状态(PersistentQ?
3Q游ȝ态(DetachedQ?

1Q自q态(TransientQ?/strong>
自由状态(TransientQ?/span>,是指实体对象在内存中自由存在Q他与数据库的记录无兟뀂如Q?
Java代码
  1. TUser user = new TUser();   
  2. user.setName("MyName");  

q里的user对象只是一个非常普通的java对象Q与数据库中的记录没有Q何关pR?

2Q持久状态(PersistentQ?/strong>
持久状态(PersistentQ?/span>,卛_体对象处于Hibernate框架的管理状态,实体对象被纳入Hibernate的实体容器中理。处?span style="color: brown">持久状?/span>的对象,其更变将由Hibernate固化到数据库中。如Q?
Java代码
  1. //创徏两个处于自由状态的实体对象?  
  2. TUser user_1 = new TUser();   
  3. TUser user_2 = new TUser();   
  4.   
  5. user_1.setName("Name_1");   
  6. user_2.setName("Name_2");   
  7.   
  8. Transaction tx = session.begintransaction();   
  9. session.save(user_1);   
  10. //通过session的saveҎQuser_1对象已经被纳入Hibernate的实体管理容器,处于持久化状   
  11. //?Persistent)Q这时候对user_1对象的Q何修攚w被同步到数据库中?  
  12.   
  13. tx.commit();   
  14.   
  15. //而user_2仍然才处于自q态(TransientQ,不受Hibernate框架的管理?/span>  

从上面看刎ͼ处于自由状?/span>的实体对象,可以通过Hibernate的Session.savaҎ转化?span style="color: brown">持久状?/span>?
除了用Session.saveҎ外,q可以通过其他Ҏ来获取一?span style="color: brown">持久状?/span>的对象,那就是直接通过Hibernate加蝲的对象,通过Session.loadҎQ可以直接加载一个处?span style="color: brown">持久状?/span>的实体对象。如下:
Java代码
  1. TUser user = Session.load(TUser.class,new Integer(1));   
  2. //在loadҎ没返回之前,已l先把对象纳入Hibernate的管理范_所以这里的user   
  3. //已经处于持久状态?/span>  

从上面的代码可以看出Q处?span style="color: brown">持久状?/span>的实体对象一定要和Session兌Qƈ处于该Session的有效期内?

3Q游ȝ态(DetachedQ?/strong>
处于持久状?/span>的实体对象,在其兌的Session关闭以后Q此实体对象处?span style="color: brown">游离状?/span>Q?
Java代码
  1. TUser user = new TUser();   
  2. user.setName("name_1");   
  3. Transaction tx = session.begintransaction();   
  4. session.save(user);//把自q态的实体对象user转ؓ持久状态,   
  5. tx.commit();   
  6. session.close();   
  7. //session关闭以后Q处于持久状态的实体对象user{为游ȝ态?  
  8. //因ؓ此时user已经和sessionq关系?/span>  


׃面可以看到实体对象的游离状?/span>是在对象和它所寄宿的Sessionq关系后Ş成的Q但处于自由状?/span>的实体对象也没有和Q何session有关联,那么他们两者有什么区别呢Q关键的在我们?span style="color: brown">自由状?/span>的实体对象执行了Session.saveҎQ?
当我们执?
Java代码
  1. TUser user = new TUser();  

Ӟ我们只是创徏了一个普通的对象Q他q没有和数据库里的Q何一条记录对应,当我们执?
Session.save以后QHibernate׃ؓuser讄了一个主键,是user.Id属性,通过q个属性,Hibernate把user对象和数据库里的记录兌hQ所?span style="color: brown">自由状?/span>?span style="color: brown">游离状?/span>的基本区别就?处于游离状?/span>的实体对象,在数据库里有对应的记录,因此它可以通过和session兌再次转ؓ持久状?/span>?

三种状态的转化
自由状?->持久状态:可以通过Session.savaҎ来{换?
持久状?->游离状态:可以通过Session.closeҎ来关闭sessionQ获取游ȝ态的对象
持久状?->自由状态:可以通过Session.deleteҎ来删除实体对象对应的数据库记录,使实体对象处于自q态?

补充一下,有时可能会想Q可以通过认ؓ的个处于自由状?/span>的实体对象设|一个Id?
Java代码
  1. user.Id=1  
Q来Zؓ的创Z?span style="color: brown">游离状?/span>的对象?
q里注意一点,我们可以Zؓ地给实体对象讄Id|我我们无法知道这个ID值在数据库里有没有对应的记录Q如果没有,q我们Zؓ地设|了IdQ也不能说一个有ID的实体对象就是一?span style="color: brown">游离状?/span>的对象?/div>

]]> վ֩ģ壺 ˵va| ĻþƷ| ŮAëƬ| AVվ| ˿ҺƵ| 2048޾Ʒ| ƷŮſͰˬѿ| 뾫ƷӰ| ŷһ| ߹ۿƵ| պɫƵһ| ƷѲ | ڵëƬѿ| 99͵ͼ| ԻƤȫƵѹ30| ޾Ʒר| ˳վ߸| ѹۿվ| þ޹˾Ʒɫ| þþžѾƷ6| ŷa߹ۿ| ÿ߹ۿapp| ƷƵ| AVһ| þùɫAVѿ| ޾Ʒ߹ۿ| ޹aۺ| ѿjŽŮjѿ| ŷղvؼëƬ| ѿƬѲ| žȾþƵ| þþƷav鶹ɫ| 椸Ƶ߹ۿ| һëƬѹۿ| ۺһ| ձƵ| ĻӰӰԺ߹ۿƵ| AVɫ˿| ҹ717| ҳƵ߹ۿ | CAOPORNƷƵ|
lanxin1020 2009-04-08 12:02 发表评论