Log4j由三個重要的組件構成:日志信息的優先級,日志信息的輸出目的地,日志信息的輸出格式。日志信息的優先級從高到低有ERROR、WARN、INFO、DEBUG,分別用來指定這條日志信息的重要程度;日志信息的輸出目的地指定了日志將打印到控制臺還是文件中;而輸出格式則控制了日志信息的顯示內容。
一、定義配置文件
其實您也可以完全不使用配置文件,而是在代碼中配置Log4j環境。但是,使用配置文件將使您的應用程序更加靈活。Log4j支持兩種配置文件格式,一種是XML格式的文件,一種是Java特性文件(鍵=值)。下面我們介紹使用Java特性文件做為配置文件的方法:
1.配置根Logger,其語法為:
log4j.rootLogger = [ level ] , appenderName, appenderName, …
其中,level 是日志記錄的優先級,分為OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定義的級別。Log4j建議只使用四個級別,優先級從高到低分別是ERROR、WARN、INFO、DEBUG。通過在這里定義的級別,您可以控制到應用程序中相應級別的日志信息的開關。比如在這里定義了INFO級別,則應用程序中所有DEBUG級別的日志信息將不被打印出來。 appenderName就是指定日志信息輸出到哪個地方。您可以同時指定多個輸出目的地。
2.配置日志信息輸出目的地Appender,其語法為:
log4j.appender.appenderName = fully.qualified.name.of.appender.class
log4j.appender.appenderName.option1 = value1
…
log4j.appender.appenderName.option = valueN
其中,Log4j提供的appender有以下幾種:
org.apache.log4j.ConsoleAppender(控制臺),
org.apache.log4j.FileAppender(文件),
org.apache.log4j.DailyRollingFileAppender(每天產生一個日志文件),
org.apache.log4j.RollingFileAppender(文件大小到達指定尺寸的時候產生一個新的文件),
org.apache.log4j.WriterAppender(將日志信息以流格式發送到任意指定的地方)
3.配置日志信息的格式(布局),其語法為:
log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class
log4j.appender.appenderName.layout.option1 = value1
…
log4j.appender.appenderName.layout.option = valueN
其中,Log4j提供的layout有以下幾種:
org.apache.log4j.HTMLLayout(以HTML表格形式布局),
org.apache.log4j.PatternLayout(可以靈活地指定布局模式),
org.apache.log4j.SimpleLayout(包含日志信息的級別和信息字符串),
org.apache.log4j.TTCCLayout(包含日志產生的時間、線程、類別等等信息)
Log4J采用類似C語言中的printf函數的打印格式格式化日志信息,打印參數如下: %m 輸出代碼中指定的消息
%p 輸出優先級,即DEBUG,INFO,WARN,ERROR,FATAL
%r 輸出自應用啟動到輸出該log信息耗費的毫秒數
%c 輸出所屬的類目,通常就是所在類的全名
%t 輸出產生該日志事件的線程名
%n 輸出一個回車換行符,Windows平臺為“\r\n”,Unix平臺為“\n”
%d 輸出日志時間點的日期或時間,默認格式為ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},輸出類似:2002年10月18日 22:10:28,921
%l 輸出日志事件的發生位置,包括類目名、發生的線程,以及在代碼中的行數。舉例:Testlog4.main(TestLog4.java:10)
二、在代碼中使用Log4j
1.得到記錄器
使用Log4j,第一步就是獲取日志記錄器,這個記錄器將負責控制日志信息。其語法為:
public static Logger getLogger( String name)
通過指定的名字獲得記錄器,如果必要的話,則為這個名字創建一個新的記錄器。Name一般取本類的名字,比如:
static Logger logger = Logger.getLogger ( ServerWithLog4j.class.getName () )
2.讀取配置文件
當獲得了日志記錄器之后,第二步將配置Log4j環境,其語法為:
BasicConfigurator.configure (): 自動快速地使用缺省Log4j環境。
PropertyConfigurator.configure ( String configFilename) :讀取使用Java的特性文件編寫的配置文件。
DOMConfigurator.configure ( String filename ) :讀取XML形式的配置文件。
3.插入記錄信息(格式化日志信息)
當上兩個必要步驟執行完畢,您就可以輕松地使用不同優先級別的日志記錄語句插入到您想記錄日志的任何地方,其語法如下:
Logger.debug ( Object message ) ;
Logger.info ( Object message ) ;
Logger.warn ( Object message ) ;
Logger.error ( Object message ) ;
以下內容是我自己整理的一些
Struts
實施的入門,希望能對大家有所幫助
|
?
作者:佚名 來自:未知
一、J2ME中需要的Java基礎知識
現在有大部分人,都是從零開始學J2ME的,學習J2ME的時候,總是從Java基礎開始學習,而且現在講Java基礎的書籍中都是以J2SE來講基礎,這就給學習造成了一些不必要的麻煩,下面將J2ME中用到的和不需要的Java基礎知識做一個簡單的說明。
J2ME中使用到的Java基礎知識:
1、Java語法基礎:包括基本數據類型、關鍵字、運算符等等
2、面向對象的思想:類和對象的概念,繼承和多態等等。
3、異常處理
4、多線程
J2ME中沒有用到的Java基礎知識:
1、JDK中javac和java命令的使用
2、Java基礎中的很多類在J2ME中沒有,或者類中的方法做了大量的精簡。所以建議在J2ME中熟悉類庫。
3、Applet、AWT、Swing這些知識在J2ME中根本使用不到。
簡單說這么多,希望學J2ME的朋友們能少走一些彎路,不足之處希望大家積極指正和補充。
二、J2ME中暫時無法完成的功能
列一些J2ME中暫時無法完成的功能,希望大家能積極補充:
1、在手機中不更改代碼實現移植,主要指游戲。
2、動態修改按鈕文字。
3、在Canvas上接受中文輸入。
4、操作本地資源、例如地址本、已收短信息等。
5、制作破壞性的手機病毒。
6、其他等待大家來補充。
三、J2ME的跨平臺性
J2ME技術源于Java,所以也具有JVM的優勢,可以在支持Java的平臺上進行移植,但是現在的J2ME技術在跨平臺上卻做的很糟糕,我們來簡單看一下原因:
1、手機的屏幕尺寸不一:
這個主要在界面制作上。如果你使用的是高級用戶界面,比如你做的是應用開發或者用戶登陸、用戶注冊這樣的通用功能時,一般沒有什么問題。
如果你使用的是低級用戶界面,比如你做的是游戲,那么你就需要考慮這個問題了。
2、廠商的擴展API不統一:
例如Nokia的擴展API類庫UI系列,在別的手機上或者沒有實現,或者包名不同等等。
3、手機平臺上實現的bug:
例如Nokia的7650在實現雙緩沖上有bug,那么在這種機型上運行的軟件就不能使用雙緩沖。其他NOKIA上的一些bug,可以參看:http://blog.csdn.net/Mailbomb/archive/2005/03/24/329123.aspx
4、手機性能問題。
不同手機的可用內存、最大jar文件都有要求,例如Nokia S40的大部分手機支持的最大jar文件為64K,最大可用內容為210K。
所以現在的手機軟件,特別是游戲都提供支持的機型列表,也才有了手機游戲移植人員的存在。
四、學習J2ME可以從事的工作種類
現在J2ME技術可以說相當的火暴,這里介紹一些學好了J2ME之后可以從事的工作的種類:
1、J2ME游戲開發人員
根據游戲策劃或者文檔要求,在某種特定的機型(以Nokia S40或S60居多)開發游戲程序。這是現在大部分J2ME程序員從事的工作。
需要熟練掌握:高級用戶界面、低級用戶界面、線程,如果是網絡游戲,還需要熟練網絡編程。
2、J2ME應用開發人員
現在的移動應用還不是很多,但是還是出現了一些,特別是移動定位以及移動商務相關的內容。需要熟練掌握:高級用戶界面、線程和網絡編程。
3、J2ME游戲移植人員
參照源代碼,將可以在一個平臺上可以運行的游戲移植到其他平臺上去。例如將Nokia S40的游戲移植到S60上,或者索愛的T618等等。主要是控制屏幕坐標,有些可能需要替換一些API。
需要熟悉各平臺之間的差異以及相關的技術參數,比如屏幕大小、最大jar文件尺寸等等。
五、J2ME程序設計的幾個原則
1、使用面向對象編程。
雖然使用面向過程編程可以減小文件的尺寸,但是為了以后維護的方便和利于擴展,還是要使用面向對象編程。
2、使用MVC模式
將模型、界面和控制分離。現在很多的程序將三者合一,但是如果你做的程序比較大的話,還是建議你進行分離。
3、自動存儲用戶設定
使用RMS來存儲用戶的信息,例如存儲用戶上次輸入的用戶名、密碼、用戶對于系統的設定等,這樣不僅可以減少用戶的輸入,而且對用戶友好。很多程序甚至做了自動登陸等。
4、一些系統設置允許用戶關閉。如背景音樂、背景燈顯示等。
5、將低級用戶界面的繪制動作放在一個獨立的線程里面去。
6、在需要大量時間才能完成的工作時,給用戶一個等待界面。
六、從模擬器到真機測試
對于J2ME開發者來說,模擬器給我們帶來了很多方便,比如可以在模擬器中調試程序以及很方便的察看程序的效果,但是模擬器也給我們帶來了一些問題,比如模擬器實現的bug等等,所以進行真機測試是必須的。
1、為什么要進行真機測試?
因為模擬器程序可能存在bug,以及真機的性能有限,所以必須進行真機測試。
2、如何將程序傳輸到機器中?
將程序傳輸到機器中有如下方式:
a) OTA下載
b) 使用數據線傳輸
c) 紅外傳輸
d) 藍牙
你可以根據條件,選擇合適的方式。
3、 真機測試主要測什么?
真機測試的內容很多,主要測試以下幾個方面:
a) 程序的功能
b) 程序的操作性,是否易操作
c) 程序的大小,比如Nokia S40系列的手機大部分接受的最大文件尺寸為64K
d) 程序運行速度,速度是否可以忍受。
七、從WTK到廠商SDK
對于J2ME愛好者來說,基本上大家都是從SUN的WTK(J2ME Wireless Toolkit)開始的,但是對于實際應用來說,僅僅使用WTK是遠遠不夠的,所以在學習過程中,必須完成從WTK到SDK的跨越。
1、廠商SDK的下載地址?
·Nokia
Nokia不愧為手機行業的老大,對于j2me的支持也是一流的,有專門的網站提供SDK和各種文檔說明。
網址是:http://forum.nokia.com.cn/sch/index.html
·Siemens
Siemens對于J2ME的支持也不錯,它提供了SDK,模擬器需要獨立安裝。下載地址如下:
https://communication-market.siemens.de/portal/main.aspx?LangID=0&MainMenuID=2&LeftID=2&pid=1&cid=0&tid=3000&xid=0
·SonyEricsson
SonyEricsson SDK以及自己的模擬器,下載地址為:
http://developer.sonyericsson.com/site/global/docstools/java/p_java.jsp
http://mobilityworld.ericsson.com.cn/development/download_hit.asp
·Motorola
Motorola提供了專門的SDK,內部包含模擬器,下載地址為:
http://www.motocoder.com/motorola/pcsHome.jsp
·SamSung
SamSung也提供了專門的SDK和模擬器,下載地址為:
http://developer.samsungmobile.com/eng/front_zone/bbs/bbs_main.jsp?p_menu_id=1500
·NEC:
NEC也提供了集成模擬器的SDK,下載地址為:
http://www.nec-mfriend.com/cn
2、廠商SDK和WTK有什么不同?
廠商SDK最簡單的理解就是在WTK的基礎上增加了自己的模擬器和自己的擴展API。也就是說,你在使用廠商的SDK時,可以使用廠商的擴展類庫,例如Nokia的UI類庫,和廠商自己的模擬器而已。每個廠商的擴展API都不多,而且不盡相同。
3、如何使用?
有些廠商SDK的使用都和WTK相同,例如SamSung。Nokia提供了獨立的界面來開發,但是這個界面在實際開發中使用不多。
4、廠商SDK的問題
廠商SDK實現過程中,有一些bug,而且和真機實現不一致。例如NOKIA的混音播放問題等等。
八、在J2ME中獲得手機IMEI的方法
IMEI是Internation mobile entity identification的簡稱,在手機中輸入*#06#可以顯示該數字,長度為15位,全球唯一,永遠不會沖突,所以可以作為識別用戶的一個標志。
下面是在J2ME中獲得IMEI的方法:
1、MOTO系列的手機可以通過讀取系統的IMEI屬性獲得,代碼如下:
String imei = System.getProperty("IMEI");
2、SIEMENS系列的手機可以通過讀取系統的com.siemens.IMEI屬性獲得,代碼如下:
String imei = System.getProperty("com.siemens.IMEI");
九、J2ME網絡連接中顯示問題的解決辦法
在網絡編程中,有些時候會出現一些在沒有接收到網絡數據就顯示界面的,造成界面顯示不符合要求(例如公告顯示,會先顯示公告的背景圖片再顯示公告信息),這里提一個簡單的解決辦法給大家:
解決這種情況的方法分成三個步驟:
1、在需要顯示的界面中,調用發送網絡數據的方法。每次顯示時調用該構造方法,不調用Display的setCurrent方法顯示。
2、顯示等待界面(例如進度條等),給用戶提示,在進行網絡連接。
3、在處理網絡反饋的數據完以后,調用Display的setCurrent方法顯示顯示當前界面。
雙面提供 時時整理 問題: String s1="111+222+333"; System.out.println(s1.split("+").length); //輸出時提示錯誤: java.util.regex.PatternSyntaxException: Dangling meta character '+' near index 問題出現在加號附近,查詢相關的資料顯示,+、*、|、\等符號在正則表達示中有相應的不同意義。 正則表達式的基本用法 zt | |
1、“.”為通配符,表示任何一個字符,例如:“a.c”可以匹配“anc”、“abc”、“acc”; 2、“[]”,在[]內可以指定要求匹配的字符,例如:“a[nbc]c”可以匹配“anc”、“abc”、“acc; 但不可以匹配“ancc”,a到z可以寫成[a-z],0到9可以寫成[0-9]; 3、數量限定符號,表示匹配次數(或者叫做長度)的符號: 包括:“*”——0次或者多次 “+”——1次或者多次 “?”——0次或者1次 “{n}”——匹配n次,n為整數 “{n,m}”——匹配從n到m之間的某個數的次數;n和m都是整數; “{n,}”——匹配n到無窮次之間任意次數; “{,m}”——匹配0到m之間任意次數; 他們放到匹配格式的后面: 例如: 電話號碼:024-84820482,02484820482(假設前面3或者4位,后面7或者8位,并且中間的減號可有可無) 都是符合規定的,那么可以用如下格式來匹配:[0-9]{3,4} \-? [0-9]{7,8}; 注意:“\”為轉義字符,因為“-”在正則表達式用有代表一個范圍的意義,例如:前面所說的[0-9], 所以它需要轉義字符“\”進行轉義才可使用; 4、“^”為否符號,表示不想匹配的符號,例如:[^z][a-z]+可以匹配所有除“z”開頭的以外的所有字 符串(長度大于2,因為“+”表示大于等于1的次數,從第二位開始都是小寫英文字符); 如果^放到[]的外邊則表示以[]開頭的字符串;^[az][a-z]+表示a或者z開頭的長度大于等于2的英文字符串; 5、“|”或運算符,例如:a[n|bc|cb]c可以匹配“abcc”,“anc”,“acbc”; 6、“$”以它前面的字符結尾的;例如:ab+$就可以被“abb”,“ab”匹配; 7、一些簡單表示方法: \d表示[0-9];\D表示[^0-9];\w表示[A-Z0-9];\W表示[^A-Z0-9];\s表示[\t\n\r\f],就是空格字符包括tab,空格等等;\S表示[^\t\n\r\f],就是非空格字符; 明白了這些以后,我們再返回頭看看它們如何被運用呢?一般來講只需要加[]、或是\\即可。 舉例來講: String s1="111+222+333"; System.out.println(s1.split("[+]").length); 或是 String s1="111+222+333"; System.out.println(s1.split("\\+").length); 其他用法類同。 |
Configuration cfg = new Configuration(); cfg.addResource("hello/Message.hbm.xml"); cfg.setProperties( System.getProperties() ); SessionFactory sessions = cfg.buildSessionFactory(); |
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(); |
在上圖中,我們將應用層放在了持久層的上部,實際上在傳統的項目中,應用層充當著持久層的一個客戶端角色。但對于一些簡單的項目來說,應用層和持久層并沒有區分得那么清楚,這也沒什么,在這種情況下你可以將應用層和持久層合并成了一層。
在上圖中,Hibernate的接口大致可以分為以下幾種類型:
· 一些被用戶的應用程序調用的,用來完成基本的創建、讀取、更新、刪除操作以及查詢操作的接口。這些接口是Hibernate實現用戶程序的商業邏輯的主要接口,它們包括Session、Transaction和Query。
· Hibernate用來讀取諸如映射表這類配置文件的接口,典型的代表有Configuration類。
· 回調(Callback)接口。它允許應用程序能對一些事件的發生作出相應的操作,例如Interceptor、Lifecycle和Validatable都是這一類接口。
· 一些可以用來擴展Hibernate的映射機制的接口,例如UserType、CompositeUserType和IdentifierGenerator。這些接口可由用戶程序來實現(如果有必要)。
Hibernate使用了J2EE架構中的如下技術:JDBC、JTA、JNDI。其中JDBC是一個支持關系數據庫操作的一個基礎層;它與JNDI和JTA一起結合,使得Hibernate可以方便地集成到J2EE應用服務器中去。
在這里,我們不會詳細地去討論Hibernate API接口中的所有方法,我們只簡要講一下每個主要接口的功能,如果你想了解得更多的話,你可以在Hibernate的源碼包中的net.sf.hibernate子包中去查看這些接口的源代碼。下面我們依次講一下所有的主要接口:
核心接口
以下5個核心接口幾乎在任何實際開發中都會用到。通過這些接口,你不僅可以存儲和獲得持久對象,并且能夠進行事務控制。
Session接口
Session接口對于Hibernate 開發人員來說是一個最重要的接口。然而在Hibernate中,實例化的Session是一個輕量級的類,創建和銷毀它都不會占用很多資源。這在實際項目中確實很重要,因為在客戶程序中,可能會不斷地創建以及銷毀Session對象,如果Session的開銷太大,會給系統帶來不良影響。但值得注意的是Session對象是非線程安全的,因此在你的設計中,最好是一個線程只創建一個Session對象。
在Hibernate的設計者的頭腦中,他們將session看作介于數據連接與事務管理一種中間接口。我們可以將session想象成一個持久對象的緩沖區,Hibernate能檢測到這些持久對象的改變,并及時刷新數據庫。我們有時也稱Session是一個持久層管理器,因為它包含這一些持久層相關的操作,諸如存儲持久對象至數據庫,以及從數據庫從獲得它們。請注意,Hibernate 的session不同于JSP應用中的HttpSession。當我們使用session這個術語時,我們指的是Hibernate中的session,而我們以后會將HttpSesion對象稱為用戶session。
SessionFactory 接口
這里用到了一個設計模式――工廠模式,用戶程序從工廠類SessionFactory中取得Session的實例。
令你感到奇怪的是SessionFactory并不是輕量級的!實際上它的設計者的意圖是讓它能在整個應用中共享。典型地來說,一個項目通常只需要一個SessionFactory就夠了,但是當你的項目要操作多個數據庫時,那你必須為每個數據庫指定一個SessionFactory。
SessionFactory在Hibernate中實際起到了一個緩沖區的作用,它緩沖了Hibernate自動生成的SQL語句和一些其它的映射數據,還緩沖了一些將來有可能重復利用的數據。
Configuration 接口
Configuration接口的作用是對Hibernate進行配置,以及對它進行啟動。在Hibernate的啟動過程中,Configuration類的實例首先定位映射文檔的位置,讀取這些配置,然后創建一個SessionFactory對象。
雖然Configuration接口在整個Hibernate項目中只扮演著一個很小的角色,但它是啟動hibernate時你所遇到的每一個對象。
Transaction 接口
Transaction接口是一個可選的API,你可以選擇不使用這個接口,取而代之的是Hibernate的設計者自己寫的底層事務處理代碼。 Transaction接口是對實際事務實現的一個抽象,這些實現包括JDBC的事務、JTA中的UserTransaction、甚至可以是CORBA事務。之所以這樣設計是能讓開發者能夠使用一個統一事務的操作界面,使得自己的項目可以在不同的環境和容器之間方便地移值。
Query和Criteria接口
Query接口讓你方便地對數據庫及持久對象進行查詢,它可以有兩種表達方式:HQL語言或本地數據庫的SQL語句。Query經常被用來綁定查詢參數、限制查詢記錄數量,并最終執行查詢操作。
Criteria接口與Query接口非常類似,它允許你創建并執行面向對象的標準化查詢。
值得注意的是Query接口也是輕量級的,它不能在Session之外使用。
Callback 接口
當一些有用的事件發生時――例如持久對象的載入、存儲、刪除時,Callback接口會通知Hibernate去接收一個通知消息。一般而言,Callback接口在用戶程序中并不是必須的,但你要在你的項目中創建審計日志時,你可能會用到它。
“Hello World” | “Hello world”示例程序讓您對Hibernate有一個簡單的認識。 |
理解Hibernate的架構 | 介紹Hibernate接口的主要功能。 |
核心接口 | Hibernate有5個核心接口,通過這幾個接口開發人員可以存儲和獲得持久對象,并且能夠進行事務控制 |
一個重要的術語:Type | Type是Hibernate發明者發明的一個術語,它在整個構架中是一個非常基礎、有著強大功能的元素,一個Type對象能將一個Java類型映射到數據庫中一個表的字段中去。 |
策略接口 | Hibernate與某些其它開源軟件不同的還有一點――高度的可擴展性,這通過它的內置策略機制來實現。 |
基礎配置 | Hibernate可以配置成可在任何Java環境中運行,一般說來,它通常被用在2-3層的C/S模式的項目中,并被部署在服務端。 |
創建一個SessionFactory對象 | 要創建一個SessionFactory對象,必須在Hibernate初始化時創建一個Configuration類的實例,并將已寫好的映射文件交由它處理。 |
“Hello World”
Hibernate應用程序定義了一些持久類,并且定義了這些類與數據庫表格的映射關系。在我們這個“Hello world”示例程序中包含了一個類和一個映射文件。讓我們看看這個簡單的持久類包含有一些什么?映射文件是怎樣定義的?另外,我們該怎樣用Hibernate來操作這個持久類。
我們這個簡單示例程序的目的是將一些持久類存儲在數據庫中,然后從數據庫取出來,并將其信息正文顯示給用戶。其中Message正是一個簡單的持久類:,它包含我們要顯示的信息,其源代碼如下:
列表1 Message.Java 一個簡單的持久類
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類有三個屬性:Message的id 、消息正文、以及一個指向下一條消息的指針。其中id屬性讓我們的應用程序能夠唯一的識別這條消息,通常它等同于數據庫中的主鍵,如果多個Message類的實例對象擁有相同的id,那它們代表數據庫某個表的同一個記錄。在這里我們選擇了長整型作為我們的id值,但這不是必需的。Hibernate允許我們使用任意的類型來作為對象的id值,在后面我們會對此作詳細描述。
你可能注意到Message類的代碼類似于JavaBean的代碼風格,并且它有一個沒有參數的構造函數,在我們以后的代碼中我將繼續使用這種風格來編寫持久類的代碼。
Hibernate會自動管理Message類的實例,并通過內部機制使其持久化,但實際上Message對象并沒有實現任何關于Hibernate的類或接口,因此我們也可以將它作為一個普通的Java類來使用:
Message message = new Message("Hello World"); System.out.println( message.getText() ); |
以上這段代碼正是我們所期望的結果:它打印“hello world”到屏幕上。但這并不是我們的最終目標;實際上Hibernate與諸如EJB容器這樣的環境在持久層實現的方式上有很大的不同。我們的持久類(Message類)可以用在與容器無關的環境中,不像EJB必須要有EJB容器才能執行。為了能更清楚地表現這點,以下代碼將我們的一個新消息保存到數據庫中去:
Session session = getSessionFactory().openSession(); Transaction tx = session.beginTransaction(); Message message = new Message("Hello World"); session.save(message); tx.commit(); session.close(); |
以上這段代碼調用了Hibernate的Session和Transaction接口(關于getSessionFactory()方法我們將會馬上提到)。它相當于我們執行了以下SQL語句:
insert into MESSAGES (MESSAGE_ID, MESSAGE_TEXT, NEXT_MESSAGE_ID) values (1, 'Hello World', null) |
在以上的SQL語句中,MESSAGE_ID字段到底被初始化成了什么值呢?由于我們并沒有在先前的代碼中為message對象的id屬性賦與初始值,那它是否為null呢?實際上Hibernate對id屬性作了特殊處理:由于它是一個對象的唯一標識,因此當我們進行save()調用時,Hibernate會為它自動賦予一個唯一的值(我們將在后面內容中講述它是如何生成這個值的)。
我們假設你已經在數據庫中創建了一個名為MESSAGE的表,那么既然前面這段代碼讓我們將Message對象存入了數據庫中,那么現在我們就要將它們一一取出來。下面這段代碼將按照字母順序,將數據庫中的所有Message對象取出來,并將它們的消息正文打印到屏幕上:
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(); |
在以上這段代碼中,你可能被find()方法的這個參數困擾著:"from Message as m order by m.text asc",其實它是Hibernate自己定義的查詢語言,全稱叫Hibernate Query Language(HQL)。通俗地講HQL與SQL的關系差不多就是方言與普通話之間的關系,咋一看,你會覺得它有點類似于SQL語句。其實在find()調用時,Hibernate會將這段HQL語言翻譯成如下的SQL語句:
select m.MESSAGE_ID, m.MESSAGE_TEXT, m.NEXT_MESSAGE_ID from MESSAGES m order by m.MESSAGE_TEXT asc |
以下就是運行結果:
1 message(s) found: Hello World |
如果你以前沒有ORM(對象-關系映射)的開發經驗,那你可能想在代碼的某個地方去尋找這段SQL語句,但在Hibernate中你可能會失望:它根本不存在!所有就SQL語句都是Hibernate動態生成的。
也許你會覺得還缺點什么,對!僅憑以上代碼Hibernate是無法將我們的Message類持久化的。我們還需要一些更多的信息,這就是映射定義表!這個表在Hibernate中是以XML格式來體現的,它定義了Message類的屬性是怎樣與數據庫中的MESSAGES表的字段進行一一對應的,列表2是這個示例程序的映射配置文件清單:
列表2:示例程序的對象-關系映射表
<?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="hello.Message" table="MESSAGES"> <id name="id" column="MESSAGE_ID"> <generator class="increment"/> </id> <property name="text" column="MESSAGE_TEXT"/> <many-to-one name="nextMessage" cascade="all" column="NEXT_MESSAGE_ID"/> </class> </hibernate-mapping> |
以上這個文檔告訴Hibernate怎樣將Message類映射到MESSAGES表中,其中Message類的id屬性與表的MESSAGE_ID字段對應,text屬性與表的MESSAGE_TEXT字段對應,nextMessage屬性是一個多對一的關系,它與表中的NEXT_MESSAGE_ID相對應。
相對于有些開源項目來說,Hibernate的配置文件其實是很容易理解的。你可以輕松地修改與維護它。只要你定義好了持久類與數據庫中表字段的對應關系就行了,Hibernate會自動幫你生成SQL語句來對Message對象進行插入、更新、刪除、查找工作,你可以不寫一句SQL語句,甚至不需要懂得SQL語言!
現在讓我們做一個新的試驗,我們先取出第一個Message對象,然后修改它的消息正文,最后我們再生成一個新的Message對象,并將它作為第一個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(); |
以上這段代碼在調用時,Hibernate內部自動生成如下的SQL語句:
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被程序修改時,請注意Hibernate是如何檢測到這種變化,并如何在數據庫中自動對它更新的。這實際上是Hibernate的一個很有價值的特色,我們把它稱為“自動臟數據檢測”,Hibernate的這個特色使得當我們修改一個持久對象的屬性后,不必顯式地通知Hibernate去將它在數據庫中進行更新。同樣的,當第一個Message對象調用setNextMessage()方法將第二個Message對象作為它的下一條消息的引用時,第二條消息會無需調用save()方法,便可以自動地保存在數據庫中。這種特色被稱為“級聯保存”,它也免去了我們顯式地對第二個Message對象調用save()方法之苦。
如果我們再運行先前的那段將數據庫中所有的Message對象都打印出來的代碼,那它的運行結果如下:
2 message(s) found: Greetings Earthling Take me to your leader (please) |
“Hello world”示例程序現在介紹完畢。我們總算對Hibernate有了一個簡單的認識,下面我們將回過頭來,對Hibernate的主要API調用作一下簡要的介紹:
robbin講的肯定比我好的多,自己去精華版看看。
我所給的只是我當初剛開始接觸hibernate時候很想要的一個簡單例子和設置方法。
一直沒有找到,所以現在放到這里給大家看看,(只給想要入門的一個直觀的感應,呵呵)
首先當然要新建一個項目
然后在Project Properties->Paths->Required Libraries->add->new 這里定義hibernate的類庫 把hibernate的lib下面的所有jar包進去 當然還有hibernate2.jar也要
然后一路ok下去就可以了。
再來就是hibernate.properties
從hibernate的src下面找到
把它拷到你項目的src目錄下
(什么,你的項目沒有src目錄,新建一個隨便的類就有src目錄了)
這樣一個JB下面的hibernate的開發環境就好了
然后在hibernate.properties里面設置你的數據庫連接
默認是HypersonicSQL
嗯 接下來的是你最想要做的事情了 其實很簡單
新建一個類Message.java
代碼如下
package hello; import java.io.Serializable; /** * @author getdown * @version 1.0 */ public class Message implements Serializable { private Long id; private String text; //定義一個簡單鏈表 指向另外的一個Message private Message nextMessage; public Message() {} public Message(Long id) { this.id = id; } public Message(String text) { this.text = text; } public Message(Long id, String text) { this.id = id; 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; } }
接下來是這個類對應的hibernate的配置文件 Message.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> <hibernate-mapping> <!--定義類和表的對應--> <class name="hello.Message" table="Messages" > <!--定義ID字段和生成ID的策略 這里采用identity--> <id name="id" column="MESSAGE_ID" > <generator class="identity"/> </id> <!--定義里面的text字段--> <property name="text" type="string"> <!--定義text字段在數據庫里面生成的方法--> <column name="TEXT" length="100" not-null="true" /> </property> <!--定義對象關聯之間的對應關系和關聯的字段--> <many-to-one name="nextMessage" cascade="all" column="NEXT_MESSAGE_ID" /> </class> </hibernate-mapping>
然后就是測試類
package hello; import net.sf.hibernate.cfg.Configuration; import net.sf.hibernate.SessionFactory; import net.sf.hibernate.tool.hbm2ddl.SchemaExport; import net.sf.hibernate.Session; import net.sf.hibernate.Query; import net.sf.hibernate.Hibernate; import net.sf.hibernate.type.LongType; import net.sf.hibernate.Transaction; /** * @author getdown * @version 1.0 */ public class Hello { public Hello() { } public static void main(String[] args) throws Exception { Configuration cfg = new Configuration().addClass(Message.class); /** 顧名思義 構建表。。。第一次運行的時候運行下面語句可以在數據庫生成表 * 之后可以把下面這句去掉 * */ // new SchemaExport(cfg).create(true, true); //先生成sessionFactory SessionFactory sessions = cfg.buildSessionFactory(); //再從sessionFactory得到一個session Session session = sessions.openSession(); //啟動事務 Transaction tx = session.beginTransaction(); //開始對數據庫的操作 /*----對數據庫的創建操作--------*/ Message message = new Message("helloWorld"); //創建一條記錄 session.save(message); //存入記錄 session.flush(); //提交事務 tx.commit(); /*---對數據庫的查詢操作---------------*/ // Message message = new Message(); // Query q = session.createQuery("from Message as message where message.id=1"); // message = (Message) q.list().get(0); // message.getNextMessage().setText("helloNext"); // session.flush(); // session.close(); // Long id = new Long(1); // Message message = (Message) session.find("from Message as message where
message.id=?", id, Hibernate.LONG).get(0); // System.out.println(message.getText()); // /*-------事務的處理----------------*/ // try { // Message message = new Message("hello"); // session.save(message); // session.flush(); // message = new Message("hello"); // session.save(message); // session.flush(); // tx.commit(); // } // catch (HibernateException ex) { // tx.rollback(); // } /*-------添加1000條記錄時間--------------*/ // long start = System.currentTimeMillis(); // for(int i = 0; i < 1000; i ++) { // Message message = new Message("hello"); // session.save(message); // session.flush(); // } // tx.commit(); // long end = System.currentTimeMillis(); // System.out.println("添加1000條記錄時間---" + (end-start)/1000 + "s"); session.close(); } }
ok了 運行一下Hello看看出來什么吧
怎么樣 比起CMP的持久 hibernate的持久是不是顯得很輕量級。。
還可以試試看hibernate的性能 把Hello.java的最后一段注釋去掉運行看看
當然hibernate最重要的還是它的原理,還有很多很好的,很有趣的功能和O/RM設計思想等著你自己發掘。
多看看它自己的文檔,可以學到很多東西,它的文檔真的非常好。