posts - 35,  comments - 7,  trackbacks - 0

          隨著Hibernate在Java開發(fā)中的廣泛應(yīng)用,我們在使用Hibernate進(jìn)行對象持久化操作中也遇到了各種各樣的問題。這些問題往往都是我們對Hibernate缺乏了解所致,這里我講個我從前遇到的問題及一些想法,希望能給大家一點借鑒。
          ?
          ???????這是在一次事務(wù)提交時遇到的異常。
          ???????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?(那是另外的錯誤,類似但不一樣)
          ?
          ???????這個異常應(yīng)該很多的朋友都遇到過,原因可能各不相同。但所有的異常都應(yīng)該是在flush或者事務(wù)提交的過程中發(fā)生的。這一般由我們在事務(wù)開始至事務(wù)提交的過程中進(jìn)行了不正確的操作導(dǎo)致,也會在多線程同時操作一個Session時發(fā)生,這里我們僅僅討論單線程的情況,多線程除了線程同步外基本與此相同。
          ?
          ???????至于具體是什么樣的錯誤操作那?我給大家看一個例子(假設(shè)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)


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

          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();

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

          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的顯示數(shù)據(jù).??
          JList創(chuàng)建以后,JList數(shù)據(jù)元素的值及數(shù)據(jù)元素的數(shù)量可以動態(tài)地改變.??
          JList在它的數(shù)據(jù)模式ListModel中觀察數(shù)據(jù)的改變.因此,一個ListModel 的正確實現(xiàn)應(yīng)當(dāng)在每次數(shù)據(jù)發(fā)生改變時,通知事件的監(jiān)聽者.??
          當(dāng)使用構(gòu)造函數(shù)JList(Object[])創(chuàng)建一個JList的實例時,系統(tǒng)將自動 創(chuàng)建一個DefaultListModel的實例來存儲JList的顯示數(shù)據(jù), 可以調(diào)用 DefaultListModel中定義的簡便方法來動態(tài)地修改JList的數(shù)據(jù),如 removeElementAt(index),addElement(Object)等. DefaultListModel 在修改數(shù)據(jù)的同時,將通知JList關(guān)于數(shù)據(jù)的改變.??

          ?

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

          ?

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

          ????}

          ??}
          );
          }


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


          }
          posted @ 2006-04-28 08:28 java小記 閱讀(2710) | 評論 (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.
          舉個例子,從內(nèi)存地址0x0000開始有以下數(shù)據(jù)
          ?0x0000?????0x12
          ?0x0001?????0x34
          ?0x0002?????0xab
          ?0x0003?????0xcd
          如果我們?nèi)プx取一個地址為0x0000的四個字節(jié)變量,若字節(jié)序為big-endian,則讀出
          結(jié)果為0x1234abcd;若字節(jié)序位little-endian,則讀出結(jié)果為0xcdab3412.
          如果我們將0x1234abcd寫入到以0x0000開始的內(nèi)存中,則結(jié)果為
          ????????????????big-endian?????little-endian
          0x0000?????0x12??????????????0xcd
          0x0001?????0x23??????????????0xab
          0x0002?????0xab??????????????0x34
          0x0003?????0xcd??????????????0x12
          x86系列CPU都是little-endian的字節(jié)序.
          posted @ 2006-04-25 15:21 java小記 閱讀(329) | 評論 (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小記 閱讀(268) | 評論 (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,即使選擇工程的自動編譯開關(guān)也不好使,不知道是不是Bug
          我這樣解決的:
          1. project->properties->java build path->source->.../WEB-INF/src的output folder不要默認(rèn),編輯讓它指向../WEB-INF/classes
          然后重新點擊build工程即可自動編譯。

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


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

          在conf/server.xml中配置應(yīng)用的<Context......>下面的<Realm className="org.apache.catalina.realm.MemoryRealm" />
          從一個XML文件中讀取用戶信息,默認(rèn)的就是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>

          在應(yīng)用下的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>

          在應(yīng)用下的web.xml中加入<login-config>元素
          <login-config>     
             <auth-method>FORM</auth-method>
             <!--這里FORM是基于表單的驗證,會跳轉(zhuǎn)到mylogin.jsp,如果出錯就到myerror.jsp,
             還有基于對話筐的是BASIC關(guān)鍵字,但是不安全在網(wǎng)絡(luò)傳輸中。摘要驗證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必須嚴(yán)格規(guī)范寫
          <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拷貝到應(yīng)用的WEB-INF/lib下 ,
               并把etc目下下的oscache.properties拷貝到應(yīng)用的WEB-INF/classes下.
            3, 在應(yīng)用的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訪問需要操作數(shù)據(jù)庫,并且這些內(nèi)容一段時間內(nèi)很少改變,這樣在內(nèi)存緩存這個URL很有必要
            它可以降低數(shù)據(jù)庫訪問量。
           
            經(jīng)過以上配置后,當(dāng)?shù)谝淮卧L問/servlets/UserAllProducts時,從數(shù)據(jù)庫中查出所有產(chǎn)品列表并緩存到application中600秒。
            在600秒內(nèi)的任何訪問/servlets/UserAllProducts都不會真正執(zhí)行這個servlet,而直接從application中取出緩存的內(nèi)容。這樣
            就減少了數(shù)據(jù)庫的訪問量。
          posted @ 2006-02-09 18:58 java小記 閱讀(291) | 評論 (0)編輯 收藏

          <2006年2月>
          2930311234
          567891011
          12131415161718
          19202122232425
          2627281234
          567891011

          常用鏈接

          留言簿(1)

          隨筆分類

          隨筆檔案

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 依安县| 北京市| 哈巴河县| 赫章县| 甘泉县| 荣成市| 青浦区| 芮城县| 滨州市| 临泉县| 乐都县| 岳阳市| 西昌市| 肃宁县| 崇义县| 察雅县| 屏边| 铁力市| 莱西市| 会东县| 新乡市| 桐庐县| 黔江区| 清镇市| 老河口市| 南平市| 海安县| 墨竹工卡县| 科技| 密云县| 靖边县| 得荣县| 宁南县| 东阿县| 卢龙县| 温州市| 巧家县| 宜兴市| 武陟县| 康乐县| 卢氏县|