ï»??xml version="1.0" encoding="utf-8" standalone="yes"?>天堂中文在线8,中文字幕日韩有码,精品国产乱码久久久久久1区2匹 http://www.aygfsteel.com/lanxin1020/category/38968.htmlzh-cnMon, 25 May 2009 09:50:55 GMTMon, 25 May 2009 09:50:55 GMT60hibernate 自定义数据类型映ž®„(转)http://www.aygfsteel.com/lanxin1020/archive/2009/05/24/277716.htmllanxin1020lanxin1020Sun, 24 May 2009 11:57:00 GMThttp://www.aygfsteel.com/lanxin1020/archive/2009/05/24/277716.htmlhttp://www.aygfsteel.com/lanxin1020/comments/277716.htmlhttp://www.aygfsteel.com/lanxin1020/archive/2009/05/24/277716.html#Feedback0http://www.aygfsteel.com/lanxin1020/comments/commentRss/277716.htmlhttp://www.aygfsteel.com/lanxin1020/services/trackbacks/277716.htmlHibernate中提供的用户¾cÕdž‹è‡ªå®šä¹‰æŽ¥å£ã€‚根据这个接口,可以实现自定义的数据¾cÕdž‹ã€?nbsp;

最˜q‘看<<深入‹¹…出Hibernate>>,作者在书中介绍äº?span class="hilite1">Hibernate 提供的用戯‚‡ªå®šä¹‰æ•°æ®¾cÕdž‹åQŒäºŽæ˜¯æ•ˆä»¿ä¹¦ä¸­çš„æ–ÒŽ³•åQŒåœ¨æ•°æ®åº“表中添加一个字ŒD는¨äºŽè®°å½•所有好友的useridåQŒæ¯ä¸ªuserid之间ç”?;"加以分隔åQŒåŒæ—¶å°†è¯¥å­—ŒD‰|˜ ž®„äØ“ä¸€ä¸ªç‰¹ŒDŠçš„List集合åQŒåˆ©ç”¨UserType interface实现String解析后将各个useridž®è£…在List中,ž®†List中的记录ž®è£…成以";"分隔的Stringã€?
使用UserType接口åQŒå®žçŽîCº†è¾ƒå¥½çš„设计风æ û|¼Œä»¥åŠæ›´å¥½çš„重用性ã€?
/*
* 用户自定义的数据¾cÕdž‹åQŒå¯¹åº”数据库中的一个字Œ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Œåƈž®†å…¶è§£æžä¸ºList¾cÕdž‹åŽè¿”å›?
*/
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Œä¿®æ”¹POJO¾cÖM¸­è¯¥å­—ŒD늚„˜q”回¾cÕdž‹ä¸ºListã€?
使用JUnit‹¹‹è¯•½E‹åºã€?


]]>
Hibernate悲观锁和乐观��http://www.aygfsteel.com/lanxin1020/archive/2009/04/12/265131.htmllanxin1020lanxin1020Sun, 12 Apr 2009 08:12:00 GMThttp://www.aygfsteel.com/lanxin1020/archive/2009/04/12/265131.htmlhttp://www.aygfsteel.com/lanxin1020/comments/265131.htmlhttp://www.aygfsteel.com/lanxin1020/archive/2009/04/12/265131.html#Feedback0http://www.aygfsteel.com/lanxin1020/comments/commentRss/265131.htmlhttp://www.aygfsteel.com/lanxin1020/services/trackbacks/265131.html
åQˆè{åQ?span class="hilite1">Hibernate支持两种锁机åˆÓž¼š
即通常所说的“悲观锁(Pessimistic LockingåQ?#8221;å’?
“乐观锁(OptimisticLockingåQ?#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Œå¦‚Hibernateä¸ÞZº†ä¿è¯Update
˜q‡ç¨‹ä¸­å¯¹è±¡ä¸ä¼šè¢«å¤–界修改åQŒä¼šåœ¨saveæ–ÒŽ³•å®žçŽ°ä¸­è‡ªåŠ¨äØ“ç›®æ ‡å¯¹è±¡åŠ ä¸ŠWRITE锁ã€?
Ø LockMode.UPGRADE åQšåˆ©ç”¨æ•°æ®åº“çš„for update子句加锁ã€?
Ø LockMode. UPGRADE_NOWAIT åQšOracle的特定实玎ͼŒåˆ©ç”¨Oracleçš„for
update nowait子句实现加锁�
乐观锁,大多是基于数据版本(VersionåQ‰è®°å½•æœºåˆ¶å®žçŽ°ã€‚ä½•è°“æ•°æ®ç‰ˆæœ¬ï¼Ÿå³äØ“æ•°æ®å¢žåŠ ä¸€ä¸ªç‰ˆæœ¬æ ‡è¯†ï¼Œåœ¨åŸºäºŽæ•°æ®åº“è¡¨çš„ç‰ˆæœ¬è§£å†³æ–ÒŽ¡ˆä¸­ï¼Œä¸€èˆ¬æ˜¯é€šè¿‡ä¸ºæ•°æ®åº“表增加一ä¸?#8220;version”字段来实现。读取出数据æ—Óž¼Œž®†æ­¤ç‰ˆæœ¬å·ä¸€åŒè¯»å‡ºï¼Œä¹‹åŽæ›´æ–°æ—Óž¼Œå¯ÒŽ­¤ç‰ˆæœ¬å·åŠ ä¸€ã€‚æ­¤æ—Óž¼Œž®†æäº¤æ•°æ®çš„版本数据与数据库表对应记录的当前版本信息˜q›è¡Œæ¯”对åQŒå¦‚果提交的数据版本号大于数据库表当前版本号åQŒåˆ™äºˆä»¥æ›´æ–°åQŒå¦åˆ™è®¤ä¸ºæ˜¯˜q‡æœŸæ•°æ®ã€?
悲观锁与乐观锁的比较:
悲观锁大多数情况下依靠数据库的锁机制实现åQŒä»¥ä¿è¯æ“ä½œæœ€å¤§ç¨‹åº¦çš„独占性。但随之而来的就是数据库性能的大量开销åQŒç‰¹åˆ«æ˜¯å¯šw•¿äº‹åŠ¡è€Œè¨€åQŒè¿™æ ïLš„开销往往无法承受;
相对悲观锁而言åQŒä¹è§‚锁机制采取了更加宽杄¡š„加锁机制。乐观锁机制往往åŸÞZºŽ¾pȝ»Ÿä¸­çš„æ•°æ®å­˜å‚¨é€»è¾‘å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乐观锁实现机制ã€?


]]>
使用 SchemaExport è‡ªåŠ¨å»ø™¡¨ http://www.aygfsteel.com/lanxin1020/archive/2009/04/11/265021.htmllanxin1020lanxin1020Sat, 11 Apr 2009 08:31:00 GMThttp://www.aygfsteel.com/lanxin1020/archive/2009/04/11/265021.htmlhttp://www.aygfsteel.com/lanxin1020/comments/265021.htmlhttp://www.aygfsteel.com/lanxin1020/archive/2009/04/11/265021.html#Feedback0http://www.aygfsteel.com/lanxin1020/comments/commentRss/265021.htmlhttp://www.aygfsteel.com/lanxin1020/services/trackbacks/265021.html使用 SchemaExport è‡ªåŠ¨å»ø™¡¨

使用Hibernate自带的工å…?em>hbm2ddlåQŒå¾ç«‹æ ¹æ®ä½ çš„对象徏立数据库:

首先建好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); } }


]]>
SchemaExportTask(转自 良葛æ ?http://www.aygfsteel.com/lanxin1020/archive/2009/04/11/265001.htmllanxin1020lanxin1020Sat, 11 Apr 2009 03:37:00 GMThttp://www.aygfsteel.com/lanxin1020/archive/2009/04/11/265001.htmlhttp://www.aygfsteel.com/lanxin1020/comments/265001.htmlhttp://www.aygfsteel.com/lanxin1020/archive/2009/04/11/265001.html#Feedback0http://www.aygfsteel.com/lanxin1020/comments/commentRss/265001.htmlhttp://www.aygfsteel.com/lanxin1020/services/trackbacks/265001.html在您撰寫å¥?.hbm.xml映射文äšg之後åQŒæ‚¨å¯ä»¥ä½¿ç”¨ net.sf.hibernate.tool.hbm2ddl.SchemaExportTask來自動徏立資料åín表格åQŒé€™é‚Šæ‰€ä½¿ç”¨çš„æ–¹å¼æ˜¯¾iåˆAnt進行自動化徏構,首先我們假­a­å°‡ä½¿ç”¨ä»¥ä¸‹çš„User.hbm.xmlåQ?

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Šä¾†å»ºç«‹è¡¨æ ¼åQ›sql -type用於指定表格‹Æ„位型態åQŒnot-null表示‹Æ„位不能為nullåQŒlength則用於指定表格文字欄位長度,這些屬性的說明å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å‹™schemaexportåQŒç›¸é—œçš„屬性設定是æ ÒŽ“šåƒè€ƒæ‰‹å†Šçš„廸™­°­a­å®šçš„,我們在這邊使用 hibernate.properties來告­a´SchemaExportTaskç›”R—œçš„JDBC資訊åQŒquiet、text½{‰å±¬æ€§çš„定義åQŒå¯ä»¥çœ‹åƒè€ƒæ‰‹å†Šçš„è¡?5.2ã€?/p>

 這個Ant建構檔案åQŒæœƒæ‰‘Ö°‹src目錄下包括子目錄中有çš?.hbm.xmlåQŒä¸¦è‡ªå‹•æ ÒŽ“šæ˜ å°„è³‡è¨Šå»ºç«‹è¡¨æ ¼åQŒæˆ‘們還必須提供hibernate.propertiesåQˆç½®æ–¼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

 這邊使用的是MySQLåQŒè«‹å¯¦éš›æ ÒŽ“šæ‚¨æ‰€ä½¿ç”¨çš„è³‡æ–™åín­a­å®šdialect、驅動程式等資訊åQŒåœ¨é–‹å§‹é‹è¡ŒAnt使用SchemaExportTask進行自動表格建立之前åQŒæ‚¨è¦å…ˆå»ºç«‹è³‡æ–™åº«ï¼Œé€™é‚Šçš„例子則是在MySQL中先建立HibernateTeståQ?/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>

]]>
Hibernate延迟加蝲机制(è½?http://www.aygfsteel.com/lanxin1020/archive/2009/04/11/264987.htmllanxin1020lanxin1020Sat, 11 Apr 2009 02:35:00 GMThttp://www.aygfsteel.com/lanxin1020/archive/2009/04/11/264987.htmlhttp://www.aygfsteel.com/lanxin1020/comments/264987.htmlhttp://www.aygfsteel.com/lanxin1020/archive/2009/04/11/264987.html#Feedback0http://www.aygfsteel.com/lanxin1020/comments/commentRss/264987.htmlhttp://www.aygfsteel.com/lanxin1020/services/trackbacks/264987.html   å»¶è¿ŸåŠ è²æœºåˆ¶æ˜¯äØ“äº†é¿å…ä¸€äº›æ— è°“çš„æ€§èƒ½å¼€é”€è€Œæå‡ºæ¥çš„ï¼Œæ‰€è°“åšg˜qŸåŠ è½½å°±æ˜¯å½“åœ¨çœŸæ­£éœ€è¦æ•°æ®çš„æ—¶å€™ï¼Œæ‰çœŸæ­£æ‰§è¡Œæ•°æ®åŠ è½½æ“ä½œã€‚åœ¨Hibernate中提供了对实体对象的延迟加蝲以及寚w›†åˆçš„延迟加蝲åQŒå¦å¤–在Hibernate3中还提供了对属性的延迟加蝲。下面我们就分别介绍˜q™äº›¿Uç±»çš„åšg˜qŸåŠ è½½çš„¾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属性设¾|®äØ“trueåQŒæ¥å¼€å¯å®žä½“的延迟加蝲ç‰ÒŽ€§ã€‚如果我们运行下面的代码åQ?
User user=(User)session.load(User.class,”1”);åQ?åQ?
System.out.println(user.getName());åQ?åQ?
当运行到(1)处时åQŒHibernateòq¶æ²¡æœ‰å‘起对数据的查询,如果我们此时通过一些调试工å…?比如JBuilder2005çš„Debug工具)åQŒè§‚察此时user对象的内存快照,我们会惊奇的发现åQŒæ­¤æ—¶è¿”回的可能是User$EnhancerByCGLIB$$bede8986¾cÕdž‹çš„å¯¹è±¡ï¼Œè€Œä¸”å…¶å±žæ€§äØ“null,˜q™æ˜¯æ€Žä¹ˆå›žäº‹åQŸè¿˜è®°å¾—前面我曾讲过session.load()æ–ÒŽ³•åQŒä¼š˜q”回实体对象的代理类对象åQŒè¿™é‡Œæ‰€˜q”回的对象类型就是User对象的代理类对象。在Hibernate中通过使用CGLIB,来实现动态构造一个目标对象的代理¾cÕd¯¹è±¡ï¼Œòq¶ä¸”在代理类对象中包含目标对象的所有属性和æ–ÒŽ³•åQŒè€Œä¸”所有属性均被赋å€égØ“null。通过调试器显½Cºçš„内存快照åQŒæˆ‘们可以看出此时真正的User对象åQŒæ˜¯åŒ…含在代理对象的CGLIB$CALBACK_0.target属性中åQŒå½“代码˜qè¡ŒåˆŽÍ¼ˆ2åQ‰å¤„æ—Óž¼Œæ­¤æ—¶è°ƒç”¨user.getName()æ–ÒŽ³•åQŒè¿™æ—‰™€šè¿‡CGLIB赋予的回调机åˆÓž¼Œå®žé™…上调用CGLIB$CALBACK_0.getName()æ–ÒŽ³•åQŒå½“调用该方法时åQŒHibernate会首先检查CGLIB$CALBACK_0.targetå±žæ€§æ˜¯å¦äØ“nullåQŒå¦‚果不为空åQŒåˆ™è°ƒç”¨ç›®æ ‡å¯¹è±¡çš„getNameæ–ÒŽ³•åQŒå¦‚æžœäØ“½Iºï¼Œåˆ™ä¼šå‘è“v数据库查询,生成¾cÖM¼¼˜q™æ ·çš„SQL语句åQšselect * from user where id=’1’;来查询数据,òq¶æž„造目标对象,òq¶ä¸”ž®†å®ƒèµ‹å€¼åˆ°CGLIB$CALBACK_0.target属性中ã€?
   ˜q™æ ·åQŒé€šè¿‡ä¸€ä¸ªä¸­é—´ä»£ç†å¯¹è±¡ï¼ŒHibernate实现了实体的延迟加蝲åQŒåªæœ‰å½“用户真正发è“v获得实体对象属性的动作æ—Óž¼Œæ‰çœŸæ­£ä¼šå‘è“v数据库查询操作。所以实体的延迟加蝲是用通过中间代理¾cÕd®Œæˆçš„åQŒæ‰€ä»¥åªæœ‰session.load()æ–ÒŽ³•才会利用实体延迟加蝲åQŒå› ä¸ºåªæœ‰session.load()æ–ÒŽ³•才会˜q”回实体¾cȝš„代理¾cÕd¯¹è±¡ã€?
