package com.oreilly.hh;

import net.sf.hibernate.*;
import net.sf.hibernate.cfg.Configuration;

import java.sql.Time;
import java.util.Date;


/**//**
* Create sample data, letting Hibernate persist it for us.
*/

public class CreateTest
{


public static void main(String args[]) throws Exception
{
// Create a configuration based on the properties file we've put
// in the standard place.
Configuration config = new Configuration();

// Tell it about the classes we want mapped, taking advantage of
// the way we've named their mapping documents.
config.addClass(Track.class);

// Get the session factory we can use for persistence
SessionFactory sessionFactory = config.buildSessionFactory();

// Ask for a session using the JDBC information we've configured
Session session = sessionFactory.openSession();
Transaction tx = null;

try
{
// Create some data and persist it
tx = session.beginTransaction();

Track track = new Track("Russian Trance",
"vol2/album610/track02.mp3",
Time.valueOf("00:03:30"), new Date(),
(short)0);
session.save(track);

track = new Track("Video Killed the Radio Star",
"vol2/album611/track12.mp3",
Time.valueOf("00:03:49"), new Date(),
(short)0);
session.save(track);
track = new Track("Gravity's Angel",
"vol2/album175/track03.mp3",
Time.valueOf("00:06:06"), new Date(),
(short)0);
session.save(track);

// We're done; make our changes permanent
tx.commit();


} catch (Exception e)
{

if (tx != null)
{
// Something went wrong; discard all partial changes
tx.rollback();
}
throw e;

} finally
{
// No matter what, close the session
session.close();
}

// Clean up after ourselves
sessionFactory.close();
}
}

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.
現(xiàn)在開(kāi)始講述“持久化操作”。在第27行,使用SessionFactory打開(kāi)了Session,建立了數(shù)據(jù)庫(kù)JDBC的連接,(該連接已經(jīng)進(jìn)行了初始化),我們可以借用它進(jìn)行一系列的操作,例如:創(chuàng)建、獲取、操縱、刪除持久化對(duì)象。只要session處于open狀態(tài),那么對(duì)數(shù)據(jù)庫(kù)的連接就一直建立著,所有對(duì)已經(jīng)和session綁定的持久化對(duì)象的操作都會(huì)被記錄下來(lái),并且在session關(guān)閉的時(shí)候,所有的這些操作就會(huì)被更新到數(shù)據(jù)庫(kù)中。從概念上理解,你可以將session看作一個(gè)在持久化對(duì)象和數(shù)據(jù)庫(kù)之間的“大規(guī)模的事務(wù)”,它可以跨越幾個(gè)數(shù)據(jù)庫(kù)事務(wù)。正如數(shù)據(jù)庫(kù)事務(wù)那樣,你不該在程序中將hibernate session長(zhǎng)時(shí)間的打開(kāi)著(例如當(dāng)程序在等待用戶輸入的時(shí)候),程序中的每個(gè)單獨(dú)的操作都該采用單獨(dú)的session,例如在“彈出用戶界面,或者將用戶的修改提交到數(shù)據(jù)庫(kù)”中,就該使用兩個(gè)session。同樣需要注意的是,session是線程不安全的,因此無(wú)法在線程之間共享session,每個(gè)線程都應(yīng)該使用SessionFactory建立自己的sess。
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.
下面我們對(duì)hibernate中被映射對(duì)象的聲明周期進(jìn)行說(shuō)明,因?yàn)楸挥成鋵?duì)象相關(guān)的術(shù)語(yǔ)是相當(dāng)特別的、它的概念也是很重要的。在hibernate中,被映射對(duì)象(例如程序中的Track對(duì)象)會(huì)在兩個(gè)狀態(tài)中不斷的來(lái)回切換:臨時(shí)(transient)狀態(tài)和持久(persistent)狀態(tài)。未曾與session綁定的對(duì)象就處于臨時(shí)狀態(tài),例如程序中剛開(kāi)始new出來(lái)的Track對(duì)象,它就處于臨時(shí)狀態(tài)。除非你通知hibernate對(duì)它進(jìn)行持久化,否則整個(gè)對(duì)象就會(huì)在垃圾收集器回收或者程序結(jié)束的時(shí)候消逝。
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.
但是,將一個(gè)臨時(shí)對(duì)象使用session的save方法保存之后,它就處于持久狀態(tài),即使在垃圾回事或者Java VM結(jié)束之后,它都一直存在,知道該對(duì)象被明確刪除為止(在附錄A開(kāi)頭有相關(guān)“entities和values區(qū)別”的討論,即使其在虛擬機(jī)中并不真實(shí)存在著一個(gè)對(duì)象與之相對(duì)應(yīng))。當(dāng)你對(duì)持久化對(duì)象調(diào)用session.delete()方法時(shí),該對(duì)象又變?yōu)榕R時(shí)狀態(tài)。雖然該對(duì)象仍然在程序中做為一個(gè)實(shí)例存在著,但是除非你改變主意再次將其持久化,那么它將很快的消逝,它的“實(shí)體(entity)”也就愕然而之。
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.
另一方面,需要強(qiáng)調(diào)的是:如若你不刪除某持久化對(duì)象,那么當(dāng)你改變其屬性時(shí),并不需要顯示的對(duì)其的改變進(jìn)行保存。hibernate將會(huì)自動(dòng)的跟蹤到你對(duì)持久化對(duì)象的改變,然后在適當(dāng)?shù)臅r(shí)候?qū)⑦@些改變填入到數(shù)據(jù)庫(kù)中。
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關(guān)閉后,和session綁定的持久化對(duì)象的狀態(tài)”的問(wèn)題。例如當(dāng)你執(zhí)行了一個(gè)查詢,得到了你所需要的實(shí)體對(duì)象之后,正如前面所述的那樣,你不應(yīng)該將session保持過(guò)久,使之超出數(shù)據(jù)庫(kù)操作的范圍,這時(shí)候你將會(huì)關(guān)閉session。那么此時(shí)那些已經(jīng)載入的映射對(duì)象處于什么狀態(tài)呢?答案是這樣的,在session的打開(kāi)的過(guò)程中,它是處于持久化狀態(tài),但是它一旦不在和active session(因?yàn)榇藭r(shí)session已經(jīng)關(guān)閉)綁定,那么它就處于持久化狀態(tài)。但是,這并不意味著他們?cè)跀?shù)據(jù)庫(kù)中就不再存在,事實(shí)上,如果你再次執(zhí)行查詢(假設(shè)此間無(wú)人修改數(shù)據(jù)),那么你將可以得到同樣的集合數(shù)據(jù)。也就是說(shuō),虛擬機(jī)中的對(duì)象所處的狀態(tài)和數(shù)據(jù)庫(kù)中的實(shí)體數(shù)據(jù)的狀態(tài)之間并沒(méi)有必然的聯(lián)系。這時(shí)候,你可以對(duì)那些對(duì)象進(jìn)行自己的操作,如果你改變了一些對(duì)象的數(shù)據(jù),并想將其存儲(chǔ)到數(shù)據(jù)庫(kù)中,那么你必須重新建立一個(gè)session,使用它保存那些經(jīng)過(guò)改變的數(shù)據(jù)。因?yàn)槊總€(gè)實(shí)體都有自己的唯一ID,因此hibernate可以很容易的在新的session中計(jì)算出如何將臨時(shí)對(duì)象重新轉(zhuǎn)換為相應(yīng)的持久對(duì)象。
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.
通過(guò)上面的概念的講述和討論,那么例子中的其他部分也就很好理解了。第31行,使用打開(kāi)的session建立了數(shù)據(jù)庫(kù)事務(wù)。在事務(wù)中,33-50行創(chuàng)建了一個(gè)Track對(duì)象,并在session中將其保存,將其從臨時(shí)對(duì)象變?yōu)槌志脤?duì)象。最后,53行提交事務(wù),原子性的執(zhí)行數(shù)據(jù)庫(kù)改變。這里的try/catch/finally封裝了事務(wù)處理中常出現(xiàn)的idom。一旦出現(xiàn)任何問(wèn)題,56-60行就會(huì)回滾事務(wù),然后拋出異常,保證數(shù)據(jù)庫(kù)維持原狀。無(wú)論如何,都會(huì)執(zhí)行finnally塊中的63行,無(wú)論在成功執(zhí)行或者出現(xiàn)錯(cuò)誤回滾的情況下,都會(huì)關(guān)閉session。
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. In this simple example, when the main() method returns, the application is ending.
在方法的最后67行,將會(huì)關(guān)閉session factory。這是你的應(yīng)用程序正常退出時(shí)應(yīng)該執(zhí)行的操作。在Web程序中,你則需要使用一定的生命周期事件處理器,完成此操作。在我們的例子中,在main退出的時(shí)候,也就是程序中止的時(shí)間。