posts - 35,  comments - 7,  trackbacks - 0

          隨著Hibernate在Java開發中的廣泛應用,我們在使用Hibernate進行對象持久化操作中也遇到了各種各樣的問題。這些問題往往都是我們對Hibernate缺乏了解所致,這里我講個我從前遇到的問題及一些想法,希望能給大家一點借鑒。
          ?
          ???????這是在一次事務提交時遇到的異常。
          ???????an?assertion?failure?occured?(this?may?indicate?a?bug?in?Hibernate,?but?is?more?likely?due?to?unsafe?use?of?the?session)
          net.sf.hibernate.AssertionFailure:?possible?nonthreadsafe?access?to?session
          注:非possible?non-threadsafe?access?to?the?session?(那是另外的錯誤,類似但不一樣)
          ?
          ???????這個異常應該很多的朋友都遇到過,原因可能各不相同。但所有的異常都應該是在flush或者事務提交的過程中發生的。這一般由我們在事務開始至事務提交的過程中進行了不正確的操作導致,也會在多線程同時操作一個Session時發生,這里我們僅僅討論單線程的情況,多線程除了線程同步外基本與此相同。
          ?
          ???????至于具體是什么樣的錯誤操作那?我給大家看一個例子(假設Hibernate配置正確,為保持代碼簡潔,不引入包及處理任何異常)
          ??

          SessionFactory?sf?=?new?Configuration().configure().buildSessionFactory()?;
          Session?s?=?sf.openSession();
          Cat?cat?=?new?Cat();

          Transaction?tran?=?s.beginTransaction();?(1)
          s.save(cat);?(2)(此處同樣可以為update?delete)
          s.evict(cat);?(3)
          tran.commit();?(4)
          s.close();(5)


          ???????這就是引起此異常的典型錯誤。我當時就遇到了這個異常,檢查代碼時根本沒感覺到這段代碼出了問題,想當然的認為在Session上開始一個事務,通過Session將對象存入數據庫,再將這個對象從Session上拆離,提交事務,這是一個很正常的流程。如果這里正常的話,那問題一定在別處。
          ?
          ????????問題恰恰就在這里,我的想法也許沒有錯,但是一個錯誤的論據所引出的觀點永遠都不可能是正確的。因為我一直以為直接在對數據庫進行操作,忘記了在我與數據庫之間隔了一個Hibernate,Hibernate在為我們提供持久化服務的同時,也改變了我們對數據庫的操作方式,這種方式與我們直接的數據庫操作有著很多的不同,正因為我們對這種方式沒有一個大致的了解造成了我們的應用并未得到預先設想的結果。
          ?
          那Hibernate的持久化機制到底有什么不同那?簡單的說,Hibernate在數據庫層之上實現了一個緩存區,當應用save或者update一個對象時,Hibernate并未將這個對象實際的寫入數據庫中,而僅僅是在緩存中根據應用的行為做了登記,在真正需要將緩存中的數據flush入數據庫時才執行先前登記的所有行為。
          ?
          在實際執行的過程中,每個Session是通過幾個映射和集合來維護所有與該Session建立了關聯的對象以及應用對這些對象所進行的操作的,與我們這次討論有關的有entityEntries(與Session相關聯的對象的映射)、insertions(所有的插入操作集合)、deletions(刪除操作集合)、updates(更新操作集合)。下面我就開始解釋在最開始的例子中,Hibernate到底是怎樣運作的。
          (1)生成一個事務的對象,并標記當前的Session處于事務狀態(注:此時并未啟動數據庫級事務)。
          (2)應用使用s.save保存cat對象,這個時候Session將cat這個對象放入entityEntries,用來標記cat已經和當前的會話建立了關聯,由于應用對cat做了保存的操作,Session還要在insertions中登記應用的這個插入行為(行為包括:對象引用、對象id、Session、持久化處理類)。
          (3)s.evict(cat)將cat對象從s會話中拆離,這時s會從entityEntries中將cat這個對象移出。
          (4)事務提交,需要將所有緩存flush入數據庫,Session啟動一個事務,并按照insert,update,……,delete的順序提交所有之前登記的操作(注意:所有insert執行完畢后才會執行update,這里的特殊處理也可能會將你的程序搞得一團糟,如需要控制操作的執行順序,要善于使用flush),現在cat不在entityEntries中,但在執行insert的行為時只需要訪問insertions就足夠了,所以此時不會有任何的異常。異常出現在插入后通知Session該對象已經插入完畢這個步驟上,這個步驟中需要將entityEntries中cat的existsInDatabase標志置為true,由于cat并不存在于entityEntries中,此時Hibernate就認為insertions和entityEntries可能因為線程安全的問題產生了不同步(也不知道Hibernate的開發者是否考慮到例子中的處理方式,如果沒有的話,這也許算是一個bug吧),于是一個net.sf.hibernate.AssertionFailure就被拋出,程序終止。
          ?
          我想現在大家應該明白例子中的程序到底哪里有問題了吧,我們的錯誤的認為s.save會立即的執行,而將cat對象過早的與Session拆離,造成了Session的insertions和entityEntries中內容的不同步。所以我們在做此類操作時一定要清楚Hibernate什么時候會將數據flush入數據庫,在未flush之前不要將已進行操作的對象從Session上拆離。
          ?
          對于這個錯誤的解決方法是,我們可以在(2)和(3)之間插入一個s.flush()強制Session將緩存中的數據flush入數據庫(此時Hibernate會提前啟動事務,將(2)中的save登記的insert語句登記在數據庫事務中,并將所有操作集合清空),這樣在(4)事務提交時insertions集合就已經是空的了,即使我們拆離了cat也不會有任何的異常了。
          前面簡單的介紹了一下Hibernate的flush機制和對我們程序可能帶來的影響以及相應的解決方法,Hibernate的緩存機制還會在其他的方面給我們的程序帶來一些意想不到的影響。看下面的例子:
          ??

          (name為cat表的主鍵)
          Cat?cat?=?new?Cat();
          cat.setName(“tom”);
          s.save(cat);

          cat.setName(“mary”);
          s.update(cat);(6)

          Cat?littleCat?=?new?Cat();
          littleCat.setName(“tom”);
          s.save(littleCat);

          s.flush();


          這個例子看起來有什么問題?估計不了解Hibernate緩存機制的人多半會說沒有問題,但它也一樣不能按照我們的思路正常運行,在flush過程中會產生主鍵沖突,可能你想問:“在save(littleCat)之前不是已經更改cat.name并已經更新了么?為什么還會發生主鍵沖突那?”這里的原因就是我在解釋第一個例子時所提到的緩存flush順序的問題,Hibernate按照insert,update,……,delete的順序提交所有登記的操作,所以你的s.update(cat)雖然在程序中出現在s.save(littleCat)之前,但是在flush的過程中,所有的save都將在update之前執行,這就造成了主鍵沖突的發生。
          ?
          這個例子中的更改方法一樣是在(6)之后加入s.flush()強制Session在保存littleCat之前更新cat的name。這樣在第二次flush時就只會執行s.save(littleCat)這次登記的動作,這樣就不會出現主鍵沖突的狀況。
          ?
          再看一個例子(很奇怪的例子,但是能夠說明問題)

          Cat?cat?=?new?Cat();
          cat.setName(“tom”);
          s.save(cat);?(7)
          s.delete(cat);(8)

          cat.id=null;(9)
          s.save(cat);(10)
          s.flush();

          ?
          這個例子在運行時會產生異常net.sf.hibernate.HibernateException:?identifier?of?an?instance?of?Cat?altered?from?8b818e920a86f038010a86f03a9d0001?to?null
          ?
          這里例子也是有關于緩存的問題,但是原因稍有不同:
          (7)和(2)的處理相同。
          (8)Session會在deletions中登記這個刪除動作,同時更新entityEntries中該對象的登記狀態為DELETED。
          (9)Cat類的標識符字段為id,將其置為null便于重新分配id并保存進數據庫。
          (10)此時Session會首先在entityEntries查找cat對象是否曾經與Session做過關聯,因為cat只改變了屬性值,引用并未改變,所以會取得狀態為DELETED的那個登記對象。由于第二次保存的對象已經在當前Session中刪除,save會強制Session將緩存flush才會繼續,flush的過程中首先要執行最開始的save動作,在這個save中檢查了cat這個對象的id是否與原來執行動作時的id相同。不幸的是,此時cat的id被賦為null,異常被拋出,程序終止(此處要注意,我們在以后的開發過程盡量不要在flush之前改變已經進行了操作的對象的id)。
          ?
          這個例子中的錯誤也是由于緩存的延時更新造成的(當然,與不正規的使用Hibernate也有關系),處理方法有兩種:
          1、在(8)之后flush,這樣就可以保證(10)處save將cat作為一個全新的對象進行保存。
          2、刪除(9),這樣第二次save所引起的強制flush可以正常的執行,在數據庫中插入cat對象后將其刪除,然后繼續第二次save重新插入cat對象,此時cat的id仍與從前一致。
          ?
          這兩種方法可以根據不同的需要來使用,呵呵,總覺得好像是很不正規的方式來解決問題,但是問題本身也不夠正規,只希望能夠在應用開發中給大家一些幫助,不對的地方也希望各位給與指正。
          ?
            總的來說,由于Hibernate的flush處理機制,我們在一些復雜的對象更新和保存的過程中就要考慮數據庫操作順序的改變以及延時flush是否對程序的結果有影響。如果確實存在著影響,那就可以在需要保持這種操作順序的位置加入flush強制Hibernate將緩存中記錄的操作flush入數據庫,這樣看起來也許不太美觀,但很有效。
          posted @ 2006-05-24 13:47 java小記 閱讀(327) | 評論 (0)編輯 收藏

          ???? public ? static ? void ?main(String[]?args)? throws ?Exception? {?
          ????????System.out.println(isWrapClass(Long.
          class ));?
          ????????System.out.println(isWrapClass(String.
          class ));?
          ????}
          ?

          ????
          public ? static ? boolean ?isWrapClass(Class?clz)? {?
          ????????
          try ? {?
          ????????????
          return ?((Class)?clz.getField( " TYPE " ).get( null )).isPrimitive();?
          ????????}
          ? catch ?(Exception?e)? {?
          ????????????
          return ? false ;?
          ????????}
          ?
          ????}
          ?
          posted @ 2006-05-22 16:44 java小記 閱讀(895) | 評論 (0)編輯 收藏
          <script language="javascript">
          ? g_blnCheckUnload = true;
          ? function RunOnBeforeUnload() {
          ? ?? if (g_blnCheckUnload) {window.event.returnValue = 'You will lose any unsaved content';??
          ??? ?}?
          ? }
          </script>
          <body? onbeforeunload="RunOnBeforeUnload()">
          </body>
          posted @ 2006-05-15 09:27 java小記 閱讀(262) | 評論 (0)編輯 收藏

          ?

          import ?java.io.FileOutputStream;
          import ?java.util.List;

          import ?org.jdom.Attribute;
          import ?org.jdom.Document;
          import ?org.jdom.Element;
          import ?org.jdom.input.SAXBuilder;
          import ?org.jdom.output.Format;
          import ?org.jdom.output.XMLOutputter;

          public ? class ?XML? {
          ????
          public ? static ? void ?main(String[]?args)? throws ?Exception? {

          ????????SAXBuilder?builder?
          = ? new ?SAXBuilder();
          ????????Document?doc?
          = ?builder.build( " d:\\destination.xml " );
          ????????Element?root?
          = ?doc.getRootElement();
          ????????root.removeChild(
          " Target " );
          ????????Element?items?
          = ?root.getChild( " Items " );
          ????????List?item?
          = ?items.getChildren( " item " );
          ????????
          for ?( int ?i? = ? 0 ;?i? < ?item.size();?i ++ )? {
          ????????????Element?elem?
          = ?(Element)?item.get(i);
          ????????????Attribute?attr?
          = ?elem.getAttribute( " displayName " );????????????
          ????????????attr.setValue(attr.getValue()?
          + ? " 中國 " );????????????
          ????????}

          ????????
          // ?保存
          ????????Format?format? = ?Format.getCompactFormat();
          ????????format.setEncoding(
          " gb2312 " );
          ????????format.setIndent(
          " ?? " );
          ????????XMLOutputter?XMLOut?
          = ? new ?XMLOutputter(format);
          ????????XMLOut.output(doc,?
          new ?FileOutputStream( " d:\\destination_tmp.xml " ));

          ????}

          }

          posted @ 2006-05-13 09:22 java小記 閱讀(225) | 評論 (0)編輯 收藏
          STUN (Simple Traversal of UDP through NATs (Network Address Translation)) is a protocol for assisting devices behind a NAT firewall or router with their packet routing.
          • STUN enables a device to find out its public IP address and the type of NAT service its sitting behind.
          • STUN operates on TCP and UDP port 3478.
          • STUN is not widely supported by VOIP devices yet.
          • STUN may use DNS SRV records to find STUN servers attached to a domain. The service name is _stun._udp or _stun._tcp

          Definitions (from the RFC)

          • STUN Client: A STUN client (also just referred to as a client) is an entity that generates STUN requests. A STUN client can execute on an end system, such as a user's PC, or can run in a network element, such as a conferencing server.
          • STUN Server: A STUN Server (also just referred to as a server) is an entity that receives STUN requests, and sends STUN responses. STUN servers are generally attached to the public Internet.

          Various types of NAT (still according to the RFC)
          • Full Cone: A full cone NAT is one where all requests from the same internal IP address and port are mapped to the same external IP address and port. Furthermore, any external host can send a packet to the internal host, by sending a packet to the mapped external address.
          • Restricted Cone: A restricted cone NAT is one where all requests from the same internal IP address and port are mapped to the same external IP address and port. Unlike a full cone NAT, an external host (with IP address X) can send a packet to the internal host only if the internal host had previously sent a packet to IP address X.
          • Port Restricted Cone: A port restricted cone NAT is like a restricted cone NAT, but the restriction includes port numbers. Specifically, an external host can send a packet, with source IP address X and source port P, to the internal host only if the internal host had previously sent a packet to IP address X and port P.
          • Symmetric: A symmetric NAT is one where all requests from the same internal IP address and port, to a specific destination IP address and port, are mapped to the same external IP address and port. If the same host sends a packet with the same source address and port, but to a different destination, a different mapping is used. Furthermore, only the external host that receives a packet can send a UDP packet back to the internal host.
          posted @ 2006-05-12 16:19 java小記 閱讀(323) | 評論 (0)編輯 收藏
          1、密碼由6-32位字母、數字或下劃線構成;
          2、至少需要一位小寫字母;
          3、至少需要一位大寫字母;
          4、至少需要一位數字。

          String?password?=?"password";
          ????????System.out.println(password?
          !=?null?&&?password.length()?>=?6
          ????????????????
          &&?password.length()?<=?32
          ????????????????
          &&?Pattern.compile("[a-z]+").matcher(password).find()
          ????????????????
          &&?Pattern.compile("[A-Z]+").matcher(password).find()
          ????????????????
          &&?Pattern.compile("[\\d]+").matcher(password).find());
          posted @ 2006-05-10 09:10 java小記 閱讀(409) | 評論 (0)編輯 收藏

          ??
          JList組件有一個單獨的顯示模式ListModel來表示JList的顯示數據.??
          JList創建以后,JList數據元素的值及數據元素的數量可以動態地改變.??
          JList在它的數據模式ListModel中觀察數據的改變.因此,一個ListModel 的正確實現應當在每次數據發生改變時,通知事件的監聽者.??
          當使用構造函數JList(Object[])創建一個JList的實例時,系統將自動 創建一個DefaultListModel的實例來存儲JList的顯示數據, 可以調用 DefaultListModel中定義的簡便方法來動態地修改JList的數據,如 removeElementAt(index),addElement(Object)等. DefaultListModel 在修改數據的同時,將通知JList關于數據的改變.??

          ?

          posted @ 2006-04-28 08:28 java小記 閱讀(476) | 評論 (0)編輯 收藏

          ?

          import ?java.awt. * ;
          import ?java.awt.event. * ;
          public ? class ?MyFrame? extends ?Frame {
          {
          public ?MyFrame() {
          ??setSize(
          500 , 400 );
          ??setResizable(?
          false ?);?
          ??
          this .addWindowStateListener( new ?WindowStateListener() { // 狀態監聽器
          ???? public ? void ?windowStateChanged(WindowEvent?e) {
          ??????
          if (getState() == 1 ) { // 最小化狀態
          ????????setState( 0 ); // 切換成正常狀態
          ??????}

          ????}

          ??}
          );
          }


          public ? static ? void ?main(String[]?args) {
          ????
          new ?MyFrame().setVisible( true );
          }


          }
          posted @ 2006-04-28 08:28 java小記 閱讀(2711) | 評論 (0)編輯 收藏
          簡而言之:
          Big endian machine: It thinks the first byte it reads is the biggest.
          Little endian machine: It thinks the first byte it reads is the littlest.
          舉個例子,從內存地址0x0000開始有以下數據
          ?0x0000?????0x12
          ?0x0001?????0x34
          ?0x0002?????0xab
          ?0x0003?????0xcd
          如果我們去讀取一個地址為0x0000的四個字節變量,若字節序為big-endian,則讀出
          結果為0x1234abcd;若字節序位little-endian,則讀出結果為0xcdab3412.
          如果我們將0x1234abcd寫入到以0x0000開始的內存中,則結果為
          ????????????????big-endian?????little-endian
          0x0000?????0x12??????????????0xcd
          0x0001?????0x23??????????????0xab
          0x0002?????0xab??????????????0x34
          0x0003?????0xcd??????????????0x12
          x86系列CPU都是little-endian的字節序.
          posted @ 2006-04-25 15:21 java小記 閱讀(330) | 評論 (0)編輯 收藏
          ?VoIP applications like Skype, GoogleTalk and Others

          Internet Voice, also known as Voice over Internet Protocol (VoIP), is a technology that allows you to make telephone calls using a broadband Internet connection instead of a regular (or analog) phone line. Some services using VoIP may only allow you to call other people using the same service, but others may allow you to call anyone who has a telephone number - including local, long distance, mobile, and international numbers. Also, while some services only work over your computer or a special VoIP phone, other services allow you to use a traditional phone through an adaptor.
          posted @ 2006-04-05 09:59 java小記 閱讀(269) | 評論 (1)編輯 收藏
          import ?java.security.MessageDigest;
          import ?java.security.NoSuchAlgorithmException;
          public ? class ?PasswordManager? {
          ????
          ????
          // ***************************************************************
          ????
          // ?Public?Interface
          ????
          // ***************************************************************

          ????
          /**
          ?????*?Creates?a?one-way?has?of?the?specified?password.??This?allows?passwords?to?be
          ?????*?safely?stored?in?the?database?without?any?way?to?retrieve?the?original?value.
          ?????*?
          ?????*?
          @param ?password?the?string?to?encrypt.
          ?????*?
          ?????*?
          @return ?the?encrypted?password,?or?null?if?encryption?failed.
          ?????
          */

          ????
          public ? static ?String?encryptPassword(?String?password?)? {
          ????????
          ????????
          try ? {
          ????????????MessageDigest?md?
          = ?MessageDigest.getInstance( " SHA " );
          ????????
          ????????????
          // Create?the?encrypted?Byte[]
          ????????????md.update(?password.getBytes()?);
          ????????????
          byte []?hash? = ?md.digest();
          ????????????
          ????????????
          // Convert?the?byte?array?into?a?String
          ????????????
          ????????????StringBuffer?hashStringBuf?
          = ? new ?StringBuffer();
          ????????????String?byteString;
          ????????????
          int ?byteLength;
          ????????????
          ????????????
          for (? int ?index? = ? 0 ;?index? < ?hash.length;?index ++ ?)? {
          ????????????????
          ????????????????byteString?
          = ?String.valueOf(?hash[index?]? + ? 128 ?);
          ????????????????
          ????????????????
          // Pad?string?to?3.??Otherwise?hash?may?not?be?unique.
          ????????????????byteLength? = ?byteString.length();
          ????????????????
          switch (?byteLength?)? {
          ????????????????
          case ? 1 :
          ????????????????????byteString?
          = ? " 00 " ? + ?byteString;
          ????????????????????
          break ;
          ????????????????
          case ? 2 :
          ????????????????????byteString?
          = ? " 0 " ? + ?byteString;
          ????????????????????
          break ;
          ????????????????}

          ????????????????hashStringBuf.append(?byteString?);
          ????????????}

          ????????????
          ????????????
          return ?hashStringBuf.toString();
          ????????}

          ????????
          catch (?NoSuchAlgorithmException?nsae?)? {
          ????????????System.out.println(?
          " Error?getting?password?hash?-? " ? + ?nsae.getMessage()?);
          ????????????
          return ? null ;
          ????????}

          ????}

          }
          posted @ 2006-03-28 15:45 java小記 閱讀(275) | 評論 (0)編輯 收藏
          偶爾eclipse3.1的web項目有時候不能自動編譯/WEB-INF/src,即使選擇工程的自動編譯開關也不好使,不知道是不是Bug
          我這樣解決的:
          1. project->properties->java build path->source->.../WEB-INF/src的output folder不要默認,編輯讓它指向../WEB-INF/classes
          然后重新點擊build工程即可自動編譯。

          2. 再就是最重要的要看工程下面是否缺少了work目錄,由于CVS控制時不把work加如版本,所以checkout后沒有這個目錄,要手工加上有的工程就能自動編譯了
          posted @ 2006-03-21 10:50 java小記 閱讀(1320) | 評論 (0)編輯 收藏
          XP系統一般情況下在裝完系統后會有一個計算機管理員權限的用戶,以后登陸時就顯示這個用戶
          進入系統后在控制面板中的用戶帳號下看不到Administrator用戶,就好象丟失了一樣,如何看到呢?
          里面有另外一個問題涉及XP自動登陸                                      
          單擊"開始/運行",輸入"rundll32 netplwiz.dll,UsersRunDll",按回車鍵后彈出“用戶帳戶”窗口,
          這和“控制面板”中打開的“用戶賬戶”窗口不同!
          然后取消選定"要使用本機,用戶必須輸入用戶名和密碼"選項,單擊確定.
          在彈出的對話框中輸入你想讓電腦每次自動登錄的賬戶(默認Administrator)和密碼即可。
          下一次開機自動用Administrator登陸到系統,再看控制面板就有了Administrator。
          Xp默認把Administrator隱藏,雖然都是計算機管理員Administrator和有計算機管理員權限的用戶還是有
          細微差別的。但是一般情況下使用系統用計算機管理員權限的用戶就足夠了
          posted @ 2006-02-13 21:40 java小記 閱讀(5288) | 評論 (3)編輯 收藏


          安全域是Tomcat的內置功能,主要有以下幾種安全域:
          JDBCRealm
          DataSourceRealm
          JNDIRealm
          MemoryRealm
          JAASRealm

          在conf/server.xml中配置應用的<Context......>下面的<Realm className="org.apache.catalina.realm.MemoryRealm" />
          從一個XML文件中讀取用戶信息,默認的就是tomcat-users.xml

          tomcat-users.xml中的角色定義
          <?xml version='1.0' encoding='utf-8'?>
          <tomcat-users> 
              <role rolename="tomcat"/> 
              <role rolename="role1"/> 
              <role rolename="guest"/>
              <user username="lee" password="lee" roles="guest"/>
              <user username="suoxin" password="suoxin" roles="tomcat,role1"/>
          </tomcat-users>

          在應用下的web.xml中加入<security-constraint>元素
          <security-constraint>  
              <web-resource-collection>
                   <url-pattern>/*</url-pattern>   
              </web-resource-collection>   
              <auth-constraint>    
                   <role-name>admin</role-name>   
                   <role-name>guest</role-name>  
              </auth-constraint>
          </security-constraint>

          在應用下的web.xml中加入<login-config>元素
          <login-config>     
             <auth-method>FORM</auth-method>
             <!--這里FORM是基于表單的驗證,會跳轉到mylogin.jsp,如果出錯就到myerror.jsp,
             還有基于對話筐的是BASIC關鍵字,但是不安全在網絡傳輸中。摘要驗證DIGEST會采
             用MD5(Message Digest Algorithm)加密傳輸-->
             <form-login-config>       
                <form-login-page>/mylogin.jsp</form-login-page>       
                <form-error-page>/myerror.jsp</form-error-page>     
             </form-login-config>
          </login-config>

          mylogin.jsp的action和name必須嚴格規范寫
          <form name="form1" id="form1" method="post" action="j_security_check"> 
             <input type="text" name="j_username"/> 
             <input type="text" name="j_password"/>
             <input type="submit" name="Submit" value="提交" />
          </form>

           

          posted @ 2006-02-11 09:11 java小記 閱讀(221) | 評論 (0)編輯 收藏
           
            1,下載OSCache, oscache-2.2-full.zip
            2,解壓縮oscache-2.2-full.zip后把oscache-2.2.jar拷貝到應用的WEB-INF/lib下 ,
               并把etc目下下的oscache.properties拷貝到應用的WEB-INF/classes下.
            3, 在應用的web.xml中加入緩存過濾器    
              
                 <filter>
                     
          <filter-name>CacheFilter</filter-name>
                     
          <filter-class>com.opensymphony.oscache.web.filter.CacheFilter</filter-class>
                     
          <init-param>
                         
          <param-name>time</param-name>
                         
          <param-value>600</param-value>
                     
          </init-param>
                     
          <init-param>
                         
          <param-name>scope</param-name>
                         
          <param-value>application</param-value>
                     
          </init-param>
                 
          </filter>
                 
                 
          <filter-mapping>
                     
          <filter-name>CacheFilter</filter-name>
                     
          <url-pattern>/servlets/UserAllProducts</url-pattern>
                 
          </filter-mapping>

            以上的/servlets/UserAllProducts訪問需要操作數據庫,并且這些內容一段時間內很少改變,這樣在內存緩存這個URL很有必要
            它可以降低數據庫訪問量。
           
            經過以上配置后,當第一次訪問/servlets/UserAllProducts時,從數據庫中查出所有產品列表并緩存到application中600秒。
            在600秒內的任何訪問/servlets/UserAllProducts都不會真正執行這個servlet,而直接從application中取出緩存的內容。這樣
            就減少了數據庫的訪問量。
          posted @ 2006-02-09 18:58 java小記 閱讀(291) | 評論 (0)編輯 收藏

          今天遇到了這樣的問題,就是浮點運算后數據比較出現錯誤,郁悶了半天,網上查了資料才發現浮點數直接用雙目運算符連接會出現結果不準確問題。解決方法如下:
          1。所有浮點運算都在數據庫內做好,也就是都用sql實現了
          2。用BigDecimal實現,方法如下(僅僅是個例子):

          import java.math.BigDecimal;

          public class tt {

           
          /**
            * 
          @param args
            
          */

           
          public static void main(String[] args) {
            
          float a = 1.1f;
            
          float b = 2.2f;
            tt t 
          = new tt();
            System.out.println(t.add(a,b));
            System.out.println(t.sub(a,b));
            System.out.println(t.mul(a,b));
            System.out.println(t.div(a,b));
            System.out.println(t.round(a));

           }

           
          public float add(float v1,float v2){//加法
             BigDecimal b1 = new BigDecimal(Float.toString(v1));
             BigDecimal b2 
          = new BigDecimal(Float.toString(v2));
             
          return b1.add(b2).floatValue();
            }


            
          public float sub(float v1,float v2){//減法
             BigDecimal b1 = new BigDecimal(Float.toString(v1));
             BigDecimal b2 
          = new BigDecimal(Float.toString(v2));
             
          return b1.subtract(b2).floatValue();
            }


            
          public float mul(float v1,float v2){//乘法
             BigDecimal b1 = new BigDecimal(Float.toString(v1));
             BigDecimal b2 
          = new BigDecimal(Float.toString(v2));
             
          return b1.multiply(b2).floatValue();
            }


            
          public float div(float v1,float v2){//除法
             BigDecimal b1 = new BigDecimal(Float.toString(v1));
             BigDecimal b2 
          = new BigDecimal(Float.toString(v2));
             
          return b1.divide(b2,3,BigDecimal.ROUND_HALF_UP).floatValue();
            }


            
          public float round(float v){//截取3位
             BigDecimal b = new BigDecimal(Float.toString(v));
             BigDecimal one 
          = new BigDecimal("1");
             
          return b.divide(one,3,BigDecimal.ROUND_HALF_UP).floatValue();
            }

          }

          posted @ 2006-02-08 16:43 java小記 閱讀(277) | 評論 (0)編輯 收藏

          spring配置中bean的循環引用問題及解決方法

          問題:Spring+Hibernate的應用中,定義了兩個業務Service,這里分別稱它們為serivceA,ServiceB。
          它們的關系簡單點來說是這樣的:
          serviceA需要引用serviceB,在serviceB中定義了一個接口列表,serverA必須在serviceB初始化時設置進列表。
          在純bean的情況下,也就是這兩個類不需要設置其他bean的情況下,循環引用是正常的,可以通過的。例如下面配置所表示:

              <bean id="serviceA" class="A"  autowire="byName"  lazy-init="true">
               <property name="serviceB"><ref local="serviceB"/></property>
              </bean>
           <bean id="serviceB" class="B"  autowire="byName"  lazy-init="true">
               <property name="serviceA"><ref bean="serviceA"/></property>
           </bean>
          但是作為一個業務接口,它應該是不需要關心事務,回滾這些無關的東西,
          但現實又有這樣的需求,所以我們必須保證透明的實現這個功能,于是引
          入了AOP方式解決該問題,利用的是Spring自帶的org.springframework.t
          ransaction.interceptor.TransactionProxyFactoryBean.
          重新聲明文件如下:
             <bean id="baseTxProxy" lazy-init="true"
                class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
                  <property name="proxyTargetClass"><value>true</value></property>
                  <property name="transactionAttributes">
                      <props>
            <prop key="*">PROPAGATION_REQUIRED</prop>
                      </props>
                  </property>
              </bean>
               
              <bean id="serviceA" parent="baseTxProxy">
               <property name="target"><ref local="serviceAImpl"/></property>
              </bean>
             
             <bean id="serviceAImpl" class="serviceA"  autowire="byName"  lazy-init="true">
               <property name="serviceB">
                   <ref bean="serviceB"/>
               </property>
             </bean>
             
              <bean id="serviceB" parent="baseTxProxy" lazy-init="true">
               <property name="target"><ref local="serviceBImpl"/></property>
              </bean>
            
             <bean id="serviceBImpl" class="D" lazy-init="true">
               <property name="serviceA">
                   <ref bean="serviceA"/>
               </property>
             </bean>
          于是問題就出現了,Spring報了FactoryBeanCircularReferenceException,無法繼續完成設置工作。
          查看TransactionProxyFactoryBean源碼,其實現了FactoryBean和InitializingBean接口,應該是
          做了代理之后,兩個代理Bean需要等待所有Bean設置完成后才會標識狀態為初始化完畢,于是造成了
          沖突。

              由于兩個業務服務互相調用的路徑是不相交的,所以采用了一種變通的方法,在聲明serviceA時,
          直接定義serviceB:
            <bean id="serviceAImpl" class="serviceA"  autowire="byName"  lazy-init="true">
               <property name="serviceB">
                   <bean class="B"  autowire="byName"/>
               </property>
           </bean>
          相當于serviceB和serviceA中使用的serviceB不是同一個實例。
           
           但是如果確實調用重合時怎么辦?
           
           解決方法是這樣的:
           
           <bean id="serviceAImpl" class="serviceA"  autowire="byName"  lazy-init="true">
               <property name="serviceB">
                   <ref bean="serviceBImpl"/>
               </property>
           </bean>
           
            非常簡單,serviceAImpl調用時,可能已經在事務環境中了,不需再使用serviceB代理的事務支持,
            于是直接引用serviceB實例。這個方法是我寫這篇文章時想到的,-_-!!!,看來知識果真還是好好
            整理呀。

           

          posted @ 2006-02-08 16:32 java小記 閱讀(898) | 評論 (0)編輯 收藏
          關于網站開發中連接的可移植性總結

          網絡主機地址http://localhost:
          8080/

          1. 相對于根目錄的連接,形如: "/another.jsp"
           
           /DIR/目錄下的
           <a href
          ="/another.jsp">Link</a>
           <html:link href
          ="/another.jsp">Link</html:link>
           <html:link page
          ="/another.jsp">Link</html:link> 
           在默認ROOT應用中
          ,分別連接到地址:
           http://localhost:
          8080/another.jsp
           http://localhost:
          8080/another.jsp
           http://localhost:
          8080/another.jsp 
           在應用test中
          ,分別連接到地址:
           http://localhost:
          8080/another.jsp
           http://localhost:
          8080/another.jsp
           http://localhost:
          8080/test/another.jsp 
           
          2. 相對于當前目錄的連接,形如: "./another.jsp" 或 "another.jsp"
           
           /DIR/目錄下的
           <a href
          ="./another.jsp">Link</a> 
           <html:link href
          ="./another.jsp">Link</html:link>
           <html:link page
          ="./another.jsp">Link</html:link> 
           在默認ROOT應用中
          ,都分別連接到地址:
           http://localhost:
          8080//DIR/another.jsp
           http://localhost:
          8080//DIR/another.jsp
           http://localhost:
          8080//DIR/another.jsp  
           在應用test中
          ,分別連接到地址:
           http://localhost:
          8080//DIR/another.jsp
           http://localhost:
          8080//DIR/another.jsp
           http://localhost:
          8080/test./another.jsp   錯誤連接(而且與DIR無關,都連接到此地址)
            
           /DIR/目錄下的
           <a href
          ="another.jsp">Link</a> 
           <html:link href
          ="another.jsp">Link</html:link> 
           <html:link page
          ="another.jsp">Link</html:link> 
           在默認ROOT應用中
          ,都分別連接到地址:
           http://localhost:
          8080//DIR/another.jsp
           http://localhost:
          8080//DIR/another.jsp
           http://localhost:
          8080//DIR/another.jsp   
           在應用test中
          ,分別連接到地址:
           http://localhost:
          8080//DIR/another.jsp
           http://localhost:
          8080//DIR/another.jsp
           http://localhost:
          8080/testanother.jsp       錯誤連接(而且與DIR無關,都連接到此地址)
           
          3總結
           由于在網站開發時經常不使用默認的WEB應用,而可能把一個模塊開發成一個WEb應用(可能多人合作),
           但是在發布的時候要把所有模塊發布為一個WEB應用,并通常是默認的WEB應用,為了使URL不依賴于Web應用
           和是否是默認WEB應用,建議如下
            a.對于相對于WEB應用根目錄的連接
          ,形如: "/another.jsp"
              使用<html:link page
          ="/..">Link </html:link>
            b.對于相對于當前目錄的連接,形如: 
          "./another.jsp" 或 "another.jsp"
              使用<html:link href
          ="./another.jsp">Link </html:link>
                  <a href
          ="./another.jsp">Link </a>或        
                  <html:link href
          ="another.jsp">Link </html:link>
                  <a href
          ="another.jsp">Link </a>
              不要使用<html:link page
          ="./another.jsp">Link </html:link>
                      <html:link page
          ="another.jsp">Link </html:link> 此二者不可移植
            c.建議使用struts的html標簽庫<html:link..標簽,因為當用戶關閉Cookie時會自動重寫URL,所以概括
              兩句話:相對應用根目錄用<html:link page
          ="/.."  
                      相對當前的目錄用<html:link href
          ="./XXXXX.jsp"   或 <html:link href="XXXXX.jsp"  
           
           
          4.補充
            還有一個標簽<html:link forward
          ="forwardname"> Link </html:link> 上面沒有提到,現做以說明。
            
            forward屬性和struts配置文件<global-forwards>中的一個<forward>元素匹配,不能和<action>中<forward>匹配。
            
            例子:<global-forwards>
                   <forward name
          ="forwardname" path="//another.jsp"/>
                 </global-forwards>
                 
                 <html:link forward
          ="forwardname"> Link </html:link>
                 相當于<html:link page
          ="//another.jsp"> Link </html:link>
            需要注意的是:<global-forwards>中<forward>的path要使用相對于WEB應用的根目錄路徑,包括<action>中也是。
            
            在struts1.1多應用模塊時<html:link forwad. 有時不好使,不知道為什么????(好像是模塊切換狀態
            不對)所以最好不用。
            替代方法;
            網頁中用連接
              <html:link page
          ="/forwardaction.do">forward</html:link>
            在action-mapping配置如下action
               <action  path
          ="/forwardaction"  forward="/index.jsp" />
            
          posted @ 2006-02-06 20:58 java小記 閱讀(210) | 評論 (0)編輯 收藏
          package aa;

          import java.util.ArrayList;
          import java.util.Date;
          import java.util.List;

          //for test6
          import static java.lang.Math.*;

          public class Test {

              
          public static void main(String[] args) {
                  
          // 1
                  Double d = 123.45;
                  d 
          += 20.601;
                  System.out.println(d);
                  
          double dd = d + 45.123;
                  System.out.println(dd);

                  
          // 2,3
                  List<List<String>> list = new ArrayList<List<String>>();

                  List
          <String> line1 = new ArrayList<String>();
                  line1.add(
          "hello");
                  line1.add(
          ",");
                  line1.add(
          "world");
                  
          // line1.add(new Integer(123));//complie error
                  list.add(line1);

                  List
          <String> line2 = new ArrayList<String>();
                  line2.add(
          "hello2");
                  line2.add(
          ",");
                  line2.add(
          "world2");
                  list.add(line2);

                  
          for (List<String> g : list) {
                      
          for (String str : g) {
                          System.out.print(str);
                      }

                      System.out.println();
                  }


                  
          // 4
                  Color bg = Color.Red;
                  System.out.println(bg);

                  
          for (Color c : Color.values()) {
                      System.out.println(c);
                  }


                  
          // 5
                  print("hello"",""World"new Date(), 123456);
                  
                  
          //6
                  double i=2*PI;
                  print(i);

              }


              
          public static void print(Object objects) {
                  
          for (Object obj : objects) {
                      System.out.println(obj);
                  }

              }


          }


          enum Color {
              Red, Green, Blue
          }

          posted @ 2006-02-05 10:55 java小記 閱讀(233) | 評論 (0)編輯 收藏
          eclipse2不支持jdk1.5支持1.4
          eclipse3.0好象也不支持jdk1.5
          eclipse3.1支持jdk1.5

          jbuilder9不支持jdk1.5支持1.4
          jbuilder2006好象集成的就是jdk1.5,沒用過
          posted @ 2006-02-05 10:52 java小記 閱讀(238) | 評論 (0)編輯 收藏

          創建一個密鑰文件,
          %JAVA_HOME%/bin/keytool -genkey -alias myalias   -keyalg RSA  -validity 3650 -keystore ./mykeystorefilename

          修改conf/server.xml,打開Tomcat的HTTPS端口,
              <Connector port="8443"
                         maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
                         enableLookups="false" disableUploadTimeout="true"
                         acceptCount="100" debug="0" scheme="https" secure="true"
                         keystoreFile="mykeystorefilepath" 
                         keystorePass="mykeystorepassword" >
                <Factory clientAuth="false" protocol="TLS" />
              </Connector>
             
          在應用中修改web.xml,增加授權區
          <security-constraint>
                  <web-resource-collection>
                          <url-pattern>/*</url-pattern>
                          <http-method>GET</http-method>
                          <http-method>POST</http-method>
                  </web-resource-collection>
                  <user-data-constraint>
                          <transport-guarantee>CONFIDENTIAL</transport-guarantee>
                  </user-data-constraint>
          </security-constraint>

          posted @ 2006-01-21 21:32 java小記 閱讀(167) | 評論 (0)編輯 收藏


          指定網絡名稱不可用
          The specified network name is no longer available. : winnt_accept: Asynchronous AcceptEx failed.

          An operation was attempted on something that is not a socket.:winnt_accept: AcceptEx failed. Attempting to recover.

          出現這樣的問題,解決方法是:禁止使用AcceptEx,方法為在httpd.conf文件中增加Win32DisableAcceptEx標記,例如:
                 <IfModule mpm_winnt.c>
                 ..........
                       Win32DisableAcceptEx
                 .........
                 </IfModule>
          雖然這樣會使性能降低一些.
          from apache docs2.0:
          AcceptEx() is a Microsoft WinSock v2 API that provides some performance improvements over the use of
          the BSD style accept() API in certain circumstances. Some popular Windows products, typically virus
          scanning or virtual private network packages, have bugs that interfere with the proper operation of
          AcceptEx(). If you encounter an error condition like:
          [error] (730038)An operation was attempted on something that is not a socket.: winnt_accept: AcceptEx
          failed. Attempting to recover.
          you should use this directive to disable the use of AcceptEx().

          posted @ 2006-01-21 21:07 java小記 閱讀(365) | 評論 (0)編輯 收藏

          在tomcat配置文件server.xml的<Connector ... />配置中,有和連接數相關的參數:
           <Connector
          port="8080"               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
                         enableLookups="false" redirectPort="8443" acceptCount="100"
                         debug="0" connectionTimeout="20000"
                         disableUploadTimeout="true" />

          web server允許的最大連接數還受制于操作系統的內核參數設置,通常Windows是2000個左右,Linux是1000個左右。

          posted @ 2006-01-05 13:29 java小記 閱讀(643) | 評論 (0)編輯 收藏
          在tomcat_home /conf/web.xml中,把listings參數設置成false即可
          <servlet>
          ...
          <init-param>
          <param-name>listings</param-name>
          <param-value>false</param-value>
          </init-param>
          ...
          </servlet>
          posted @ 2006-01-05 13:21 java小記 閱讀(165) | 評論 (0)編輯 收藏

          下面的這兩個文件,尺寸差別很大.
          %JAVA_HOME%/jre/bin/client/jvm.dll
          %JAVA_HOME%/jre/bin/server/jvm.dll
          Jvm動態庫有client和server兩個版本,分別針對桌面應用和服務器應用做了相應的優化,
          client版本加載速度較快,server版本加載速度較慢但運行起來較快。

          讓Tomcat 使用Server版本的jvm吧,在開始菜單 tomcat5 ->tomcat config的java屬性中有一項 jvm路徑指向server目錄下的jvm就行了。

          更改默認java.exe調用的jvm.dll,這個由jvm.cfg決定。
          編輯%JAVA_HOME%\jre\lib\i386\jvm.cfg 
          里面第一行寫的是 -client 默認就是client版本 ,把第二行的-server KNOWN 放到第一行, 如下面所示
          -server KNOWN
          -client KNOWN
          -hotspot ALIASED_TO -client
          -classic WARN
          -native ERROR
          -green ERROR
          改完保存,然后看看默認版本:
          C:\java -version
          java version "1.4.2_07"
          Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_07-b05)
          Java HotSpot(TM) Server VM (build 1.4.2_07-b05, mixed mode)
          看到有 Server VM 字樣

          posted @ 2006-01-05 13:09 java小記 閱讀(245) | 評論 (0)編輯 收藏


          內存不足 (OOM) - 由于 java 堆或本地內存中的內存耗盡,應用程序顯示“內存不足”錯誤。
          內存泄漏 - java 堆或本地內存的持續內存增長,最終將導致內存不足狀態。調試內存泄漏狀態的技術與調試內存不足狀態的技術相同。

          Java 堆 - 這是 JVM 用來分配 java 對象的內存。java 堆內存的最大值用 java 命令行中的 -Xmx 標志來指定。
          如果未指定最大的堆大小,那么該極限值由 JVM 根據諸如計算機中的物理內存量和該時刻的可用空閑內存量這類
          因素來決定。始終建議您指定最大的 java 堆值。

          本地內存 - 這是 JVM 用于其內部操作的內存。JVM 將使用的本地內存堆數量取決于生成的代碼量、創建的線程、
          GC 期間用于保存 java 對象信息的內存,以及在代碼生成、優化等過程中使用的臨時空間。
          如果有一個第三方本地模塊,那么它也可能使用本地內存。例如,本地 JDBC 驅動程序將分配本地內存。
          最大本地內存量受到任何特定操作系統上的虛擬進程大小限制的約束,也受到用 -Xmx 標志指定用于 java 堆的內存量的限制。
          例如,如果應用程序能分配總計為 3 GB 的內存量,并且最大 java 堆的大小為 1 GB,那么本地內存量的最大值可能在 2 GB 左右。
           
          進程大小 - 進程大小將是 java 堆、本地內存與加載的可執行文件和庫所占用內存的總和。在 32 位操作系統上,進程的虛擬地址
          空間最大可達到 4 GB。從這 4 GB 內存中,操作系統內核為自己保留一部分內存(通常為 1 - 2 GB)。剩余內存可用于應用程序。

          Windows缺省情況下,2 GB 可用于應用程序,剩余 2 GB 保留供內核使用。但是,在 Windows 的一些變化版本中,有一個 /3GB 開關
          可用于改變該分配比率,使應用程序能夠獲得 3 GB。有關 /3GB 開關的詳細信息,可以在以下網址中找到:
          http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ddtools/hh/ddtools/bootini_1fcj.asp
          RH Linux AS 2.1 - 3 GB 可用于應用程序。

          進程地址空間和物理內存之間的差異:
          每個進程都獲得其自有的地址空間。在 32 位操作系統中,此地址空間范圍為 0 到 4 GB。此范圍與計算機的可用隨機存取內存 (RAM)
          或交換空間無關。計算機中的可用物理內存總量是該計算機上的可用 RAM 和交換空間之和。所有運行的進程共享這些物理內存。

          進程內的存儲地址是虛擬地址。內核將此虛擬地址映射到物理地址上。物理地址指向物理內存中的某個位置。在任一給定時間,計算機
          中運行進程所使用的全部虛擬內存的總和不能超過該計算機上可用物理內存的總量。


          為什么會發生 OOM 問題,JVM 在這種情況下如何處理?

          如果 JVM 不能在 java 堆中獲得更多內存來分配更多 java 對象,將會拋出 java 內存不足 (java OOM) 錯誤。如果 java 堆充滿了活
          動對象,并且 JVM 無法再擴展 java 堆,那么它將不能分配更多 java 對象。
          在這種情況下,JVM 讓應用程序決定在拋出 java.lang.OutOfMemoryError 后該執行什么操作。例如,應用程序可以處理此錯誤,并決定
          以安全方式自行關閉或決定忽略此錯誤。如果應用程序不處理此錯誤,那么拋出此錯誤的線程將退出(如果您進行 java Thread Dump,那
          么將看不到該線程)。

          在使用 Weblogic Server 的情況下,如果此錯誤是由某個執行線程拋出的,則會處理此錯誤并將其記錄在日志中。如果連續拋出此錯誤,
          那么核心運行狀況監視器線程將關閉 Weblogic Server。

          如果 JVM 無法獲得更多本地內存,它將拋出本地內存不足(本地 OOM)錯誤。當進程到達操作系統的進程大小限值,或者當計算機用完
          RAM 和交換空間時,通常會發生這種情況。當發生這種情況時,JVM 處理本地 OOM 狀態,記錄說明它已用完本地內存或無法獲得內存的
          消息,然后退出。如果 JVM 或加載的任何其它模塊(如 libc 或第三方模塊)不處理這個本地 OOM 狀態,那么操作系統將給 JVM 發送
          命令 JVM 退出的 sigabort 信號。通常情況下,JVM 收到 sigabort 信號時將會生成一個核心文件。


          排除故障的步驟:
          確定是 Java OOM 還是本地 OOM:
          如果 stdout/stderr 消息說明這是一個 java.lang.OutOfMemoryError,那么這就是 Java OOM
          如果 stdout/stderr 消息說明無法獲得內存,那么這就是本地 OOM
          請注意,上述消息僅發送到 stdout 或 stderr 中,而不發送到應用程序特定的日志文件(如 weblogic.log)


          對于 Java OOM,收集和分析 verbose:gc 輸出 在 java 命令行中添加“-verbose:gc”標志。這樣將會把 GC 活動信息打印到
          stdout/stderr。將 stdout/stderr 重定向到一個文件。運行應用程序,直到該問題重現。 確保 JVM 在拋出 java OOM 之
          前完成下列任務,執行一次完整 GC 運行,并且刪除了所有不可及對象以及虛可及、弱可及、軟可及對象,并回收了那些空間。
          有關不同級別的對象可及性的詳細信息,可以在以下網址中可找到:
          http://java.sun.com/developer/technicalArticles/ALT/RefObj
          您可以檢查是否在發出 OOM 消息之前執行了完整 GC 運行。當完成一次完整 GC 運行時,將會打印類似如下消息(格式取決
          于 JVM - 請查看 JVM 幫助信息以了解有關格式)
          [memory ] 7.160: GC 131072K->130052K (131072K) in 1057.359 ms
          以上輸出的格式如下(備注:在此模式下將全部使用相同的格式):
          [memory ] <start>: GC <before>K-><after>K (<heap>K), <total> ms
          [memory ] <start> - start time of collection (seconds since jvm start)
          [memory ] <before> - memory used by objects before collection (KB)
          [memory ] <after> - memory used by objects after collection (KB)
          [memory ] <heap> - size of heap after collection (KB)
          [memory ] <total> - total time of collection (milliseconds)

          但是,沒有辦法斷定是否使用 verbose 消息刪除了軟/弱/虛可及的對象。如果您懷疑在拋出 OOM 時這些對象仍然存在,請
          與 JVM 供應商聯系。

          如果垃圾回收算法是一種按代回收算法(對于 Jrockit 為 gencopy 或 gencon,對于其它 JDK 則是缺省算法),您也將看
          到類似如下的 verbose 輸出:
          [memory ] 2.414: Nursery GC 31000K->20760K (75776K), 0.469 ms
          以上是 nursery GC(即 young GC)周期,它將把活動對象從 nursery(或 young 空間)提升到 old 空間。這個周期對我
          們的分析不重要。有關按代回收算法的詳細信息,可以在 JVM 文檔中找到。
          如果在 java OOM 之前未發生 GC 周期,那么這是一個 JVM 錯誤。

          完全壓縮:
          確保 JVM 執行了適當的壓縮工作,并且內存并未成碎片(否則會阻止分配大對象并觸發 java OOM 錯誤)。
          Java 對象要求內存是連續的。如果可用空閑內存是一些碎片,那么 JVM 將無法分配大對象,因為它可能無法放入任何可用
          空閑內存塊中。在這種情況下,JVM 將執行一次完全壓縮,以便形成更多連續的空閑內存來容納大對象。
          壓縮工作包括在 java 堆內存中將對象從一個位置移動到另一個位置,以及更新對這些對象的引用以指向新位置。除非確有
          必要,否則 JVM 不會壓縮所有對象。這是為了減少 GC 周期的暫停時間。
          我們可以通過分析 verbose gc 消息來檢查 java OOM 是否由碎片引起。如果您看到類似如下的輸出(在此無論是否有可用
          的空閑 java 堆都會拋出 OOM),那么這就是由碎片引起的。

          [memory ] 8.162: GC 73043K->72989K (131072K) in 12.938 ms
          [memory ] 8.172: GC 72989K->72905K (131072K) in 12.000 ms
          [memory ] 8.182: GC 72905K->72580K (131072K) in 13.509 ms
          java.lang.OutOfMemoryError
          在上述情況中您可以看到,所指定的最大堆內存是 128MB,并且當實際內存使用量僅為 72580K 時,JVM 拋出 OOM。堆使用量
          僅為 55%。因此在這種情況下,碎片影響是:即使還有 45% 的空閑堆,內存也會拋出 OOM。這是一個 JVM 錯誤或缺陷。您應
          當與 JVM 供應商聯系。

          如果 JVM 一切都正常(上一步中提到的所有操作),那么此 java OOM 可能是應用程序的問題。應用程序可能在不斷泄漏一些
          java 內存,而這可能導致出現上述問題。或者,應用程序使用更多的活動對象,因此它需要更多 java 堆內存。在應用程序中
          可以檢查以下方面: 應用程序中的緩存功能 - 如果應用程序在內存中緩存 java 對象,則應確保此緩存并沒有不斷增大。對
          緩存中的對象數應有一個限值。我們可以嘗試減少此限值,來觀察其是否降低 java 堆使用量。 Java 軟引用也可用于數據緩存,
          當 JVM 用完 java 堆時,可以保證刪除軟可及對象。

          長期活動對象 - 如果應用程序中有長期活動對象,則可以嘗試盡可能減少這些對象的存在期。例如,調整 HTTP 會話超時值將
          有助于更快地回收空閑會話對象。
          內存泄漏 - 內存泄漏的一個例子是在應用服務器中使用數據庫連接池。當使用連接池時,必須在 finally 塊中顯式關閉 JDBC
          語句和結果集對象。這是因為,當從池中調用連接對象上的 close() 時,只是簡單地把連接返回池中以供重用,并沒有實際關閉
          連接和關聯的語句/結果集對象。

          增加 java 堆 - 如果可能的話,我們也可嘗試增加 java 堆,以觀察是否能解決問題。

          如果上述建議都不適用于該應用程序,那么,我們需要使用一個基于 JVMPI(JVM 事件探查器接口)的事件探查器(如 Jprobe 或
          OptimizeIt)來找出哪些對象正在占用 java 堆。事件探查器還提供 java 代碼中正在創建這些對象的位置的詳細信息。本文檔并
          不介紹每個事件探查器的詳細信息。可以參考事件探查器文檔來了解如何用事件探查器設置和啟動應用程序。一般而言,基于 JVMPI
           的事件探查器需要較高的系統開銷,并會大大降低應用程序的性能。因此,在生產環境中使用這些事件探查器并不可取。
          http://www.borland.com/optimizeit
          http://www.quest.com/jprobe

          對于本地 OOM 問題:
          收集下列信息: .verbosegc 輸出,通過它可監視 java 堆使用量。這樣將有助于了解此應用程序的 java 內存要求。
          應當注意,指定的最大堆內存量(在 java 命令行中使用 Xmx 標志)與應用程序的實際 java 堆使用量無關,其在 JVM 啟動時被保留,
          并且此保留內存不能用于其它任何用途。

          在使用 Jrockit 時,使用 -verbose 來代替 -verbosegc,因為這可以提供 codegen 信息以及 GC 信息。
          定期記錄進程虛擬內存大小,從啟動應用程序時起直到 JVM 用完本地內存。這樣將有助于了解此進程是否確實達到該操作系統的大小限
          值。在 Windows 環境下,使用下列步驟來監視虛擬進程大小:
          在“開始” -> “運行”對話框中,輸入“perfmon”并單擊“確定”。
          在彈出的“性能”窗口中,單擊“+”按鈕(圖表上部)。
          在顯示的對話框中選擇下列選項:
          性能對象:進程(不是缺省的處理器)
          從列表中選擇計數器:虛擬字節數
          從列表中選擇實例:選擇 JVM (java) 實例
          單擊“添加”,然后單擊“關閉”
          在 Unix 或 Linux 環境下,對于一個給定 PID,可以使用以下命令來查找虛擬內存大小 - ps -p <PID> -o vsz。

          在 Linux 環境下,單個 JVM 實例內的每個 java 線程都顯示為一個獨立的進程。如果我們獲得根 java 進程的 PID,那么這就足夠了。
          可以使用 ps 命令的 .forest 選項來找到根 java 進程。例如,ps lU <user> --forest 將提供一個由指定用戶啟動的所有進程的 ASCII
          樹圖。您可以從該樹圖中找到根 java。

          計算機中的內存可用性
          如果計算機沒有足夠的 RAM 和交換空間,則操作系統將不能為此進程提供更多內存,這樣也會導致內存不足。請確保 RAM 與磁盤中的交換
          空間之和足以滿足該計算機中正在運行的所有進程的需要。

          調整 java 堆
          如果 java 堆使用量完全在最大堆范圍內,則減小 java 最大堆將為 JVM 提供更多的本地內存。這不是一個解決辦法,而是一個可嘗試的變
          通方法。由于操作系統限制進程大小,我們需要在 java 堆和本地堆之間尋求一個平衡。
          JVM 的本地內存使用量
          在加載了所有類并調用了方法(代碼生成結束)后,JVM 的本地內存用量預計將會幾乎達到穩定。對于大多數應用程序而言,這通常發生在
          最初幾小時內。此后,JVM 可能會因加載運行時類型、生成優化代碼等處理而僅使用少量本地內存。

          為了縮小問題的范圍,可嘗試禁用運行時優化,并檢查這是否會產生任何效果。

          在使用 Jrockit 時,可使用 -Xnoopt 標志來禁用運行時優化。

          在使用 SUN hotspot JVM 時,-Xint 標志將強迫 JVM 在解釋模式中運行(不生成代碼)。
          如果在整個運行過程中,本地內存使用量繼續不斷增加,那么這可能是本地代碼中的內存泄漏。

          第三方本地模塊或應用程序中的 JNI 代碼
          檢查您是否在使用類似數據庫驅動程序的任何第三方本地模塊。這些本地模塊也可以分配本地內存,泄漏可能從這些模塊中發生。為了縮
          小問題的范圍,應嘗試在沒有這些第三方模塊的情況下重現問題。例如,可以使用純 java 驅動程序來代替本地數據庫驅動程序。

          檢查應用程序是否使用一些 JNI 代碼。這也可能造成本地內存泄漏,如果可能的話,您可以嘗試在沒有 JNI 代碼的情況下運行應用程序。

          如果在執行上述步驟后還不能找到本地內存泄漏的根源,那么您需要與 JVM 供應商合作來獲得一個特殊的編譯版本,它可以跟蹤本地內存
          分配調用,并可提供有關泄漏的更多信息。

          Jrockit 特定特性
          Jrockit 81SP1 和更高版本支持 JRA 記錄(Java 運行時間分析器)。這對于收集 JVM 運行時的信息很有用,將提供應用程序的有關信息,
          例如,正在運行的 GC 數、軟/弱/虛引用的數目、熱方法,等等。如果 JVM 出現性能問題或掛起問題,那么用幾分鐘進行記錄和分析數據
          就會很有用。有關詳細信息,可以在 Jrockit 文檔中找到。
          http://e-docs.bea.com/wljrockit/docs142/userguide/jra.html


          如果您已經理解這個模式,但仍需要其它幫助,您可以:
          http://support.bea.com 上查詢 AskBEA(例如使用“out of memory”),以查找其它已發布的解決方案。
          http://support.bea.com 上,向 BEA 的某個新聞組中提出更詳細具體的問題。
          如果這還不能解決您的問題,并且您擁有有效的技術支持合同,您可以通過登錄以下網站來打開支持案例:http://support.bea.com
           

          posted @ 2005-12-21 21:48 java小記 閱讀(410) | 評論 (0)編輯 收藏

          修改 windows: mysql-root/my.ini  (mysql-4.1.14-win32.zip)
               linux:   /etc/my.cnf
          將其中的default-character-set都改成gbk
          也就是如下兩個SECTION
          [client] 
          。。。。
          default-character-set=gbk
          。。。。


          [mysqld]
          。。。。
          default-character-set=gbk
          。。。。


          Linux上:
          mysql> show variables like "%set%";
          +--------------------------+----------------------------------------------------
          ----------------------+
          | Variable_name            | Value
                                |
          +--------------------------+----------------------------------------------------
          ----------------------+
          | character_set_client     | gbk
                                |
          | character_set_connection | gbk
                                |
          | character_set_database   | gbk
                                |
          | character_set_results    | gbk
                                |
          | character_set_server     | gbk
                                |
          | character_set_system     | utf8
                                |
          | character_sets_dir       | /usr/local/mysql-standard-4.1.12-pc-linux-gnu-i686/
          share/mysql/charsets/ |
          +--------------------------+----------------------------------------------------
          ----------------------+
          7 rows in set (0.00 sec)
          此時可以查看中文的字段,應該一切正常顯示。如果不正常顯示說明數據庫中存放的不是正確編碼。


          Windows上:
          mysql> show variables like "%set%";
          +--------------------------+--------------------------+
          | Variable_name            | Value                    |
          +--------------------------+--------------------------+
          | character_set_client     | latin1                   |
          | character_set_connection | latin1                   |
          | character_set_database   | gbk                      |
          | character_set_results    | latin1                   |
          | character_set_server     | gbk                      |
          | character_set_system     | utf8                     |
          | character_sets_dir       | D:\MySql\share\charsets/ |
          +--------------------------+--------------------------+
          7 rows in set (0.00 sec)

          不知道為什么在windows上my.ini中
          [client]
          。。。。
          default-character-set=gbk
          沒有起作用。

          Windows上登錄mysql,更改會話的編碼為gbk

          mysql> set names "gbk";
          Query OK, 0 rows affected (0.00 sec)

          mysql> show variables like "%set%";
          +--------------------------+--------------------------+
          | Variable_name            | Value                    |
          +--------------------------+--------------------------+
          | character_set_client     | gbk                      |
          | character_set_connection | gbk                      |
          | character_set_database   | gbk                      |
          | character_set_results    | gbk                      |
          | character_set_server     | gbk                      |
          | character_set_system     | utf8                     |
          | character_sets_dir       | D:\MySql\share\charsets/ |
          +--------------------------+--------------------------+
          7 rows in set (0.00 sec)

          此時可以查看中文的字段,應該一切正常顯示。如果不正常顯示說明數據庫中存放的不是正確編碼。


          完全備份MySql
          Linux上:
            mysqldump  --user=myname --password=mypassword  mydb >mydb_backup.sql
          Windows上:
           Linux上:
            mysqldump   --default-character-set=gb2312 --user=myname --password=mypassword  mydb >mydb_backup.sql

          Windows腳本自動登陸
          D:\MySql\bin>mysql  --user=myname  --password=mypassword   --default-character-set=gbk   --host=192.168.0.17

          posted @ 2005-12-20 15:56 java小記 閱讀(551) | 評論 (0)編輯 收藏

          項目中需要對安全問題引起足夠的重視,比如下列tomcat的安全問題容易被忽略:
           
          server.xml默認有下面一行:
          <Server port="8005" shutdown="SHUTDOWN">
          這樣允許任何人只要telnet到服務器的8005端口,輸入"SHUTDOWN",然后回車,服務器立即就被關掉了。
          從安全的角度上考慮,我們需要把這個shutdown指令改成一個別人不容易猜測的字符串。
          例如修改如下:
          <Server port="8006" shutdown="lizongbo">,這樣就只有在telnet到8006,并且輸入"lizongbo"才能夠關閉Tomcat.
          注意:這個修改不影響shutdown.bat的執行。運行shutdown.bat一樣可以關閉服務器。

           

          參考Tomcat安全文檔英文鏈接:http://jakarta.apache.org/tomcat/faq/security.html#8005
          還有兩個問題需要注意:
          1、  對于tomcat3.1中,屏蔽目錄文件自動列出的方法是什么?
          缺省情況下,如果你訪問tomcat下的一個web應用,那么如果你輸入的是一個目錄名,而且該目錄下沒有一個可用的welcome文件,那么tomcat會將該目錄下的所有文件列出來,如果你想屏蔽這個缺省行為,那么可以修改conf/web.xml文件,將其中的:
          <servlet>
          <servlet-name>default</servlet-name>
          <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
          <init-param>
          <param-name>debug</param-name>
          <param-value>0</param-value>
          </init-param>
          <init-param>
          <param-name>listings</param-name>
          <param-value>true</param-value>
          </init-param>
          <load-on-startup>1</load-on-startup>
          </servlet>
          修改為:
          <servlet>
          <servlet-name>default</servlet-name>
          <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
          <init-param>
          <param-name>debug</param-name>
          <param-value>0</param-value>
          </init-param>
          <init-param>
          <param-name>listings</param-name>
          <param-value>false</param-value>
          </init-param>
          <load-on-startup>1</load-on-startup>
          </servlet>


          2、 如何讓Tomcat記錄客戶端的訪問日志 
          下面是Tomcat相關手冊中的介紹:
          以下是引用來自 的內容:
          Valve (功能與Logger差不多,其prefix和suffix屬性解釋和Logger 中的一樣) className 指定Valve使用的類名,
          如用org.apache.catalina.valves.AccessLogValve類可以記錄應用程序的訪問信息 directory 指定log文件存放
          的位置 pattern 有兩個值,common方式記錄遠程主機名或ip地址,用戶名,日期,第一行請求的字符串,HTTP響
          應代碼,發送的字節數。combined方式比common方式記錄的值更多 

          所以需要完成的步驟:
             1。修改Tomcat的conf/server.xml文件。
             2。加上Valve節點到server.xml文件中,和您目前使用的Connector的節點平級。
                如:<Valve className="org.apache.catalina.valves.AccessLogValve"
                directory="e:\trs\trscds\tomcat\logs" pattern="combined"/>
             3。重新啟動您的Tomcat
             4。有用戶在訪問的時候,在指定的log目錄下面會生成一個access_log文件(每天一個)。
          上述的步驟是以Tomcat4.x為例。(可能會影響性能,不推薦大家使用)。

           

          還有一個問題:需要處理好Tomcat管理臺的安全。
          Tomcat管理臺的應用文件,默認在{Tomcat安裝目錄}\server\webapps下,有admin和manager兩個應用。
          其用戶密碼,在{Tomcat安裝目錄}\conf/tomcat-users.xml中定義。在{Tomcat安裝目錄}\webapps下
          admin.xml和manager.xml文件定義了可以通過訪問/admin和/manager進入。
          默認情況下,完全可以登錄tomcat管理臺,造成嚴重安全問題
          檢測辦法:用IE打開鏈接http://[IP]:[Port]/admin,以用戶名admin,密碼為空登錄,如果成功,
          說明存在問題。
          解決辦法:可以刪除{Tomcat安裝目錄}\webapps下admin.xml和manager.xml文件,或者去掉用戶密
          碼,也可以刪除應用文件。


          我們一個用戶提到如果找不到網頁即出現404錯誤,會顯示服務器版本號,服務器配置也一目了然,
          為了避免這種情況,希望自定義設置錯誤頁面。
          設置如下:
          1、將附件的index.htm文件拷貝至\webapps\ROOT目錄內,刪除或改名原來的index.jsp文件。
          2、用記事本打開\conf\web.xml文件,在文件的倒數第二行(</web-app>一行之前)加入以下內容:
                 <error-page> 
                  <error-code>404</error-code>
                  <location>/index.htm</location> 
                </error-page>


           

          posted @ 2005-12-20 15:54 java小記 閱讀(444) | 評論 (0)編輯 收藏

          默認安裝tomcat5然后在catalina.bat最前面加入set JAVA_OPTS=-Xms128m -Xmx350m 如果用startup.bat啟動tomcat,OK設置生效.夠成功的分配200M內存.

          但是如果不是執行startup.bat啟動tomcat而是利用windows的系統服務啟動tomcat服務,上面的設置就不生效了,就是說set JAVA_OPTS=-Xms128m -Xmx350m 沒起作用.上面分配200M內存就OOM了..

          windows服務執行的是bin\tomcat.exe.他讀取注冊表中的值,而不是catalina.bat的設置.

          解決辦法:
          修改注冊表HKEY_LOCAL_MACHINE\SOFTWARE\Apache Software Foundation\Tomcat Service Manager\Tomcat5\Parameters\JavaOptions
          原值為
          -Dcatalina.home="C:\ApacheGroup\Tomcat 5.0"
          -Djava.endorsed.dirs="C:\ApacheGroup\Tomcat 5.0\common\endorsed"
          -Xrs

          加入 -Xms300m -Xmx350m 
          重起tomcat服務,設置生效.

          posted @ 2005-12-20 11:58 java小記 閱讀(3292) | 評論 (0)編輯 收藏

          <2005年12月>
          27282930123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          常用鏈接

          留言簿(1)

          隨筆分類

          隨筆檔案

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 密云县| 疏附县| 涞水县| 织金县| 阳山县| 怀柔区| 双桥区| 遂川县| 夏河县| 梁山县| 桃园县| 甘肃省| 金寨县| 纳雍县| 温宿县| 错那县| 定州市| 夏津县| 化州市| 沅江市| 凤山县| 新建县| 海城市| 额济纳旗| 崇州市| 南宫市| 石林| 甘泉县| 东安县| 昆山市| 若尔盖县| 和平区| 新兴县| 黑河市| 米脂县| 灌南县| 郑州市| 临高县| 从江县| 西丰县| 龙游县|