Bã€?nbsp;       集合¾cÕdž‹çš„åšg˜qŸåŠ è½½ï¼š
在Hibernateçš„åšg˜qŸåŠ è½½æœºåˆ¶ä¸­åQŒé’ˆå¯šw›†åˆç±»åž‹çš„应用åQŒæ„ä¹‰æ˜¯æœ€ä¸ºé‡å¤§çš„åQŒå› ä¸ø™¿™æœ‰å¯èƒ½ä‹É性能得到大幅度的提高åQŒäؓ此Hibernate˜q›è¡Œäº†å¤§é‡çš„努力åQŒå…¶ä¸­åŒ…括对JDK Collection的独立实玎ͼŒæˆ‘们在一对多兌™”中,定义的用来容¾U›_…³è”对象的Set集合åQŒåƈ不是java.util.Set¾cÕdž‹æˆ–其子类型,而是net.sf.hibernate.collection.Set¾cÕdž‹åQŒé€šè¿‡ä½¿ç”¨è‡ªå®šä¹‰é›†åˆç±»çš„实玎ͼŒHibernateå®žçŽ°äº†é›†åˆç±»åž‹çš„å»¶è¿ŸåŠ è²ã€‚äØ“äº†å¯¹é›†åˆ¾cÕdž‹ä½¿ç”¨å»¶è¿ŸåŠ è²å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中对集合¾cÕdž‹˜q›è¡Œ¾~“å­˜æ—Óž¼Œæ˜¯åˆ†ä¸¤éƒ¨åˆ†è¿›è¡Œç¼“存的åQŒé¦–先缓存集合中所有实体的id列表åQŒç„¶åŽç¼“存实体对象,˜q™äº›å®žä½“对象的id列表åQŒå°±æ˜¯æ‰€è°“的数据索引。当查找数据索引æ—Óž¼Œå¦‚果没有扑ֈ°å¯¹åº”的数据烦引,˜q™æ—¶ž®×ƒ¼šä¸€æ¡select SQL的执行,获得½W¦åˆæ¡äšg的数据,òq¶æž„造实体对象集合和数据索引åQŒç„¶åŽè¿”回实体对象的集合åQŒåƈ且将实体对象和数据烦引纳入Hibernate的缓存之中。另一斚w¢åQŒå¦‚果找到对应的数据索引åQŒåˆ™ä»Žæ•°æ®çƒ¦å¼•中取出id列表åQŒç„¶åŽæ ¹æ®id在缓存中查找对应的实体,如果扑ֈ°ž®×ƒ»Ž¾~“存中返回,如果没有扑ֈ°åQŒåœ¨å‘è“vselect SQL查询。在˜q™é‡Œæˆ‘们看出了另外一个问题,˜q™ä¸ªé—®é¢˜å¯èƒ½ä¼šå¯¹æ€§èƒ½äº§ç”Ÿå½±å“åQŒè¿™ž®±æ˜¯é›†åˆ¾cÕdž‹çš„缓存策略。如果我们如下配¾|®é›†åˆç±»åž‹ï¼š
<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ç­–略来配置集合¾cÕdž‹åQŒHibernatež®†åªä¼šå¯¹æ•°æ®ç´¢å¼•˜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Œä¼šå¾—到¾cÖM¼¼ä¸‹é¢çš„输出:
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¬äºŒ‹Æ¡å†‹Æ¡åŠ è½½å®žä½“æ—¶åQŒHibernate扑ֈ°äº†å¯¹åº”实体的数据索引å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会对集合¾cÕdž‹ä¸­çš„实体也进行缓存,如果æ ÒŽ®˜q™ä¸ªé…ç½®å†æ¬¡˜qè¡Œä¸Šé¢çš„代码,ž®†ä¼šå¾—到¾cÖM¼¼å¦‚下的输出:
Select * from user where id=’1’;
Select * from address where user_id=’1’;
Tianjin
Dalian
Second query……
Tianjin
Dalian
˜q™æ—¶ž®†ä¸ä¼šå†æœ‰æ ¹æ®æ•°æ®çƒ¦å¼•进行查询的SQL语句åQŒå› ä¸ºæ­¤æ—¶å¯ä»¥ç›´æŽ¥ä»Ž¾~“存中获得集合类型中存放的实体对象ã€?
Cã€?nbsp;      属性åšg˜qŸåŠ è½½ï¼š
  在Hibernate3中,引入了一¿Uæ–°çš„特性——属性的延迟加蝲åQŒè¿™ä¸ªæœºåˆ¶åˆä¸ø™Ž·å–高性能查询提供了有力的工具。在前面我们讲大数据对象è¯Õd–æ—Óž¼Œåœ¨User对象中有一个resume字段åQŒè¯¥å­—段是一个java.sql.Clob¾cÕdž‹åQŒåŒ…含了用户的简历信息,当我们加载该对象æ—Óž¼Œæˆ‘们不得不每一‹Æ¡éƒ½è¦åŠ è½½è¿™ä¸ªå­—ŒDµï¼Œè€Œä¸è®ºæˆ‘们是否真的需要它åQŒè€Œä¸”˜q™ç§å¤§æ•°æ®å¯¹è±¡çš„è¯Õd–本èín会带来很大的性能开销。在Hibernate2中,我们只有通过我们前面讲过的面性能的粒度细分,来分解User¾c»ï¼Œæ¥è§£å†Œ™¿™ä¸ªé—®é¢˜ï¼ˆè¯·å‚ç…§é‚£ä¸€èŠ‚çš„è®ø™¿°åQ‰ï¼Œä½†æ˜¯åœ¨Hibernate3中,我们可以通过属性åšg˜qŸåŠ è½½æœºåˆÓž¼Œæ¥ä‹É我们获得只有当我们真正需要操作这个字Œ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Œä‹É用了¾cÕd¢žå¼ºå™¨æ¥å¯¹å®žä½“¾cȝš„Classæ–‡äšg˜q›è¡Œå¼ºåŒ–处理åQŒé€šè¿‡å¢žå¼ºå™¨çš„增强åQŒå°†CGLIB的回调机刉™€»è¾‘åQŒåŠ å…¥å®žä½“ç±»åQŒè¿™é‡Œæˆ‘们可以看出属性的延迟加蝲åQŒè¿˜æ˜¯é€šè¿‡CGLIB来实现的。CGLIB是Apache的一个开源工½E‹ï¼Œ˜q™ä¸ª¾cÕdº“可以操纵java¾cȝš„字节码,æ ÒŽ®å­—节码来动态构造符合要求的¾cÕd¯¹è±¡ã€‚根据上面的配置我们˜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Œä¼šç”Ÿæˆ¾cÖM¼¼å¦‚下的SQL语句åQ?
