锘??xml version="1.0" encoding="utf-8" standalone="yes"?>
榪欓噷鎵涓劇殑渚嬪瓙錛岄兘鏄熀浜庤繖鏍風殑涓涓儏鏅紝Item涓寘鍚湁Images銆?/SPAN>
<set name="images" lazy="true" table="ITEM_IMAGE">
<key column="ITEM_ID"/>
<element type="string" column="FILENAME" not-null="true"/>
</set>
榪欓噷鐨?/SPAN><key>瀹氫箟浜嗗閿?/SPAN>ITEM_ID錛?/SPAN><elememt>鍒欏0鏄庝簡闆嗗悎鐨勫唴閮ㄦ暟鎹厓绱犮?/SPAN><set>瀹氫箟鐨勯泦鍚堜腑涓嶅彲浠ユ湁閲嶅鐨勬暟鎹?/SPAN>
<idbag name="images" lazy="true" table="ITEM_IMAGE">
<collection-id type="long" column="ITEM_IMAGE_ID">
<generator class="sequence"/>
</collection-id>
<key column="ITEM_ID"/>
<element type="string" column="FILENAME" not-null="true"/>
</idbag>
ITEM_IMAGE_ID涓轟富閿紝鑰?/SPAN>ITEM_ID鍒欎負澶栭敭錛?/SPAN><element>鍏冪礌涓嶅彉錛岃繖灝卞厑璁擱泦鍚堜腑鐨勬暟鎹噸澶嶃?/SPAN>
<list name="images" lazy="true" table="ITEM_IMAGE">
<key column="ITEM_ID"/>
<index column="POSITION"/>
<element type="string" column="FILENAME" not-null="true"/>
</list>
榪欓噷涓?/SPAN>ITEM_IMAGE琛ㄦ坊鍔犱簡index錛屾暣涓〃鐨勪富閿槸ITEM_ID鍜?/SPAN>POSITION鏋勬垚鐨勫鍚堜富閿紝瀹冨厑璁擱泦鍚堜腑鐨勬暟鎹牴鎹?/SPAN>POSITION榪涜鎺掑簭銆?/SPAN>
<map name="images"
lazy="true"
table="ITEM_IMAGE"
sort="natural">
<key column="ITEM_ID"/>
<index column="IMAGE_NAME" type="string"/>
<element type="string" column="FILENAME" not-null="true"/>
</map>
榪欓噷涓?/SPAN>ITEM_IMAGE琛ㄦ坊鍔犱簡index錛屾暣涓〃鐨勪富閿槸ITEM_ID鍜?/SPAN>POSITION鏋勬垚鐨勫鍚堜富閿紝瀹冨厑璁擱泦鍚堜腑鐨勬暟鎹牴鎹?/SPAN>sort鎸囧畾鐨勫唴瀹硅繘琛屾帓搴忥紝榪欓噷鍏佽鐢ㄦ埛瀵?/SPAN>sort榪涜瀹氬埗銆?/SPAN>
<map name="images"
lazy="true"
table="ITEM_IMAGE"
order-by="IMAGE_NAME asc">
<key column="ITEM_ID"/>
<index column="IMAGE_NAME" type="string"/>
<element type="string" column="FILENAME" not-null="true"/>
</map>
榪欓噷閲囩敤鐨勬槸orbder-by錛屾敞鎰?/SPAN>sort鍜?/SPAN>order-by鐨勫尯鍒?/SPAN>Sort鏄湪鍐呭瓨涓嬌鐢?/SPAN>comparator榪涜鎺掑簭錛岃?/SPAN>order-by鍒欐槸鍦ㄦ暟鎹簱涓嬌鐢?/SPAN>SQL璇彞榪涜鎺掑簭銆?/SPAN>
<set name="images"
lazy="true"
table="ITEM_IMAGE"
order-by="IMAGE_NAME asc">
<key column="ITEM_ID"/>
<composite-element class="Image">
<property name="name" column="IMAGE_NAME" not-null="true"/>
<property name="filename" column="FILENAME" not-null="true"/>
<property name="sizeX" column="SIZEX" not-null="true"/>
<property name="sizeY" column="SIZEY" not-null="true"/>
</composite-element>
</set>
榪欓噷瀹氫箟浜嗕竴涓柊鐨?/SPAN>Image綾伙紝瀹冧笉鏄疄浣撶被(entity class)錛岃屾槸涓涓畝鍗曠殑鍊肩被鍨?/SPAN>(value type)錛屼粎浠呮槸鐖跺疄浣撶殑涓涓?/SPAN>component錛屽叾鐢熷懡鍛ㄦ湡瀹屽叏鐢卞寘鍚叾鐨勭埗瀹炰綋 (parent entity) ITEM鎺у埗銆傝繖閲?/SPAN>Image綾諱腑鍖呭惈鏈夋暟鎹?/SPAN>ITEM_ID銆?/SPAN> IMAGE_NAME銆?/SPAN>FILENAME銆?/SPAN>SIZEX銆佸拰SIZEY銆?/SPAN>
<set name="images"
lazy="true"
table="ITEM_IMAGE"
order-by="IMAGE_NAME asc">
<key column="ITEM_ID"/>
<composite-element class="Image">
<parent name="item"/>
<property name="name" column="IMAGE_NAME" not-null="true"/>
<property name="filename" column="FILENAME" not-null="true"/>
<property name="sizeX" column="SIZEX" not-null="true"/>
<property name="sizeY" column="SIZEY" not-null="true"/>
</composite-element>
</set>
鍓嶉潰瀹氫箟鐨?/SPAN>IMAGE綾諱腑錛屽茍涓嶅寘鍚湁瀵圭埗瀹炰綋ITEM鐨勫紩鐢ㄣ備篃灝辨槸璇達紝鍙彲浠ヤ粠ITEM涓鑸埌IMAGE涓紝浣嗘槸鍦?/SPAN>IMAGE鏃犳硶寰楀埌ITEM銆傝繖鍙互閫氳繃<parent>瀹炵幇銆傝繖鏍?/SPAN>IMAGE綾諱腑灝卞惈鏈変竴涓暟鎹垚鍛?/SPAN>item錛屾寚鍚戝叾鐖跺疄浣撱?/SPAN>
浣嗘槸錛屽畠鏄棤娉曞仛鍒扮湡姝g殑鍙屽悜瀵艱埅鐨勩備緥濡傦細閫氳繃SQL鏌ヨ鐩存帴寰楀埌IMAGE鍚庯紝浣嗘槸濡傚悓鏅氱殑鍊肩被鍨嬩竴鏍鳳紝IMAGE瀵硅薄鐨?/SPAN>item鏄?/SPAN>null錛屼綘鏃犳硶浠?/SPAN>component濡傛鐩存帴寰楀埌鍏剁埗瀵硅薄錛岃繖蹇呴』鐢遍氳繃鐖訛紞瀛愬叧緋葷殑entity瀹屾垚銆?/SPAN>
In our CaveatEmptor application, both the user who posted a comment and any system administrator can open an Edit Comment screen to delete or edit the text of a comment. Suppose two different administrators open the edit screen to view the same comment simultaneously. Both edit the comment text and submit their changes. At this point, we have three ways to handle the concurrent attempts to
write to the database:
鈻?Last commit wins鈥?/SPAN>Both updates succeed, and the second update overwrites the changes of the first. No error message is shown.
鈻?First commit wins鈥?/SPAN>The first modification is persisted, and the user submitting the second change receives an error message. The user must restart the business process by retrieving the updated comment. This option is often called optimistic locking.
鈻?SPAN style="FONT: 7pt 'Times New Roman'"> Merge conflicting updates鈥?/SPAN>The first modification is persisted, and the second modification may be applied selectively by the user.
鍦ㄦ垜浠殑CavertEmptor涓紝鐢ㄦ埛鍜岀郴緇熺鐞嗗憳閮藉彲浠ユ墦寮鈥滅紪杈?/SPAN>cooment鈥濆姛鑳斤紝鍒犻櫎鎴栬呯紪杈戣瘎璁恒傚亣璁懼悓鏃舵湁涓や釜綆$悊鍛樺鍚屼竴涓瘎璁烘墦寮緙栬緫鍔熻兘錛屼粬浠兘瀵硅瘎璁鴻繘琛岀紪杈戠劧鍚庢彁浜ゃ傝繖鏄紝鎴戜滑鍙戠幇鍙兘鏈変笁縐嶆柟寮忓姝ゅ茍鍙戞搷浣滆繘琛屽鐞嗐佸啓鍏ユ暟鎹簱錛?/SPAN>
鍚庤呮彁浜よ幏鑳滐紞涓ゆ鏇存柊閮芥垚鍔燂紝浣嗘槸絎簩嬈℃洿鏂板皢浼氳鐩栫涓嬈$殑鏇存柊錛屼笉鏄劇ず浠諱綍閿欒銆?/SPAN>
鍓嶈呮彁浜よ幏鑳滐紞絎竴涓彁浜よ呮垚鍔燂紝鏇存柊鏁版嵁搴擄紝鍚庝竴涓彁浜ゅけ璐ワ紝騫惰繑鍥為敊璇俊鎭傜敤鎴峰繀欏婚噸鏂板紑濮嬫暣涓笟鍔¤繃紼嬶紝鍙栧緱琚洿鏂扮殑璇勮銆傝呭氨鏄父璇寸殑鈥滀箰瑙傞攣鈥濄?/SPAN>
鍚堝茍鏇存柊鍐茬獊錛嶇涓涓洿鏂拌淇濆瓨錛岃岀浜屼釜鏇存柊鍒欑敱鐢ㄦ埛閫夋嫨鏄惁淇濆瓨銆?/SPAN>
The first option, last commit wins, is problematic; the second user overwrites the changes of the first user without seeing the changes made by the first user or even knowing that they existed. In our example, this probably wouldn鈥檛 matter, but it would be unacceptable for some other kinds of data. The second and third options are usually acceptable for most kinds of data. From our point of view, the third option is just a variation of the second鈥攊nstead of showing an error message, we show the message and then allow the user to manually merge changes. There is no single best solution. You must investigate your own business requirements to decide among these three options.
涓婇潰鐨勭涓涓柟妗堟槸鏈夐棶棰樼殑錛氱浜屼釜鐢ㄦ埛鍦ㄤ笉鐭ラ亾鏀瑰彉銆佺敋鑷充笉鐭ラ亾絎竴涓敤鎴峰凡緇忔搷浣滅殑鎯呭喌涓嬶紝鐩存帴閲嶅啓浜嗘暟鎹簱銆傚湪鎴戜滑鐨勪緥瀛愪腑錛屼篃璁告槸娌″叧緋葷殑錛屼絾鏄浜庢煇浜涘簲鐢ㄦ槸涓嶅彲鎺ュ彈鐨勩傜浜屼釜鍜岀涓変釜鏂規瀵逛簬緇濆ぇ閮ㄥ垎鏁版嵁鏄彲浠ョ粨鏉熺殑銆傛寜鐓ф垜浠殑瑙傜偣錛岀涓変釜鏄浜屼釜鐨勫彉縐嶏紝瀹冧笉鏄樉寮忛敊璇俊鎭紝鑰屾槸緇欑敤鎴瘋繘琛岄夋嫨錛屽厑璁哥敤鎴鋒墜宸ュ悎騫跺鏁版嵁鐨勪慨鏀廣傝繖閲屽茍娌℃湁涓涓渶瀹岀編鐨勮В鍐蟲柟妗堛備綘蹇呴』鏍規嵁浣犺嚜宸遍」鐩殑闇瑕佽嚜琛岄夋嫨鏂規銆?/SPAN>
The first option happens by default if you don鈥檛 do anything special in your application銆?/SPAN>On the other hand, Hibernate can help you implement the second and third strategies, using managed versioning for optimistic locking.
濡傛灉鍦ㄤ綘鐨勯」鐩腑涓嶉噰鍙栦換浣曟帾鏂斤紝閭d箞浼氶粯璁や嬌鐢ㄧ涓涓柟妗堛備絾鏄紝hibernate鍙互閫氳繃浣跨敤瀵光滀箰瑙傞攣鈥濅嬌鐢ㄢ滅鐞嗙増鏈濓紝甯姪浣犲疄鐜扮浜屼釜鎴栫涓変釜鏂規銆?/SPAN>
Managed versioning relies on either a version number that is incremented or a timestamp that is updated to the current time, every time an object is modified. For Hibernate managed versioning, we must add a new property to our Comment class and map it as a version number using the <version> tag. First, let鈥檚 look at the changes to the Comment class:
public class Comment {
...
private int version;
...
void setVersion(int version) {
this.version = version;
}
int getVersion() {
return version;
}
}
鈥滅鐞嗙増鏈濅嬌鐢ㄧ増鏈彿鎴栬呮椂闂存埑瀵規暟鎹繘琛屾爣璁幫紝姣忔鏁版嵁鍦ㄦ洿鏂扮殑鏃跺欙紝瀹冮兘浼氳鏇存柊銆傚浜?/SPAN>hibernate錛屾垜浠繀欏葷粰Comment綾伙紝娣誨姞鏂扮殑灞炴э紝鐒跺悗浣跨敤<version>鏍囩瀵瑰叾榪涜鏄犲皠銆傞鍏堣鎴戜滑鏉ョ湅涓涓?/SPAN>Comment綾葷殑鏀瑰彉錛?/SPAN>
public class Comment {
...
private int version;
...
void setVersion(int version) {
this.version = version;
}
int getVersion() {
return version;
}
}
You can also use a public scope for the setter and getter methods. The <version> property mapping must come immediately after the identifier property mapping in the mapping file for the Comment class:
<class name="Comment" table="COMMENTS">
<id ...
<version name="version" column="VERSION"/>
...
</>
浣犲彲浠ヤ嬌鐢?/SPAN>public鐨?/SPAN>setter鎴?/SPAN>getter鏂規硶錛岃繖閲岀殑<version>鏄犲皠鐨勫畾涔夊繀欏葷揣璺熷湪鏄犲皠鏂囦歡涓?/SPAN>comment綾葷殑id鍚庨潰銆?/SPAN>
<class name="Comment" table="COMMENTS">
<id ...
<version name="version" column="VERSION"/>
...
</>
You don鈥檛 need to set the value of the version or timestamp property yourself; Hibernate will initialize the value when you first save a Comment, and increment or reset it whenever the object is modified. Whenever Hibernate updates a comment, it uses the version column in the SQLWHERE clause:
update COMMENTS set COMMENT_TEXT='New comment text', VERSION=3
where COMMENT_ID=123 and VERSION=2
浣犳棤闇鑷繁鎵嬪伐鍘諱慨鏀硅繖閲岀殑鐗堟湰鍙鋒垨鑰呮椂闂存埑錛?/SPAN>hibernate灝嗕細鍦ㄤ綘淇濆瓨Commment鐨勬椂鍊欏鍏跺垵濮嬪寲錛岀劧鍚庡湪瀵硅薄姣忔琚洿鏂扮殑鏃跺欏嵆浣挎洿鏂板叾鐗堟湰鍙峰拰鏃墮棿鎴熾傛棤璁?/SPAN>hibernate浣曟椂鏇存柊comment,瀹冮兘浼氬湪SQL璇彞鐨?/SPAN>where鍚庨潰鍔犱笂version鍒楋細
update COMMENTS set COMMENT_TEXT='New comment text', VERSION=3
where COMMENT_ID=123 and VERSION=2
If another application transaction would have updated the same item since it was read by the current application transaction, the VERSION column would not contain the value 2, and the row would not be updated. Hibernate would check the row count returned by the JDBC driver鈥攚hich in this case would be the number of rows updated, zero鈥攁nd throw a StaleObjectStateException. Using this exception, we might show the user of the second application transaction an error message (鈥淵ou have been working with stale data because another user modified it!鈥? and let the first commit win. Alternatively, we could catch the exception and show the second user a new screen, allowing the user to manually merge changes between the two versions.
濡傛灉鏌愪釜浜嬪姟宸茬粡鏇存柊浜嗘煇涓暟鎹紝鑰屽彟澶栦竴涓簨鍔′篃鍑嗗鏇存柊姝ゆ暟鎹紝浣嗘槸褰撴椂瀹冨彇寰楁暟鎹殑鐗堟湰鍙鋒槸2錛岃屾鏃剁敱浜庤鏁版嵁宸茬粡琚洿鏂拌繃錛屾柊鐗堟湰鍙鋒槸3錛屽洜姝ゅ皢鏃犳硶鏇存柊鏁版嵁搴撲腑鐨勪換浣曠殑鏁版嵁銆傝繖鏃跺?/SPAN>hibernate灝嗕細媯鏌?/SPAN>jdbc鐨勮繑鍥炶鏁幫紞濡傛灉鏈湁浠諱綍鏁版嵁琛岃鏇存柊錛屽垯榪斿洖0錛嶅洜姝ゅ皢浼氭姏鍑?/SPAN>StaleObjectStateException寮傚父銆?/SPAN>
Using this exception, we might show the user of the second application transaction an error message (鈥淵ou have been working with stale data because another user modified it!鈥? and let the first commit win. Alternatively, we could catch the exception and show the second user a new screen, allowing the user to manually merge changes between the two versions.
Session錛堜細璇濓級鎺ュ彛鏄疕ibernate搴旂敤浣跨敤鐨勪富瑕佹帴鍙c備細璇濇帴鍙g殑瀹炰緥鏄交閲忕駭鐨勫茍涓斿垱寤轟笌閿姣佺殑浠d環涔熶笉鏄傝吹銆傝繖寰堥噸瑕佸洜涓轟綘鐨勫簲鐢ㄥ彲鑳藉緇堝湪鍒涘緩涓庨攢姣佷細璇濓紝鍙兘姣忎竴嬈¤姹傞兘浼氬姝ゃ侶ibernate浼氳瘽騫朵笉鏄嚎紼嬪畨鍏ㄧ殑鍥犳搴旇琚璁′負姣忔鍙兘鍦ㄤ竴涓嚎紼嬩腑浣跨敤銆?o:p>
Hibernate浼氳瘽鏄竴涓粙浜庤繛鎺ュ拰浜嬪姟涔嬮棿鐨勬蹇點?FONT color=#ff1493>浣犲彲浠ョ畝鍗曞湴璁や負浼氳瘽鏄浜庝竴涓崟鐙殑宸ヤ綔鍗曞厓宸茶杞藉璞$殑緙撳瓨鎴栭泦鍚堛侶ibernate鍙互媯嫻嬪埌榪欎釜宸ヤ綔鍗曞厓涓璞$殑鏀瑰彉銆?/FONT>鎴戜滑鏈夋椂涔熷皢浼氳瘽縐頒負鎸佺畫鎬х鐞嗗櫒錛屽洜涓哄畠涔熸槸涓庢寔緇ф湁鍏崇殑鎿嶄綔渚嬪瀛樺偍鍜屽彇鍑哄璞$殑鎺ュ彛銆傛敞鎰忥紝Hibernate浼氳瘽涓嶹eb灞傜殑HttpSession娌℃湁浠諱綍鍏崇郴銆傚綋鎴戜滑鍦ㄦ湰涔︿腑浣跨敤浼氳瘽鏃訛紝鎴戜滑鎸囩殑鏄疕ibernate浼氳瘽銆備負浜嗗尯鍒紝鏈夋椂鎴戜滑灝咹ttpSession瀵硅薄縐頒負鐢ㄦ埛浼氳瘽銆?o:p>
SessionFactory鎺ュ彛
搴旂敤浠?/SPAN>SessionFactory錛堜細璇濆伐鍘傦級閲岃幏寰椾細璇濆疄渚嬨備笌浼氳瘽鎺ュ彛鐩告瘮錛岃繖涓璞′笉澶熶護浜哄叴濂嬨?/SPAN>
浼氳瘽宸ュ巶褰撶劧涓嶆槸杞婚噺綰х殑錛佸畠鎵撶畻鍦ㄥ涓簲鐢ㄧ嚎紼嬮棿榪涜鍏變韓銆傚吀鍨嬪湴錛?FONT color=#ff1493>鏁翠釜搴旂敤鍙湁鍞竴鐨勪竴涓細璇濆伐鍘傗斺斾緥濡傚湪搴旂敤鍒濆鍖栨椂琚垱寤恒傜劧鑰岋紝濡傛灉浣犵殑搴旂敤浣跨敤Hibernate璁塊棶澶氫釜鏁版嵁搴擄紝浣犻渶瑕佸姣忎竴涓暟鎹簱浣跨敤涓涓細璇濆伐鍘傘?o:p>
The cascade attribute tells Hibernate that you want operations performed on a 'parent' object to be transitively applied to its 'child' or 'dependent' objects. It's applicable to all forms of collections and associations. There are several possible values to choose among. The most common are none (the default), save-update, delete, and all (which combines save-update and delete). You can also change the default from none to save-update throughout your entire mapping document by supplying a default-cascade attribute in the hibernate-mapping tag itself.
綰ц仈錛坈ascade錛夊睘鎬у憡璇塰ibernate錛氭墍鏈夊鐖跺璞$殑鎿嶄綔閮藉皢浠樿浜庡瓙瀵硅薄鍜屼緷璧栧璞′笂銆傜駭鑱斿彲浠ュ簲鐢ㄤ簬鍚勭褰㈠紡鐨勯泦鍚堝拰鍏寵仈涓傝繖閲岀駭鑱旂殑鍏蜂綋鍙栧煎彲浠ユ湁澶氫釜錛屾渶甯哥敤鐨勬湁錛歯one(榛樿鍊?錛宻ave-update,delete鍜宎ll錛堝叾涓寘鍚簡save-update鍜宒elete錛夈備綘鍙互鍦╤ibernate-mappiong tag涓氳繃璁劇疆default-casade灞炴э紝淇敼榪欓噷鐨刢asade鐨勯粯璁ゅ鹼紝渚嬪淇敼鍏墮粯璁ゅ間負save-update銆?BR>
In our example, we want the tracks owned by an album to be automatically managed by the album, so that when we delete the album, its tracks are deleted. Note that we need to apply the cascade attribute both to the tracks collection and its constituent track element to achieve this. Also, by using a cascade value of all, we eliminate the need to explicitly save any Track objects we create for the album鈥攖he addAlbumTrack() method of Example 5-7 no longer needs the line:
session.save(track);
鍦ㄦ垜浠殑渚嬪瓙涓紝鎴戜滑甯屾湜track瀹屽叏鐢盿lbum鑷姩鎺岀錛屽綋鎴戜滑鍒犻櫎album鏃訛紝瀹冪殑track涔熶細琚垹闄ゃ傛敞鎰忥紝榪欓噷鎴戜滑闇瑕佸湪涓ゅ璁劇疆casade灞炴у疄鐜版浠誨姟錛歵racks闆嗗悎鍜屽畠鐨勭粍鎴愬厓绱爐rack銆傚悓鏍鳳紝鐢變簬鎴戜滑璁瞔asade璁劇疆涓篴ll錛岄偅涔堜笉鍐嶉渶瑕佹樉寮忕殑淇濆瓨涓篴lbum鍒涘緩鐨則rack瀵硅薄錛?-7渚嬪瓙涓殑addAlbumTrack鏂規硶涓嶅啀闇瑕佽皟鐢╯ession.save(track)鏂規硶銆?BR>
By telling Hibernate that it's fully responsible for the relationship between an album and its track, we enable it to persist tracks when they're added to the album as well as delete them when the album itself is deleted.
When it comes time to actually perform persistence, we ask the SessionFactory to open a Session for us (line 27), which establishes a JDBC connection to the database, and provides us with a context in which we can create, obtain, manipulate, and delete persistent objects. As long as the session is open, a connection to the database is maintained, and changes to the persistent objects associated with the session are tracked so they can be applied to the database when the session is closed. Conceptually you can think of a session as a 'large scale transaction' between the persistent objects and the database, which may encompass several database-level transactions. Like a database transaction, though, you should not think about keeping your Hibernate session open over long periods of application existence (such as while you're waiting for user input). A single session is used for a specific and bounded operation in the application, something like populating the user interface or making a change that has been committed by the user. The next operation will use a new session. Also note that Session objects are not thread safe, so they cannot be shared between threads. Each thread needs to obtain its own session from the factory.
鐜板湪寮濮嬭榪扳滄寔涔呭寲鎿嶄綔鈥濄傚湪絎?7琛岋紝浣跨敤SessionFactory鎵撳紑浜哠ession錛屽緩绔嬩簡鏁版嵁搴揓DBC鐨勮繛鎺ワ紝錛堣榪炴帴宸茬粡榪涜浜嗗垵濮嬪寲錛夛紝鎴戜滑鍙互鍊熺敤瀹冭繘琛屼竴緋誨垪鐨勬搷浣滐紝渚嬪錛氬垱寤恒佽幏鍙栥佹搷綰點佸垹闄ゆ寔涔呭寲瀵硅薄銆傚彧瑕乻ession澶勪簬open鐘舵侊紝閭d箞瀵規暟鎹簱鐨勮繛鎺ュ氨涓鐩村緩绔嬬潃錛屾墍鏈夊宸茬粡鍜宻ession緇戝畾鐨勬寔涔呭寲瀵硅薄鐨勬搷浣滈兘浼氳璁板綍涓嬫潵錛屽茍涓斿湪session鍏抽棴鐨勬椂鍊欙紝鎵鏈夌殑榪欎簺鎿嶄綔灝變細琚洿鏂板埌鏁版嵁搴撲腑銆備粠姒傚康涓婄悊瑙o紝浣犲彲浠ュ皢session鐪嬩綔涓涓湪鎸佷箙鍖栧璞″拰鏁版嵁搴撲箣闂寸殑鈥滃ぇ瑙勬ā鐨勪簨鍔♀濓紝瀹冨彲浠ヨ法瓚婂嚑涓暟鎹簱浜嬪姟銆傛濡傛暟鎹簱浜嬪姟閭f牱錛屼綘涓嶈鍦ㄧ▼搴忎腑灝唄ibernate session闀挎椂闂寸殑鎵撳紑鐫錛堜緥濡傚綋紼嬪簭鍦ㄧ瓑寰呯敤鎴瘋緭鍏ョ殑鏃跺欙級錛岀▼搴忎腑鐨勬瘡涓崟鐙殑鎿嶄綔閮借閲囩敤鍗曠嫭鐨剆ession錛屼緥濡傚湪鈥滃脊鍑虹敤鎴風晫闈紝鎴栬呭皢鐢ㄦ埛鐨勪慨鏀規彁浜ゅ埌鏁版嵁搴撯濅腑錛屽氨璇ヤ嬌鐢ㄤ袱涓猻ession銆傚悓鏍烽渶瑕佹敞鎰忕殑鏄紝session鏄嚎紼嬩笉瀹夊叏鐨勶紝鍥犳鏃犳硶鍦ㄧ嚎紼嬩箣闂村叡浜玸ession錛屾瘡涓嚎紼嬮兘搴旇浣跨敤SessionFactory寤虹珛鑷繁鐨剆ess銆?BR>
We need to look more closely at the lifecycle of mapped objects in Hibernate, and how this relates to sessions, because the terminology is rather specific and the concepts are quite important. A mapped object such as an instance of our Track class moves back and forth between two states with respect to Hibernate: transient and persistent. An object that is transient is not associated with any session. When you first create a Track instance using new(), it is transient; unless you tell Hibernate to persist it, the object will vanish when it is garbage collected or your application terminates.
涓嬮潰鎴戜滑瀵筯ibernate涓鏄犲皠瀵硅薄鐨勫0鏄庡懆鏈熻繘琛岃鏄庯紝鍥犱負琚槧灝勫璞$浉鍏崇殑鏈鏄浉褰撶壒鍒殑銆佸畠鐨勬蹇典篃鏄緢閲嶈鐨勩傚湪hibernate涓紝琚槧灝勫璞★紙渚嬪紼嬪簭涓殑Track瀵硅薄錛変細鍦ㄤ袱涓姸鎬佷腑涓嶆柇鐨勬潵鍥炲垏鎹細涓存椂錛坱ransient錛夌姸鎬佸拰鎸佷箙錛坧ersistent錛夌姸鎬併傛湭鏇句笌session緇戝畾鐨勫璞″氨澶勪簬涓存椂鐘舵侊紝渚嬪紼嬪簭涓垰寮濮媙ew鍑烘潵鐨凾rack瀵硅薄錛屽畠灝卞浜庝復鏃剁姸鎬併傞櫎闈炰綘閫氱煡hibernate瀵瑰畠榪涜鎸佷箙鍖栵紝鍚﹀垯鏁翠釜瀵硅薄灝變細鍦ㄥ瀮鍦炬敹闆嗗櫒鍥炴敹鎴栬呯▼搴忕粨鏉熺殑鏃跺欐秷閫濄?BR>
Passing a transient mapped object to a Session's save() method causes it to become persistent. It will survive garbage collection and termination of the Java VM, staying available until it is explicitly deleted. (There is a related distinction between entities and values discussed at the beginning of Appendix A. Mapped objects that have been persisted are called entities, even if they do not currently exist as an instance in any virtual machine.) If you've got a persistent object and you call Session's delete() method on it, the object transitions back to a transient state. The object still exists as an instance in your application, but it is no longer going to stay around unless you change your mind and save it again; it's ceased being an entity.
浣嗘槸錛屽皢涓涓復鏃跺璞′嬌鐢╯ession鐨剆ave鏂規硶淇濆瓨涔嬪悗錛屽畠灝卞浜庢寔涔呯姸鎬侊紝鍗充嬌鍦ㄥ瀮鍦懼洖浜嬫垨鑰匤ava VM緇撴潫涔嬪悗錛屽畠閮戒竴鐩村瓨鍦紝鐭ラ亾璇ュ璞¤鏄庣‘鍒犻櫎涓烘錛堝湪闄勫綍A寮澶存湁鐩稿叧鈥渆ntities鍜寁alues鍖哄埆鈥濈殑璁ㄨ錛屽嵆浣垮叾鍦ㄨ櫄鎷熸満涓茍涓嶇湡瀹炲瓨鍦ㄧ潃涓涓璞′笌涔嬬浉瀵瑰簲錛夈傚綋浣犲鎸佷箙鍖栧璞¤皟鐢╯ession.delete()鏂規硶鏃訛紝璇ュ璞″張鍙樹負涓存椂鐘舵併傝櫧鐒惰瀵硅薄浠嶇劧鍦ㄧ▼搴忎腑鍋氫負涓涓疄渚嬪瓨鍦ㄧ潃錛屼絾鏄櫎闈炰綘鏀瑰彉涓繪剰鍐嶆灝嗗叾鎸佷箙鍖栵紝閭d箞瀹冨皢寰堝揩鐨勬秷閫濓紝瀹冪殑鈥滃疄浣?entity)鈥濅篃灝辨剷鐒惰屼箣銆?/P>
On the other hand, and this point is worth extra emphasis, if you haven't deleted an object (so it's still persistent), when you change its properties there is no need to save it again for those changes to be reflected in the database. Hibernate automatically tracks changes to any persistent objects and flushes those changes to the database at appropriate times. When you close the session, any pending changes are flushed.
鍙︿竴鏂歸潰錛岄渶瑕佸己璋冪殑鏄細濡傝嫢浣犱笉鍒犻櫎鏌愭寔涔呭寲瀵硅薄錛岄偅涔堝綋浣犳敼鍙樺叾灞炴ф椂錛屽茍涓嶉渶瑕佹樉紺虹殑瀵瑰叾鐨勬敼鍙樿繘琛屼繚瀛樸俬ibernate灝嗕細鑷姩鐨勮窡韙埌浣犲鎸佷箙鍖栧璞$殑鏀瑰彉錛岀劧鍚庡湪閫傚綋鐨勬椂鍊欏皢榪欎簺鏀瑰彉濉叆鍒版暟鎹簱涓?BR>
An important but subtle point concerns the status of persistent objects you worked with in a session that has been closed, such as after you run a query to find all entities matching some criteria (you'll see how to do this in the upcoming section, 'Finding Persistent Objects'). As noted above, you don't want to keep this session around longer than necessary to perform the database operation, so you close it once your queries are finished. What's the deal with the mapped objects you've loaded at this point? Well, they were persistent while the session was around, but once they are no longer associated with an active session (in this case because the session has been closed) they are not persistent any longer. Now, this doesn't mean that they no longer exist in the database; indeed, if you run the query again (assuming nobody has changed the data in the meantime), you'll get back the same set of objects; they're still entities. It simply means that there is not currently an active correspondence being maintained between the state of the objects in your virtual machine and the database. It is perfectly reasonable to carry on working with the objects. If you later need to make changes to the objects and you want the changes to 'stick,' you will open a new session and use it to save the changed objects. Because each entity has a unique ID, Hibernate has no problem figuring out how to link the transient objects back to the appropriate persistent state in the new session.
涓嬮潰璁ㄨ鈥滃湪session鍏抽棴鍚庯紝鍜宻ession緇戝畾鐨勬寔涔呭寲瀵硅薄鐨勭姸鎬佲濈殑闂銆備緥濡傚綋浣犳墽琛屼簡涓涓煡璇紝寰楀埌浜嗕綘鎵闇瑕佺殑瀹炰綋瀵硅薄涔嬪悗錛屾濡傚墠闈㈡墍榪扮殑閭f牱錛屼綘涓嶅簲璇ュ皢session淇濇寔榪囦箙錛屼嬌涔嬭秴鍑烘暟鎹簱鎿嶄綔鐨勮寖鍥達紝榪欐椂鍊欎綘灝嗕細鍏抽棴session銆傞偅涔堟鏃墮偅浜涘凡緇忚澆鍏ョ殑鏄犲皠瀵硅薄澶勪簬浠涔堢姸鎬佸憿錛熺瓟妗堟槸榪欐牱鐨勶紝鍦╯ession鐨勬墦寮鐨勮繃紼嬩腑錛屽畠鏄浜庢寔涔呭寲鐘舵侊紝浣嗘槸瀹冧竴鏃︿笉鍦ㄥ拰active session錛堝洜涓烘鏃秙ession宸茬粡鍏抽棴錛夌粦瀹氾紝閭d箞瀹冨氨澶勪簬鎸佷箙鍖栫姸鎬併備絾鏄紝榪欏茍涓嶆剰鍛崇潃浠栦滑鍦ㄦ暟鎹簱涓氨涓嶅啀瀛樺湪錛屼簨瀹炰笂錛屽鏋滀綘鍐嶆鎵ц鏌ヨ錛堝亣璁炬闂存棤浜轟慨鏀規暟鎹級錛岄偅涔堜綘灝嗗彲浠ュ緱鍒板悓鏍風殑闆嗗悎鏁版嵁銆備篃灝辨槸璇達紝铏氭嫙鏈轟腑鐨勫璞℃墍澶勭殑鐘舵佸拰鏁版嵁搴撲腑鐨勫疄浣撴暟鎹殑鐘舵佷箣闂村茍娌℃湁蹇呯劧鐨勮仈緋匯傝繖鏃跺欙紝浣犲彲浠ュ閭d簺瀵硅薄榪涜鑷繁鐨勬搷浣滐紝濡傛灉浣犳敼鍙樹簡涓浜涘璞$殑鏁版嵁錛屽茍鎯沖皢鍏跺瓨鍌ㄥ埌鏁版嵁搴撲腑錛岄偅涔堜綘蹇呴』閲嶆柊寤虹珛涓涓猻ession錛屼嬌鐢ㄥ畠淇濆瓨閭d簺緇忚繃鏀瑰彉鐨勬暟鎹傚洜涓烘瘡涓疄浣撻兘鏈夎嚜宸辯殑鍞竴ID錛屽洜姝ibernate鍙互寰堝鏄撶殑鍦ㄦ柊鐨剆ession涓綆楀嚭濡備綍灝嗕復鏃跺璞¢噸鏂拌漿鎹負鐩稿簲鐨勬寔涔呭璞°?BR>
Armed with these concepts and terms, the remainder of the example is easy enough to understand. Line 31 sets up a database transaction using our open session. Within that, we create a few Track instances containing sample data and save them in the session (lines 33-50), turning them from transient instances into persistent entities. Finally, line 53 commits our transaction, atomically (as a single, indivisible unit) making all the database changes permanent. The try/catch/finally block wrapped around all this shows an important and useful idiom for working with transactions. If anything goes wrong, lines 56-60 will roll back the transaction and then bubble out the exception, leaving the database the way we found it. The session is closed in the finally portion at line 63, ensuring that this takes place whether we exit through the 'happy path' of a successful commit, or via an exception that caused rollback. Either way, it gets closed as it should.
閫氳繃涓婇潰鐨勬蹇電殑璁茶堪鍜岃璁猴紝閭d箞渚嬪瓙涓殑鍏朵粬閮ㄥ垎涔熷氨寰堝ソ鐞嗚В浜嗐傜31琛岋紝浣跨敤鎵撳紑鐨剆ession寤虹珛浜嗘暟鎹簱浜嬪姟銆傚湪浜嬪姟涓紝33錛?0琛屽垱寤轟簡涓涓猅rack瀵硅薄錛屽茍鍦╯ession涓皢鍏朵繚瀛橈紝灝嗗叾浠庝復鏃跺璞″彉涓烘寔涔呭璞°傛渶鍚庯紝53琛屾彁浜や簨鍔★紝鍘熷瓙鎬х殑鎵ц鏁版嵁搴撴敼鍙樸傝繖閲岀殑try/catch/finally灝佽浜嗕簨鍔″鐞嗕腑甯稿嚭鐜扮殑idom銆備竴鏃﹀嚭鐜頒換浣曢棶棰橈紝56錛?0琛屽氨浼氬洖婊氫簨鍔★紝鐒跺悗鎶涘嚭寮傚父錛屼繚璇佹暟鎹簱緇存寔鍘熺姸銆傛棤璁哄浣曪紝閮戒細鎵цfinnally鍧椾腑鐨?3琛岋紝鏃犺鍦ㄦ垚鍔熸墽琛屾垨鑰呭嚭鐜伴敊璇洖婊氱殑鎯呭喌涓嬶紝閮戒細鍏抽棴session銆?BR>
At the end of our method we also close the session factory itself on line 67. This is something you'd do in the 'graceful shutdown' section of your application. In a web application environment, it would be in the appropriate lifecycle event handler. [3.1] In this simple example, when the main() method returns, the application is ending.
鍦ㄦ柟娉曠殑鏈鍚?7琛岋紝灝嗕細鍏抽棴session factory銆傝繖鏄綘鐨勫簲鐢ㄧ▼搴忔甯擱鍑烘椂搴旇鎵ц鐨勬搷浣溿傚湪Web紼嬪簭涓紝浣犲垯闇瑕佷嬌鐢ㄤ竴瀹氱殑鐢熷懡鍛ㄦ湡浜嬩歡澶勭悊鍣紝瀹屾垚姝ゆ搷浣溿傚湪鎴戜滑鐨勪緥瀛愪腑錛屽湪main閫鍑虹殑鏃跺欙紝涔熷氨鏄▼搴忎腑姝㈢殑鏃墮棿銆?BR>
You may be wondering why the taskdef for the schema update tool is inside our schema target, rather than at the top of the build file, next to the one for hbm2java. Well, I wanted it up there too, but I ran into a snag that's worth explaining. I got strange error messages the first time I tried to build the schema target, complaining there was no hibernate.properties on the class path and our compiled Track class couldn't be found. When I ran it again, it worked. Some detective work using ant -verbose revealed that if the classes directory didn't exist when the taskdef was encountered, Ant helpfully removed it from the class path. Since a taskdef can't have its own dependencies, the solution is to move it into the schema target, giving it the benefit of that target's dependencies, ensuring the classes directory exists by the time the taskdef is processed.
涔熻浣犱細濂囨紝涓轟綍鎵句簡schema鏇存柊宸ュ叿鐨則askdef浼氬湪schema鐨則arget涓繘琛屽畾涔夛紝鑰屼笉鏄湪build鏂囦歡鐨勯《閮紝绱ф帴鐫hbm2java榪涜瀹氫箟銆傚垰寮濮嬫垜涔熸槸閭f牱鎯崇殑錛岃繖閲屾垜闇瑕佽В閲婁竴涓嬭繖閲岀殑闂銆傚綋絎竴嬈℃瀯寤簊chema鏃訛紝鎴戝緱鍒頒簡璁稿鑾悕濂囧鐨勯敊璇紝鎶ラ敊淇℃伅鏄細鍦╟lasspath涓壘涓嶅埌hibernate.properties鍜孴rack綾匯備絾鏄啀嬈℃瀯寤虹殑鏃跺欙紝灝卞彲浠ヤ簡銆傚綋浣跨敤鍛戒護鈥渁nt -verbose鈥濇椂錛屼綘灝卞彲浠ュ彂鐜板叾涓殑緇嗚妭涔嬫墍鍦ㄣ傚鏋滃湪ant瑙f瀽鍒皌askdef鏃訛紝build鏂囦歡涓墍浣跨敤鐨刢lass鐩綍騫朵笉瀛樺湪錛岄偅涔坅nt灝變細鑷繁灝嗘鐩綍浠巆lasspath涓Щ闄ゃ備絾鏄痶askdef鍙堟棤娉曞畾涔夎嚜宸辯殑dependencies錛屽洜姝よ繖閲屼笉寰椾笉灝嗗叾縐誨叆鍒皊chema target涓紝榪欐牱涔熷氨鍙互浣跨敤鍒皌arget鐨刣ependencies錛屼繚璇佸湪ant澶勭悊taskdef鐨勬椂鍊欙紝class鐩綍蹇呯劧宸茬粡瀛樺湪銆?/P>
3錛夋柊寤篽ibernate鐨刴apping鏂囦歡錛欶ile >> New >> Other >> Hibernate >> Mapping File.
榪欓噷闇瑕侀夋嫨mapping鏂囦歡鐨勫瓨鏀句綅緗?BR> 濉叆浣犵殑鏁版嵁搴撳笎鍙鳳紝鐒跺悗refresh錛岄夋嫨浣犵殑鏁版嵁搴撹〃銆傝繖閲岀殑table pattern,schema pattern 鑷繁鐭ラ亾鍝︺?BR> 濉啓浣犵殑鍖呭悕錛岀劧鍚庣‘璁ゃ?BR>
4錛夌敓鎴愬悇欏筳ava鏂囦歡銆?BR> 鍙抽敭鍗曞嚮mapping鏂囦歡錛岀劧鍚庨夋嫨hibernate synchronize-> synchronize files銆?榪欏氨鐢熸垚鍚勯」java鏂囦歡浜嗐?
濡傛灉浣犵湅涓嶅埌錛岄偅灝眗efresh鏁翠釜宸ョ▼鐨勬枃浠跺す銆?BR>
5錛夌紪鍐欐祴璇曠▼搴忥紝浣跨敤閭g敓鎴愮殑java鏂囦歡榪涜鏁版嵁搴撴搷浣溿?BR>
嫻嬭瘯紼嬪簭涓墍浣跨敤鐨勪袱涓帴鍙f槸錛歿tablename}.java , {tablename}DAO.java
渚嬪錛氬鏋滀綘鐨勮〃鍚嶆槸Person錛岄偅涔堜綘灝嗙敤Person.java, PersonDAO.java
榪欓噷鐨凱ersonDAO灝佽浜唄ibernate鐨勬搷浣滐紝鏇村姞鏂逛究浜嗐?BR>
鑷繁瑙傚療涓涓嬪惂錛屼細鏈夋洿澶氭敹鑾風殑銆?/P>