Select id,age,name from user where name=’zx’;
˜q™æ—¶Hibernate会检索User实体中所有非延迟加蝲属性对应的字段数据åQŒå½“执行åˆ?2)处时åQŒä¼šç”Ÿæˆ¾cÖM¼¼å¦‚下的SQL语句åQ?
Select resume from user where id=’1’;
˜q™æ—¶ä¼šå‘起对resume字段数据真正的读取操作ã€?


]]>
Hibernate¾~“存机制åQˆè{åQ?/title><link>http://www.aygfsteel.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://www.aygfsteel.com/lanxin1020/archive/2009/04/11/264983.html</guid><wfw:comment>http://www.aygfsteel.com/lanxin1020/comments/264983.html</wfw:comment><comments>http://www.aygfsteel.com/lanxin1020/archive/2009/04/11/264983.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/lanxin1020/comments/commentRss/264983.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/lanxin1020/services/trackbacks/264983.html</trackback:ping><description><![CDATA[1.1.1.         基本的缓存原ç?<br /> Hibernate¾~“å­˜åˆ†äØ“äºŒçñ”åQŒç¬¬ä¸€¾U§å­˜æ”¾äºŽsession中称ä¸ÞZ¸€¾U§ç¼“存,默认带有且不能卸载ã€?<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šæ­¤3¿Uæ–¹å¼çš„æŸ¥è¯¢é€Ÿåº¦æ˜¯ä¾‹Æ¡é™ä½?<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å†…éƒ¨æ•°æ®çŠ¶æ€åŒæ­¥ã€‚åÆˆéžæ˜¯hibernateä¸ÞZº†å¤§å¹…提高¾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查询æ—Óž¼ŒiterateåQˆï¼‰æ–ÒŽ³•å…ähœ‰è‘—名çš?“n+1”‹Æ¡æŸ¥è¯¢çš„问题åQŒä¹Ÿž®±æ˜¯è¯´åœ¨½W¬ä¸€‹Æ¡æŸ¥è¯¢æ—¶ <br /> <br /> iterateæ–ÒŽ³•会执行满­‘Ïx¡ä»¶çš„æŸ¥è¯¢¾l“果数再加一‹Æ¡ï¼ˆn+1åQ‰çš„æŸ¥è¯¢ã€‚但是此问题只存在于½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 /> 另外åQŒhibernate会自行维护二¾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Œå¦‚果你使用了JDBC¾l•过hibernate直接执行å¯ÒŽ•°æ®åº“的操作。此æ—Óž¼ŒHibernate不会/也不可能自行 <br /> <br /> 感知到数据库被进行的变化改动åQŒä¹Ÿž®×ƒ¸èƒ½å†ä¿è¯¾~“存中数据的有效性!åQ?<br /> <br /> <br /> <br /> ˜q™ä¹Ÿæ˜¯æ‰€æœ‰çš„ORM产品共同å…ähœ‰çš„问题。幸˜qçš„æ˜¯ï¼ŒHibernate为我们暴露了Cache的清除方法,˜q™ç»™æˆ‘们 <br /> <br /> 提供了一个手动保证数据有效性的æœÞZ¼šåQï¼ <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://www.aygfsteel.com/lanxin1020/aggbug/264983.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/lanxin1020/" target="_blank">lanxin1020</a> 2009-04-11 10:24 <a href="http://www.aygfsteel.com/lanxin1020/archive/2009/04/11/264983.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate ¾~“存机制(è½?http://www.aygfsteel.com/lanxin1020/archive/2009/04/11/264973.htmllanxin1020lanxin1020Sat, 11 Apr 2009 02:18:00 GMThttp://www.aygfsteel.com/lanxin1020/archive/2009/04/11/264973.htmlhttp://www.aygfsteel.com/lanxin1020/comments/264973.htmlhttp://www.aygfsteel.com/lanxin1020/archive/2009/04/11/264973.html#Feedback0http://www.aygfsteel.com/lanxin1020/comments/commentRss/264973.htmlhttp://www.aygfsteel.com/lanxin1020/services/trackbacks/264973.html¾~“存是介于应用程序和物理数据源之é—ß_¼Œå…¶ä½œç”¨æ˜¯ä¸ÞZº†é™ä½Žåº”用½E‹åºå¯¹ç‰©ç†æ•°æ®æºè®‰K—®çš„频‹Æ¡ï¼Œä»Žè€Œæé«˜äº†åº”用的运行性能。缓存内的数据是对物理数据源中的数据的复åˆÓž¼Œåº”用½E‹åºåœ¨è¿è¡Œæ—¶ä»Žç¼“存读写数据,在特定的时刻或事件会同步¾~“存和物理数据源的数据ã€?

  ¾~“存的介质一般是内存åQŒæ‰€ä»¥è¯»å†™é€Ÿåº¦å¾ˆå¿«ã€‚但如果¾~“存中存攄¡š„数据量非常大æ—Óž¼Œä¹Ÿä¼šç”¨ç¡¬ç›˜ä½œä¸ºç¼“存介质。缓存的实现不仅仅要考虑存储的介质,˜q˜è¦è€ƒè™‘到管理缓存的òq¶å‘讉K—®å’Œç¼“存数据的生命周期ã€?

  Hibernate的缓存包括Session的缓存和SessionFactory的缓存,其中SessionFactoryçš„ç¼“å­˜åˆå¯ä»¥åˆ†äØ“ä¸¤ç±»åQšå†…¾|®ç¼“存和外置¾~“存。Session的缓存是内置的,不能被卸载,也被¿UîCØ“Hibernate的第一¾U§ç¼“存。SessionFactory的内¾|®ç¼“存和Session的缓存在实现方式上比较相ä¼û|¼Œå‰è€…是SessionFactory对象的一些集合属性包含的数据åQŒåŽè€…是指Session的一些集合属性包含的数据。SessionFactory的内¾|®ç¼“存中存放了映ž®„元数据和预定义SQL语句åQŒæ˜ ž®„元数据是映ž®„文件中数据的拷贝,而预定义SQL语句是在Hibernate初始化阶ŒD‰| ¹æ®æ˜ ž®„元数据推导出来åQŒSessionFactory的内¾|®ç¼“存是只读的,应用½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Œæ‰€ä»¥å­˜æ”„¡š„介质可以是内存或¼‹¬ç›˜ã€‚缓存内的数据既可以是相互关联的对象形式也可以是对象的松散数据åŞ式。松散的对象数据形式有点¾cÖM¼¼äºŽå¯¹è±¡çš„序列化数据,但是对象分解为松散的½Ž—法比对象序列化的算法要求更快ã€?

  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™ç§éš”离¾cÕdž‹åQŒå› ä¸ºå®ƒå¯ä»¥é˜²æ­¢è„è¯»å’Œä¸å¯é‡å¤è¯»˜q™ç±»çš„åÆˆå‘é—®é¢˜ã€?

  è¯Õd†™åž‹ï¼šæä¾›äº†Read Committed事务隔离¾U§åˆ«ã€‚仅仅在非集¾Ÿ¤çš„环境中适用。对于经常被è¯ÖM½†å¾ˆå°‘修改的数据,可以采用˜q™ç§éš”离¾cÕdž‹åQŒå› ä¸ºå®ƒå¯ä»¥é˜²æ­¢è„è¯»˜q™ç±»çš„åÆˆå‘é—®é¢˜ã€?

ã€€ã€€éžä¸¥æ ÆD¯»å†™åž‹åQšä¸ä¿è¯¾~“å­˜ä¸Žæ•°æ®åº“ä¸­æ•°æ®çš„ä¸€è‡´æ€§ã€‚å¦‚æžœå­˜åœ¨ä¸¤ä¸ªäº‹åŠ¡åŒæ—¶è®¿é—®ç¼“å­˜ä¸­ç›¸åŒæ•°æ®çš„å¯èƒ½ï¼Œå¿…é¡»ä¸ø™¯¥æ•°æ®é…ç½®ä¸€ä¸ªå¾ˆçŸ­çš„æ•°æ®˜q‡æœŸæ—‰™—´åQŒä»Žè€Œå°½é‡é¿å…è„è¯…R€‚对于极ž®‘被修改åQŒåƈ且允许偶ž®”脏è¯Èš„数据åQŒå¯ä»¥é‡‡ç”¨è¿™¿Uåƈ发访问策略ã€?

  只读型:对于从来不会修改的数据,如参考数据,可以使用˜q™ç§òq¶å‘讉K—®½{–ç•¥ã€?

ã€€ã€€äº‹åŠ¡åž‹åÆˆå‘è®¿é—®ç­–ç•¥æ˜¯äº‹åŠ¡éš”ç¦»¾U§åˆ«æœ€é«˜ï¼Œåªè¯»åž‹çš„隔离¾U§åˆ«æœ€ä½Žã€‚事务隔¼›Èñ”别越高,òq¶å‘性能ž®Þp¶Šä½Žã€?

]]>
Hibernate 体系¾l“构与工作原ç?è½?http://www.aygfsteel.com/lanxin1020/archive/2009/04/09/264745.htmllanxin1020lanxin1020Thu, 09 Apr 2009 15:54:00 GMThttp://www.aygfsteel.com/lanxin1020/archive/2009/04/09/264745.htmlhttp://www.aygfsteel.com/lanxin1020/comments/264745.htmlhttp://www.aygfsteel.com/lanxin1020/archive/2009/04/09/264745.html#Feedback0http://www.aygfsteel.com/lanxin1020/comments/commentRss/264745.htmlhttp://www.aygfsteel.com/lanxin1020/services/trackbacks/264745.html1.Hibernate 的初始化.
è¯Õd–Hibernate 的配¾|®ä¿¡æ?〉创建Session Factory
1)创徏Configeration¾cȝš„实例ã€?br /> 它的构造方法:ž®†é…¾|®ä¿¡æ?Hibernate config.xml)è¯Õd…¥åˆ°å†…å­˜ã€?br /> 一个Configeration 实例代表Hibernate 所有Java¾cÕdˆ°Sql数据库映ž®„的集合ã€?br /> 2)创徏SessionFactory实例
把Configeration 对象中的所有配¾|®ä¿¡æ¯æ‹·è´åˆ°SessionFactory的缓存中ã€?br /> SessionFactory的实例代表一个数据库存储员源åQŒåˆ›å»ºåŽä¸å†ä¸ŽConfigeration 对象兌™”ã€?br /> ¾~“å­˜(cache):指Java对象的属æ€?通常是一些集合类型的属性-åQå ç”¨å†…存空间ã€?br />      SessionFactory的缓存中åQšHibernate 配置信息。OR映射元数据ã€?br /> ¾~“å­˜åQå¤§åQšé‡é‡çñ”对象 ž®ï¼šè½»é‡¾U§å¯¹è±?br /> 3)调用SessionFactory创徏Session的方æ³?br /> 1】用戯‚‡ªè¡Œæä¾›JDBC˜qžæŽ¥ã€?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>

]]>
Hibernate 的原理与配置(�http://www.aygfsteel.com/lanxin1020/archive/2009/04/09/264744.htmllanxin1020lanxin1020Thu, 09 Apr 2009 15:50:00 GMThttp://www.aygfsteel.com/lanxin1020/archive/2009/04/09/264744.htmlhttp://www.aygfsteel.com/lanxin1020/comments/264744.htmlhttp://www.aygfsteel.com/lanxin1020/archive/2009/04/09/264744.html#Feedback0http://www.aygfsteel.com/lanxin1020/comments/commentRss/264744.htmlhttp://www.aygfsteel.com/lanxin1020/services/trackbacks/264744.html
  看完本文后,我相信你对什么是ORMåQˆå¯¹åƒ?关系映射åQ‰ä»¥åŠå®ƒçš„优点会有一个深åˆÈš„认识åQŒæˆ‘们先通过一个简单的例子开始来展现它的威力ã€?

  正如一些传¾lŸçš„¾lå…¸è®¡ç®—机文章大都会通过一ä¸?#8220;hello,world”çš„ä¾‹å­å¼€å§‹è®²è§£ä¸€æ øP¼Œæˆ‘们也不例外åQŒæˆ‘们也ž®†ä»Žä¸€ä¸ªç›¸å¯¹ç®€å•的例子来阐˜q°Hibernate的开发方法,但如果要真正阐述Hibernate的一些重要思想åQŒä»…仅靠在屏òq•上打印一些字½W¦æ˜¯˜qœè¿œä¸å¤Ÿçš„,在我们的½CÞZ¾‹½E‹åºä¸­ï¼Œæˆ‘们ž®†åˆ›å»ÞZ¸€äº›å¯¹è±¡ï¼Œòq¶å°†å…¶ä¿å­˜åœ¨æ•°æ®åº“中åQŒç„¶åŽå¯¹å®ƒä»¬˜q›è¡Œæ›´æ–°å’ŒæŸ¥è¯¢ã€?

ã€€ã€€é˜…è¯»å¯ÆDˆª

  “Hello World”“Hello world”½CÞZ¾‹½E‹åºè®©æ‚¨å¯¹Hibernate有一个简单的认识ã€?
  理解Hibernate的架构介¾lHibernate接口的主要功能ã€?
  核心接口Hibernateæœ?个核心接口,通过˜q™å‡ ä¸ªæŽ¥å£å¼€å‘äh员可以存储和获得持久对象åQŒåƈ且能够进行事务控åˆ?
  一个重要的术语åQšTypeType是Hibernate发明者发明的一个术语,它在整个构架中是一个非常基¼‹€ã€æœ‰ç€å¼ºå¤§åŠŸèƒ½çš„å…ƒç´ ï¼Œä¸€ä¸ªType对象能将一个Java¾cÕdž‹æ˜ å°„到数据库中一个表的字ŒDµä¸­åŽ…R€?
  ½{–略接口Hibernate与某些其它开源èÊY件不同的˜q˜æœ‰ä¸€ç‚¹â€•―高度的可扩展性,˜q™é€šè¿‡å®ƒçš„内置½{–略机制来实现ã€?
  基础配置Hibernate可以配置成可在ä“Q何Java环境中运行,一般说来,它通常被用åœ?åQ?层的C/S模式的项目中åQŒåƈ被部¾|²åœ¨æœåŠ¡ç«¯ã€?
  创徏一个SessionFactory对象要创å»ÞZ¸€ä¸ªSessionFactory对象åQŒå¿…™åÕdœ¨Hibernate初始化时创徏一个Configuration¾cȝš„实例åQŒåƈž®†å·²å†™å¥½çš„æ˜ ž®„文件交由它处理ã€?

  “Hello World”

  Hibernate应用½E‹åºå®šä¹‰äº†ä¸€äº›æŒä¹…ç±»åQŒåƈ且定义了˜q™äº›¾cÖM¸Žæ•°æ®åº“表格的映射关系。在我们˜q™ä¸ª“Hello world”½CÞZ¾‹½E‹åºä¸­åŒ…含了一个类和一个映ž®„文件。让我们看看˜q™ä¸ª½Ž€å•的持久¾cÕdŒ…含有一些什么?映射文äš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;
  }
  }

  Message¾cÀLœ‰ä¸‰ä¸ªå±žæ€§ï¼šMessageçš„id 、消息正文、以及一个指向下一条消息的指针。其中id属性让我们的应用程序能够唯一的识别这条消息,通常它等同于数据库中的主键,如果多个Message¾cȝš„实例对象拥有相同的idåQŒé‚£å®ƒä»¬ä»£è¡¨æ•°æ®åº“某个表的同一个记录。在˜q™é‡Œæˆ‘ä»¬é€‰æ‹©äº†é•¿æ•´åž‹ä½œäØ“æˆ‘ä»¬çš„idå€û|¼Œä½†è¿™ä¸æ˜¯å¿…需的。Hibernate允许我们使用ä»ÀL„çš„ç±»åž‹æ¥ä½œäØ“å¯¹è±¡çš„idå€û|¼Œåœ¨åŽé¢æˆ‘们会å¯ÒŽ­¤ä½œè¯¦¾l†æ˜q°ã€?

  你可能注意到Message¾cȝš„代码¾cÖM¼¼äºŽJavaBean的代码风æ û|¼Œòq¶ä¸”它有一个没有参数的构造函敎ͼŒåœ¨æˆ‘们以后的代码中我ž®†ç‘ô¾l­ä‹É用这¿Ué£Žæ ¼æ¥¾~–写持久¾cȝš„代码ã€?

  Hibernate会自动管理Message¾cȝš„实例åQŒåƈ通过内部机制使其持久化,但实际上Message对象òq¶æ²¡æœ‰å®žçŽîC“Q何关于Hibernate的类或接口,因此我们也可以将它作ä¸ÞZ¸€ä¸ªæ™®é€šçš„Java¾cÀL¥ä½¿ç”¨åQ?

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

  以上˜q™æ®µä»£ç æ­£æ˜¯æˆ‘们所期望的结果:它打å?#8220;hello world”到屏òq•上。但˜q™åƈ不是我们的最¾lˆç›®æ ‡ï¼›å®žé™…上Hibernate与诸如EJB容器˜q™æ ·çš„环境在持久层实现的方式上有很大的不同。我们的持久¾c?Message¾c?可以用在与容器无关的环境中,不像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自己定义的查询语­a€åQŒå…¨¿U°å«Hibernate Query Language(HQL)。通俗地讲HQL与SQL的关¾pÕd·®ä¸å¤šž®±æ˜¯æ–¹è¨€ä¸Žæ™®é€šè¯ä¹‹é—´çš„å…³¾p»ï¼Œå’‹ä¸€çœ‹ï¼Œä½ ä¼šè§‰å¾—它有点类ä¼égºŽSQL语句。其实在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

  如果你以前没有ORMåQˆå¯¹è±¡ï¼å…³ç³»æ˜ å°„åQ‰çš„开发经验,那你可能惛_œ¨ä»£ç çš„æŸä¸ªåœ°æ–¹åŽ»å¯ÀL‰¾˜q™æ®µSQL语句åQŒä½†åœ¨Hibernate中你可能会失望:它根本不存在åQæ‰€æœ‰å°±SQL语句都是Hibernate动态生成的ã€?

  也许你会觉得˜q˜ç¼ºç‚¹ä»€ä¹ˆï¼Œå¯¹ï¼ä»…凭以上代码Hibernate是无法将我们的Message¾cÀLŒä¹…化的。我们还需要一些更多的信息åQŒè¿™ž®±æ˜¯æ˜ å°„定义表!˜q™ä¸ªè¡¨åœ¨Hibernate中是以XML格式来体现的åQŒå®ƒå®šä¹‰äº†Message¾cȝš„属性是怎样与数据库中的MESSAGES表的字段˜q›è¡Œä¸€ä¸€å¯¹åº”的,列表2是这个示例程序的映射配置文äšg清单åQ?

  列表2åQšç¤ºä¾‹ç¨‹åºçš„对象åQå…³¾pÀL˜ ž®„表

  å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?
  åQœhibernate-mappingåQ?
  åQœclass name="hello.Message" table="MESSAGES"åQ?
  åQœid name="id" column="MESSAGE_ID"åQ?
  åQœgenerator class="increment"/åQ?
  åQ?idåQ?
  åQœproperty name="text" column="MESSAGE_TEXT"/åQ?
  åQœmany-to-one name="nextMessage" cascade="all" column="NEXT_MESSAGE_ID"/åQ?
  åQ?classåQ?
  åQ?hibernate-mappingåQ?

  以上˜q™ä¸ªæ–‡æ¡£å‘Šè¯‰Hibernate怎样ž®†Message¾cÀL˜ ž®„到MESSAGES表中åQŒå…¶ä¸­Message¾cȝš„id属性与表的MESSAGE_ID字段对应åQŒtext属性与表的MESSAGE_TEXT字段对应åQŒnextMessage属性是一个多对一的关¾p»ï¼Œå®ƒä¸Žè¡¨ä¸­çš„NEXT_MESSAGE_ID相对应ã€?

  相对于有些开源项目来è¯ß_¼ŒHibernate的配¾|®æ–‡ä»¶å…¶å®žæ˜¯å¾ˆå®¹æ˜“理解的。你可以è½ÀL¾åœîC¿®æ”¹ä¸Ž¾l´æŠ¤å®ƒã€‚只要你定义好了持久¾cÖM¸Žæ•°æ®åº“中表字Œ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™æ®µä»£ç åœ¨è°ƒç”¨æ—¶åQŒHibernate内部自动生成如下的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;åQŒHibernate的这个特色ä‹É得当我们修改一个持久对象的属性后åQŒä¸å¿…显式地通知HibernateåŽÕd°†å®ƒåœ¨æ•°æ®åº“中˜q›è¡Œæ›´æ–°ã€‚同æ ïLš„åQŒå½“½W¬ä¸€ä¸ªMessage对象调用setNextMessage()æ–ÒŽ³•ž®†ç¬¬äºŒä¸ªMessageå¯¹è±¡ä½œäØ“å®ƒçš„ä¸‹ä¸€æ¡æ¶ˆæ¯çš„å¼•ç”¨æ—Óž¼Œ½W¬äºŒæ¡æ¶ˆæ¯ä¼šæ— éœ€è°ƒç”¨save()æ–ÒŽ³•åQŒä¾¿å¯ä»¥è‡ªåЍåœîC¿å­˜åœ¨æ•°æ®åº“中。这¿Uç‰¹è‰²è¢«¿UîCØ““¾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”½CÞZ¾‹½E‹åºçŽ°åœ¨ä»‹ç»å®Œæ¯•ã€‚æˆ‘ä»¬æ€È®—对Hibernate有了一个简单的认识åQŒä¸‹é¢æˆ‘们将回过头来åQŒå¯¹Hibernate的主要API调用作一下简要的介绍åQ?
  

  理解Hibernate的架�/strong>

  当你想用Hibernate开发自å·Þqš„åŸÞZºŽæŒä¹…层的应用æ—Óž¼Œ½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Œå…¸åž‹çš„代表有Configuration¾c…R€?

  · 回调(Callback)接口。它允许应用½E‹åºèƒ½å¯¹ä¸€äº›äº‹ä»¶çš„发生作出相应的操作,例如Interceptor、Lifecycleå’ŒValidatable都是˜q™ä¸€¾cÀLŽ¥å£ã€?

  · 一些可以用来扩展Hibernate的映ž®„机制的接口åQŒä¾‹å¦‚UserType、CompositeUserTypeå’ŒIdentifierGenerator。这些接口可ç”Þq”¨æˆïL¨‹åºæ¥å®žçްåQˆå¦‚果有必要åQ‰ã€?

  Hibernate使用了J2EE架构中的如下技术:JDBC、JTA、JNDI。其中JDBC是一个支持关¾pÀL•°æ®åº“操作的一个基¼‹€å±‚;它与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¶åŠæ—¶åˆ·æ–°æ•°æ®åº“。我们有时也¿U°Session是一个持久层½Ž¡ç†å™¨ï¼Œå› äؓ它包含这一些持久层相关的操作,诸如存储持久对象è‡Ïx•°æ®åº“åQŒä»¥åŠä»Žæ•°æ®åº“从获得它们。请注意åQŒHibernate çš„session不同于JSP应用中的HttpSession。当我们使用session˜q™ä¸ªæœ¯è¯­æ—Óž¼Œæˆ‘们指的是Hibernate中的sessionåQŒè€Œæˆ‘们以后会ž®†HttpSesion对象¿UîCؓ用户sessionã€?

  SessionFactory 接口

  ˜q™é‡Œç”¨åˆ°äº†ä¸€ä¸ªè®¾è®¡æ¨¡å¼â€•―工厂模式,用户½E‹åºä»Žå·¥åŽ‚ç±»SessionFactory中取得Session的实例ã€?

  令你感到奇怪的是SessionFactoryòq¶ä¸æ˜¯è½»é‡çñ”的!实际上它的设计者的意图是让它能在整个应用中å…׃ín。典型地来说åQŒä¸€ä¸ªé¡¹ç›®é€šå¸¸åªéœ€è¦ä¸€ä¸ªSessionFactoryž®±å¤Ÿäº†ï¼Œä½†æ˜¯å½“你的项目要操作多个数据库时åQŒé‚£ä½ å¿…™åÖMؓ每个数据库指定一个SessionFactoryã€?
  SessionFactory在Hibernate中实际è“våˆîCº†ä¸€ä¸ªç¼“冲区的作用,它缓冲了Hibernate自动生成的SQL语句和一些其它的映射数据åQŒè¿˜¾~“冲了一些将来有可能重复利用的数据ã€?

  Configuration 接口

  Configuration接口的作用是对Hibernate˜q›è¡Œé…ç½®åQŒä»¥åŠå¯¹å®ƒè¿›è¡Œå¯åŠ¨ã€‚åœ¨Hibernate的启动过½E‹ä¸­åQŒConfiguration¾cȝš„实例首先定位映射文档的位¾|®ï¼Œè¯Õd–˜q™äº›é…ç½®åQŒç„¶åŽåˆ›å»ÞZ¸€ä¸ªSessionFactory对象ã€?

  虽然Configuration接口在整个Hibernate™å¹ç›®ä¸­åªæ‰®æ¼”着一个很ž®çš„角色åQŒä½†å®ƒæ˜¯å¯åЍhibernate时你所遇到的每一个对象ã€?

  Transaction 接口

  Transaction接口是一个可选的APIåQŒä½ å¯ä»¥é€‰æ‹©ä¸ä‹É用这个接口,取而代之的是Hibernate的设计者自己写的底层事务处理代码ã€?Transaction接口是对实际事务实现的一个抽象,˜q™äº›å®žçŽ°åŒ…æ‹¬JDBC的事务、JTA中的UserTransaction、甚臛_¯ä»¥æ˜¯CORBA事务。之所以这栯‚®¾è®¡æ˜¯èƒ½è®©å¼€å‘者能够ä‹É用一个统一事务的操作界面,使得自己的项目可以在不同的环境和容器之间方便地移倹{€?

  Query和Criteria接口

  Query接口让你方便地对数据库及持久对象˜q›è¡ŒæŸ¥è¯¢åQŒå®ƒå¯ä»¥æœ‰ä¸¤¿Uè¡¨è¾¾æ–¹å¼ï¼šHQL语言或本地数据库的SQL语句。Query¾lå¸¸è¢«ç”¨æ¥ç»‘定查询参数、限制查询记录数量,òq¶æœ€¾lˆæ‰§è¡ŒæŸ¥è¯¢æ“ä½œã€?

  Criteria接口与Query接口非常¾cÖM¼¼åQŒå®ƒå…è®¸ä½ åˆ›å»ºåƈ执行面向对象的标准化查询ã€?

  值得注意的是Query接口也是轻量¾U§çš„åQŒå®ƒä¸èƒ½åœ¨Session之外使用ã€?

  Callback 接口

  当一些有用的事äšg发生时――例如持久对象的载入、存储、删除时åQŒCallback接口会通知HibernateåŽÀLŽ¥æ”¶ä¸€ä¸ªé€šçŸ¥æ¶ˆæ¯ã€‚ä¸€èˆ¬è€Œè¨€åQŒCallback接口在用æˆïL¨‹åºä¸­òq¶ä¸æ˜¯å¿…™åȝš„åQŒä½†ä½ è¦åœ¨ä½ çš„项目中创徏审计日志æ—Óž¼Œä½ å¯èƒ½ä¼šç”¨åˆ°å®ƒã€?

   一个重要的术语åQšType

  Hibernate的设计者们发明了一个术语:TypeåQŒå®ƒåœ¨æ•´ä¸ªæž„架中是一个非常基¼‹€ã€æœ‰ç€å¼ºå¤§åŠŸèƒ½çš„å…ƒç´ ã€‚ä¸€ä¸ªType对象能将一个Java¾cÕdž‹æ˜ å°„到数据库中一个表的字ŒDµä¸­åŽ»ï¼ˆå®žé™…ä¸Šï¼Œå®ƒå¯ä»¥æ˜ ž®„到表的多个字段中去åQ‰ã€‚持久类的所有属性都对应一个type。这¿Uè®¾è®¡æ€æƒ³ä½¿ç”¨Hibernate有着高度的灵‹zÀL€§å’Œæ‰©å±•性ã€?

  Hibernate内置很多type¾cÕdž‹åQŒå‡ ä¹ŽåŒ…括所有的Java基本¾cÕdž‹åQŒä¾‹å¦‚Java.util.Currency、Java.util.calendar、byte[]å’ŒJava.io.Serializableã€?

  不仅如此åQŒHibernate˜q˜æ”¯æŒç”¨æˆ¯‚‡ªå®šä¹‰çš„typeåQŒé€šè¿‡å®žçŽ°æŽ¥å£UserType和接口CompositeUserTypeåQŒä½ å¯ä»¥åŠ å…¥è‡ªå·±çš„type。你可以利用˜q™ç§ç‰¹è‰²è®©ä½ çš„项目中使用自定义的诸如Address、Name˜q™æ ·çš„typeåQŒè¿™æ ·ä½ ž®±å¯ä»¥èŽ·å¾—æ›´å¤§çš„ä¾¿åˆ©åQŒè®©ä½ çš„代码更优雅。自定义type在Hibernate中是一™åÒŽ ¸å¿ƒç‰¹è‰ÔŒ¼Œå®ƒçš„设计者鼓åŠ×ƒ½ å¤šå¤šä½¿ç”¨å®ƒæ¥åˆ›å¾ä¸€ä¸ªçµ‹z…R€ä¼˜é›…çš„™å¹ç›®å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接口)

  Hibernateä¸ÞZ»¥ä¸Šæ‰€åˆ—的机制分别创徏了一个缺省的实现åQŒå› æ­¤å¦‚果你只是要增强它的某个策略的功能的话åQŒåªéœ€½Ž€å•地¾l§æ‰¿˜q™ä¸ª¾cÕd°±å¯ä»¥äº†ï¼Œæ²¡æœ‰å¿…要从头开始写代码ã€?

  以上ž®±æ˜¯Hibernate的一些核心接口,但当我们真正开始用它进行开发时åQŒä½ çš„è„‘‹¹·é‡Œå¯èƒ½æ€ÖM¼šæœ‰ä¸€ä¸ªç–‘问:我是通过什么方式,òq¶ä»Žå“ªé‡Œå–å¾—Session的呢åQŸä»¥ä¸‹æˆ‘们就解答˜q™ä¸ªé—®é¢˜ã€?

  基础配置

  现在回顾一下我们先前的内容åQšæˆ‘ä»¬å†™å‡ÞZº†ä¸€ä¸ªç¤ºä¾‹ç¨‹åºï¼Œòq¶ç®€è¦åœ°è®²è§£äº†Hibernate的一些核心类。但要真正ä‹Éä½ çš„™å¹ç›®˜qè¡Œèµäh¥åQŒè¿˜æœ‰ä¸€ä»¶äº‹å¿…须要做åQšé…¾|®ã€‚Hibernate可以配置成可在ä“Q何Java环境中运行,一般说来,它通常被用åœ?åQ?层的C/S模式的项目中åQŒåƈ被部¾|²åœ¨æœåŠ¡ç«¯ã€‚åœ¨˜q™ç§™å¹ç›®ä¸­ï¼ŒWeb‹¹è§ˆå™¨ã€æˆ–Java GUI½E‹åºå……当者客æˆïL«¯ã€‚å°½½Ž¡æˆ‘们的焦点主要是集中在多层web应用åQŒä½†å®žé™…上在一些基于命令行的应用中也可以ä‹É用Hibernateã€‚åÆˆä¸”ï¼Œå¯¹Hibernate的配¾|®åœ¨ä¸åŒçš„环境下都会不同åQŒHibernate˜qè¡Œåœ¨ä¸¤¿UçŽ¯å¢ƒä¸‹åQšå¯½Ž¡ç†çŽ¯å¢ƒå’Œä¸å¯ç®¡ç†çŽ¯å¢?

  · 可管理环境――这¿UçŽ¯å¢ƒå¯½Ž¡ç†å¦‚下资源åQšæ± èµ„æº½Ž¡ç†åQŒè¯¸å¦‚数据库˜qžæŽ¥æ± å’ŒåQŒè¿˜æœ‰äº‹åŠ¡ç®¡ç†ã€å®‰å…¨å®šä¹‰ã€‚ä¸€äº›å…¸åž‹çš„J2EE服务器(JBoss、Weblogic、WebSphereåQ‰å·²¾lå®žçŽîCº†˜q™äº›ã€?

  · 不可½Ž¡ç†çŽ¯å¢ƒâ€•â€•åªæ˜¯æä¾›äº†ä¸€äº›åŸºæœ¬çš„åŠŸèƒ½åQŒè¯¸å¦‚像Jetty或Tomcat˜q™æ ·çš„servlet容器环境。一个普通的Java桌面应用或命令行½E‹åºä¹Ÿå¯ä»¥è®¤ä¸ºæ˜¯å¤„于˜q™ç§çŽ¯å¢ƒä¸‹ã€‚è¿™¿UçŽ¯å¢ƒä¸èƒ½æä¾›è‡ªåŠ¨äº‹åŠ¡å¤„ç†ã€èµ„æºç®¡ç†æˆ–å®‰å…¨½Ž¡ç†åQŒè¿™äº›éƒ½å¿…须由应用程序自己来定义ã€?

  Hibernate的设计者们ž®†è¿™ä¸¤ç§çŽ¯å¢ƒè®¾è®¡äº†ä¸€ä¸ªç»Ÿä¸€çš„æŠ½è±¡ç•Œé¢ï¼Œå› æ­¤å¯¹äºŽå¼€å‘è€…æ¥è¯´åªæœ‰ä¸€¿UçŽ¯å¢ƒï¼šå¯ç®¡ç†çŽ¯å¢ƒã€‚å¦‚æžœå®žé™…é¡¹ç›®æ˜¯å»ºç«‹åœ¨è¯¸å¦‚Tomcat˜q™ç±»ä¸å¯½Ž¡ç†çš„环境中æ—Óž¼Œé‚£Hibernatež®†ä¼šä½¿ç”¨å®ƒè‡ªå·Þqš„事务处理代码和JDBC˜qžæŽ¥æ± ï¼Œä½¿å…¶å˜äؓ一个可½Ž¡ç†çŽ¯å¢ƒã€?
  对于可管理的环境而言åQŒHibernate会将自己集成在这¿UçŽ¯å¢ƒä¸­ã€‚å¯¹äºŽå¼€å‘è€…è€Œè¨€åQŒä½ æ‰€è¦åšçš„工作非常简单:只需从一个Configuration¾cÖM¸­åˆ›å¾ä¸€ä¸ªSessionFactory¾cÕd°±å¯ä»¥äº†ã€?
   创徏一个SessionFactory对象

  ä¸ÞZº†èƒ½åˆ›å»ÞZ¸€ä¸ªSessionFactory对象åQŒä½ å¿…须在Hibernate初始化时创徏一个Configuration¾cȝš„实例åQŒåƈž®†å·²å†™å¥½çš„æ˜ ž®„æ–‡ä»¶äº¤ç”±å®ƒå¤„ç†ã€‚è¿™æ øP¼ŒConfiguration对象ž®±å¯ä»¥åˆ›å»ÞZ¸€ä¸ªSessionFactory对象åQŒå½“SessionFactory对象创徏成功后,Configuration对象ž®±æ²¡æœ‰ç”¨äº†ï¼Œä½ å¯ä»¥ç®€å•地抛弃它。如下是½CÞZ¾‹ä»£ç åQ?

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

  在以上代码中åQŒMessage.hb.xml˜q™ä¸ªæ˜ å°„æ–‡äšg的位¾|®æ¯”较特ŒDŠï¼Œå®ƒä¸Žå½“前的classpath相关。例如classpath包含当前目录åQŒé‚£åœ¨ä¸Š˜qîC»£ç ä¸­çš„Message.hbm.xml映射文äšgž®±å¯ä»¥ä¿å­˜åœ¨å½“前目录下的hello目录中ã€?

ã€€ã€€ä½œäØ“ä¸€¿Uçº¦å®šï¼ŒHibernate的映ž®„文仉™»˜è®¤ä»¥.htm.xmlä½œäØ“å…¶æ‰©å±•åã€‚å¦ä¸€ä¸ªçº¦å®šæ˜¯åšæŒä¸ºæ¯ä¸€ä¸ªæŒä¹…ç±»å†™ä¸€ä¸ªé…¾|®æ–‡ä»Óž¼Œæƒ³ä¸€æƒ›_¦‚果你ž®†æ‰€æœ‰æŒä¹…类的映ž®„写入一个单独的配置文äšg中的话,那这个配¾|®æ–‡ä»¶è‚¯å®šéžå¸¸åºžå¤§ï¼Œä¸æ˜“¾l´æŠ¤ã€‚但˜q™é‡Œåˆå‡ºçŽîCº†ä¸€ä¸ªæ–°é—®é¢˜åQšå¦‚æžœäØ“æ¯ä¸ª¾cÕd†™ä¸€ä¸ªé…¾|®æ–‡ä»¶çš„话,˜q™ä¹ˆå¤šçš„配置文äšg应该存放在哪里呢åQ?

  Hibernate推荐你将每个映射文äšg保存在与持久¾cȝ›¸åŒçš„目录下,òq¶ä¸”与持久类同名。例如我们第一个示例程序中的Message持久¾cÀL”¾åœ¨helloç›®å½•ä¸‹ï¼Œé‚£ä½ å¿…é¡»åœ¨è¿™ä¸ªç›®å½•ä¸‹å­˜æ”¾åäØ“Message.hbm.xml的映ž®„文件。这样一个持久类都有自己的一个映ž®„æ–‡ä»Óž¼Œé¿å…äº†å‡ºçŽ°åƒstruts™å¹ç›®ä¸­çš„“struts-config.xml地狱”的情å†üc€‚如果你不遵循这¿Uè§„定,那你必须手动地用addResource()æ–ÒŽ³•ž®†ä¸€ä¸ªä¸ªçš„æ˜ ž®„文件蝲入;但你如果遵åó@˜q™ç§è§„定åQŒé‚£ä½ å¯ä»¥æ–¹ä¾¿åœ°ç”¨addClass()æ–ÒŽ³•同时ž®†æŒä¹…类和它的映ž®„文件蝲入,以下是体现这¿Uä¾¿åˆ©æ€§çš„½CÞZ¾‹ä»£ç å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();

  当然åQŒHibernate的映ž®„文件还有很多其它的配置选项åQŒæ¯”如数据库˜qžæŽ¥çš„设定,或是能够改变Hibernate˜qè¡Œæ—¶è¡Œä¸ºçš„一些设定。所有的讄¡½®å¯èƒ½æ˜¯éžå¸¸åºžæ‚çš„åQŒèƒö以让你喘不过气来åQŒä½†æ˜¯ä¸å¿…æ‹…å¿ƒï¼Œå› äØ“Hibernate为绝大多数值都讑֮šäº†ä¸€ä¸ªåˆç†ç¼ºçœå€û|¼Œä½ åªéœ€è¦ä¿®æ”¹è¿™äº›é…¾|®æ–‡ä»¶ä¸­çš„æžž®ä¸€éƒ¨åˆ†å€¹{€?

  你可以通过以下几种方式来修改Hibernate的系¾lŸé…¾|®å‚敎ͼš

  · ž®†ä¸€ä¸ªJava.util.Propertieså®žä¾‹ä½œäØ“å‚æ•°ä¼ ç»™Configuration¾cȝš„setProperties()æ–ÒŽ³•ã€?

  · 在Hibernate启动时用Java –Dproperty=value的方式设¾|®å€¹{€?

  · 在classpath可以扑ֈ°çš„èµ\径下创徏一个名为hibernate.properties的配¾|®æ–‡ä»¶ã€?

  · 在classpath可以扑ֈ°çš„èµ\径下创徏一个名为hibernate.cfg.xml的文ä»Óž¼Œòq¶åœ¨å…Óž¼œpropertyåQžæ ‡½{¾ä¸­å®šä¹‰å±žæ€§å€¹{€?

  以上ž®±æ˜¯å¯¹Hibernate的一个大致介¾lï¼Œå¦‚果你想知道得更多,那本文还是远˜qœä¸å¤Ÿçš„åQŒæˆ‘ž®†é™†¾l­æŽ¨å‡ºæ›´å¤šå…³äºŽHibernate的资料。但有一ç‚ÒŽ˜¯æ¯«æ— ç–‘问的:它的¼‹®æ˜¯ä¸€ä¸ªéžå¸æ€¼˜¿U€çš„æŒä¹…层解决æ–ÒŽ¡ˆåQ?/p>


]]>
Hibernate实体对象的生命周期(转)http://www.aygfsteel.com/lanxin1020/archive/2009/04/08/264425.htmllanxin1020lanxin1020Wed, 08 Apr 2009 04:02:00 GMThttp://www.aygfsteel.com/lanxin1020/archive/2009/04/08/264425.htmlhttp://www.aygfsteel.com/lanxin1020/comments/264425.htmlhttp://www.aygfsteel.com/lanxin1020/archive/2009/04/08/264425.html#Feedback0http://www.aygfsteel.com/lanxin1020/comments/commentRss/264425.htmlhttp://www.aygfsteel.com/lanxin1020/services/trackbacks/264425.htmlHibernate实体对象的生命周æœ?/a> 关键å­? hibernate学习½W”è®°
在用Hibernateçš„æ—¶å€™ï¼Œæ—¶ä¸æ—¶ä¼šå› äØ“æ²¡æœ‰å¤„ç†å¥½å®žä½“å¯¹è±¡çš„çŠ¶æ€è€ŒçŠ¯ä¸€äº›èŽ«åå…¶å¦™çš„å¼‚å¸¸åQŒåœ¨˜q™é‡Œå¯¹å®žä½“对象的各种状态整理一下,希望能有所帮助ã€?

Hibernate实体对象åQŒå³æŒ‡Hibernate O/R影射关系中的域对è±?即O/R中的"O"。在Hibrenate实体对象的生命周期中存在着三中状态,卻I¼š
1åQšè‡ªç”ÞqŠ¶æ€ï¼ˆTransientåQ‰ã€?
2åQšæŒä¹…çŠ¶æ€ï¼ˆPersistentåQ‰ã€?
3åQ𿏏¼›ÈŠ¶æ€ï¼ˆDetachedåQ‰ã€?

1åQšè‡ªç”ÞqŠ¶æ€ï¼ˆTransientåQ?/strong>
自由状态(TransientåQ?/span>,是指实体对象在内存中自由存在åQŒä»–与数据库的记录无兟뀂如åQ?
Java代码
  1. TUser user = new TUser();   
  2. user.setName("MyName");  

˜q™é‡Œçš„user对象只是一个非常普通的java对象åQŒä¸Žæ•°æ®åº“中的记录没有ä“Q何关¾p…R€?

2åQšæŒä¹…çŠ¶æ€ï¼ˆPersistentåQ?/strong>
持久状态(PersistentåQ?/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æ–ÒŽ³•åQŒuser_1对象已经被纳入Hibernate的实体管理容器,处于持久化状   
  11. //æ€?Persistent)åQŒè¿™æ—¶å€™å¯¹user_1对象的ä“Q何修攚wƒ½ž®†è¢«åŒæ­¥åˆ°æ•°æ®åº“中ã€?  
  12.   
  13. tx.commit();   
  14.   
  15. //而user_2仍然才处于自ç”ÞqŠ¶æ€ï¼ˆTransientåQ‰ï¼Œä¸å—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的有效期内ã€?

3åQ𿏏¼›ÈŠ¶æ€ï¼ˆDetachedåQ?/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已经和sessionè„Þq¦»å…³ç³»ã€?/span>  


ç”׃¸Šé¢å¯ä»¥çœ‹åˆ°å®žä½“对象的游离状æ€?/span>是在对象和它所寄宿的Sessionè„Þq¦»å…³ç³»åŽåŞ成的åQŒä½†å¤„于自由状æ€?/span>的实体对象也没有和ä“Q何session有关联,那么他们两者有什么区别呢åQŸå…³é”®çš„ž®±åœ¨æˆ‘们å¯?span style="color: brown">自由状æ€?/span>的实体对象执行了Session.saveæ–ÒŽ³•åQ?
当我们执�
Java代码
  1. TUser user = new TUser();  

æ—Óž¼Œæˆ‘们只是创徏了一个普通的对象åQŒä»–òq¶æ²¡æœ‰å’Œæ•°æ®åº“里的ä“Q何一条记录对应,当我们执è¡?
Session.save以后åQŒHibernatež®×ƒØ“user讄¡½®äº†ä¸€ä¸ªä¸»é”®ï¼Œž®±æ˜¯user.Id属性,通过˜q™ä¸ªå±žæ€§ï¼ŒHibernatež®±æŠŠuser对象和数据库里的记录兌™”èµäh¥åQŒæ‰€ä»?span style="color: brown">自由状æ€?/span>å’?span style="color: brown">游离状æ€?/span>的基本区别就æ˜?处于游离状æ€?/span>的实体对象,在数据库里有对应的记录,因此它可以通过和sessionå…Œ™”å†æ¬¡è½¬äØ“æŒä¹…çŠ¶æ€?/span>ã€?

三种状态的转化
自由状æ€?->持久状态:可以通过Session.savaæ–ÒŽ³•来è{换ã€?
持久状æ€?->游离状态:可以通过Session.closeæ–ÒŽ³•来关闭sessionåQŒèŽ·å–æ¸¸¼›ÈŠ¶æ€çš„对象
持久状æ€?->自由状态:可以通过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ؓ地设¾|®äº†IdåQŒä¹Ÿä¸èƒ½è¯´ä¸€ä¸ªæœ‰ID的实体对象就是一ä¸?span style="color: brown">游离状æ€?/span>的对象ã€?/div>

]]>
Ö÷Õ¾Ö©Öë³ØÄ£°å£º ±±íÕÇø| ÄÏľÁÖÏØ| Çíº£ÊÐ| ½¨ºþÏØ| ÁùÅÌË®ÊÐ| ÈðÀöÊÐ| ÁÙëÔÏØ| ÂåÂ¡ÏØ| ÉÏÁÖÏØ| ÀëµºÇø| º£°²ÏØ| ò£ÉÏÏØ| ÂÞ½­ÏØ| ×ÊÔ´ÏØ| ºº´¨ÊÐ| ºþ¿ÚÏØ| ä¬ÄÏÊÐ| ÐÝÄþÏØ| Ìì¶ëÏØ| ²èÁêÏØ| ÀÖ²ýÊÐ| Ó¦³ÇÊÐ| Ϋ·»ÊÐ| аͶû»¢×óÆì| ³¤ÊÙÇø| Ëç·ÒºÓÊÐ| ÈÄÑôÏØ| ¹ÅÝþÏØ| ¾ÞÂ¹ÏØ| »ªÄþÏØ| ¼ÃÔ´ÊÐ| °ÍÁÖÓÒÆì| À¥Ã÷ÊÐ| ¾«ºÓÏØ| ãôºéÏØ| ¿ÑÀûÏØ| ¹ÅÕÉÏØ| ÓÀÆ½ÏØ| ÖÜÖÁÏØ| À¶ÌïÏØ| ÔªÄ±ÏØ|