隨筆-59  評論-31  文章-0  trackbacks-0
            2011年12月31日

          Microsoft SQL Server 2008 基本安裝說明

          安裝SQL2008的過程與SQL2005的程序基本一樣,只不過在安裝的過程中部分選項有所改變,當然如果只熟悉SQL2000安裝的同志來說則是一個革命性的變動,

          一、安裝前的準備
          1. 需要.Net Framework 3.5,若在Vista或更高的OS上需要3.5 SP1的支持(在SQL2008安裝的前會自動更新安裝)
          2. 需要Widnows PowerShell的支持,WPS是一個功能非常強大的Shell應用,命令與DOX/UNIX兼容并支持直接調用.NET模塊做行命令編輯,是非常值得深入研究的工具(在SQL2008安裝時會自動更新安裝)
          3. 需要確保Windows Installer的成功啟動,需要4.5以上版本(需要檢查服務啟動狀態(tài)service.msc)
          4. 需要MDAC2.8 sp1的支持(XP以上系統中已集成)
          5. 若機器上已經安裝Visual studio 2008則需要VS 2008 sp1以上版本的支持(需要自己從MS的網站上下載安裝http://www.microsoft.com/downloads/details.aspx?familyid=FBEE1648-7106-44A7-9649-6D9F6D58056E&displaylang=en

           

          二、安裝配置過程
          1.進行SQL Server安裝中心,選擇"安裝"選項,在新的電腦上安裝SQL2008可以直接選擇“全新SQL Server獨立安裝或向現有安裝功能",將會安裝一個默認SQL實列,如下圖

          2.功能選擇,對于只安裝數據庫服務器來說,功能的選擇上可以按實際工作需要來制定,本人一般選擇:數據庫引擎服務、客戶端工具連接、SQL Server 聯機叢書、管理工具-基本、管理工具-完整
               其中數據庫引擎服務是SQL數據庫的核心服務,Analysis及Reporting服務可按部署要求安裝,這兩個服務可能需要IIS的支持。如下圖


          3.實列設置,可直接選擇默認實例進行安裝,或則若同一臺服務器中有多個數據服務實列可按不同實列名進行安裝。如圖


          4.服務器配置,服務器配置主要是服務啟動帳戶的配置,服務的帳戶名推薦使用NT AUTHORITY\SYSTEM的系統帳戶,并指定當前選擇服務的啟動類型,如圖

          5.數據庫引擎配置,在當前配置中主要設置SQL登錄驗證模式及賬戶密碼,與SQL的數據存儲目錄,身份驗證模式推薦使用混合模式進行驗證,在安裝過程中內置的SQL Server系統管理員帳戶(sa)的密碼比較特殊,SQL2008對SA的密碼強度要求相對比較高,需要有大小寫字母、數字及符號組成,否則將不允許你繼續(xù)安裝。在"指定Sql Server管理員"中最好指定本機的系統管理員administrator。如圖


           

          分類: SQL 雜文
          posted @ 2013-09-27 13:27 RoyPayne 閱讀(242) | 評論 (0)編輯 收藏
             谷歌瀏覽器的cookie:
                 依次點擊設置--高級選項--內容設置--cookies--選擇“顯示cookies和其他網站數據按鈕就可以看到了

          firefox:
                依次點開FF瀏覽器工具選項: 工具》選項》隱私》在歷史選項框中選擇“使用自定義歷史記錄設置” 進入后,再選擇“顯示Cookies”.出來一個對話框,里面就是FF記錄的所有Cookie。其值你也可以很方便查看到。




          posted @ 2013-01-28 06:54 RoyPayne 閱讀(2920) | 評論 (1)編輯 收藏
                死鎖是一個經典的多線程問題,因為不同的線程都在等待那些根本不可能被釋放的鎖,
          從而導致所有的工作都無法完成。假設有兩個線程,分別代表兩個饑餓的人,他們必須共享刀叉并輪流吃飯。
          他們都需要獲得兩個鎖:共享刀和共享叉的鎖。假如線程 "A" 獲得了刀,而線程 "B" 獲得了叉。
          線程 A 就會進入阻塞狀態(tài)來等待獲得叉,而線程 B 則阻塞來等待 A 所擁有的刀。
                
                讓所有的線程按照同樣的順序獲得一組鎖。這種方法消除了 X 和 Y 的擁有者分別等待對方的資源的問題。
            將多個鎖組成一組并放到同一個鎖下。前面死鎖的例子中,可以創(chuàng)建一個銀器對象的鎖。于是在獲得刀或叉之前都必須獲得這個銀器的鎖。
            將那些不會阻塞的可獲得資源用變量標志出來。當某個線程獲得銀器對象的鎖時,就可以通過檢查變量來判斷是否整個銀器集合中的對象鎖都可獲得。如果是,它就可以獲得相關的鎖,否則,就要釋放掉銀器這個鎖并稍后再嘗試。
            最重要的是,在編寫代碼前認真仔細地設計整個系統。多線程是困難的,在開始編程之前詳細設計系統能夠幫助你避免難以發(fā)現死鎖的問題。
          posted @ 2012-12-10 10:54 RoyPayne 閱讀(347) | 評論 (0)編輯 收藏
          <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
          <html>
           
          <head>
            
          <title> New Document </title>
            
          <meta name="Generator" content="EditPlus">
            
          <meta name="Author" content="">
            
          <meta name="Keywords" content="">
            
          <meta name="Description" content="">
           
          </head>
              
          <script type="text/javascript" src="jquery.js"></script>
              
          <script type="text/javascript">

                  
          function go() {
                      
          var str="";
                      $(
          "input[name='checkbox']:checkbox").each(function(){ 
                          
          if($(this).attr("checked")){
                              str 
          += $(this).val()+","
                          }
                      })
                      
          //alert(str);
                      str.split(",");
                      alert(str[
          0]);
                  }
              
          </script>
           
          <body>
            
          <div>
              
          <input type="text" id="content" value="111"/>
              
          <input type="checkbox" name="checkbox" value="1"/>
              
          <input type="checkbox" name="checkbox" value="2"/>
              
          <input type="checkbox" name="checkbox" value="3"/>
              
          <input type="checkbox" name="checkbox" value="4"/>
              
          <input type="checkbox" name="checkbox" value="5"/>
              
          <input type="button" id="test" onclick="go();"/>
            
          </div>
           
          </body>
          </html>
          posted @ 2012-03-02 09:40 RoyPayne 閱讀(88801) | 評論 (21)編輯 收藏
          XFire WebService開發(fā)快速起步


          http://lavasoft.blog.51cto.com/62575/105956/
          posted @ 2012-02-01 14:50 RoyPayne 閱讀(357) | 評論 (0)編輯 收藏
               摘要: oracle腳本:drop table t_student cascade constraints;Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->/*==================================================...  閱讀全文
          posted @ 2012-01-31 13:25 RoyPayne 閱讀(2253) | 評論 (2)編輯 收藏

          在Session的緩存中存放的是相互關聯的對象圖。默認情況下,當Hibernate從數據庫中加載Customer對象時,會同時加載所有關聯的 Order對象。以Customer和Order類為例,假定ORDERS表的CUSTOMER_ID外鍵允許為null

          以下Session的find()方法用于到數據庫中檢索所有的Customer對象: 

          List customerLists=session.find("from Customer as c"); 

          運行以上find()方法時,Hibernate將先查詢CUSTOMERS表中所有的記錄,然后根據每條記錄的ID,到ORDERS表中查詢有參照關系的記錄,Hibernate將依次執(zhí)行以下select語句: 

          select * from CUSTOMERS; 
          select * from ORDERS where CUSTOMER_ID=1; 
          select * from ORDERS where CUSTOMER_ID=2; 
          select * from ORDERS where CUSTOMER_ID=3; 
          select * from ORDERS where CUSTOMER_ID=4; 

          通過以上5條select語句,Hibernate最后加載了4個Customer對象和5個Order對象,在內存中形成了一幅關聯的對象圖.


          Hibernate在檢索與Customer關聯的Order對象時,使用了默認的立即檢索策略。這種檢索策略存在兩大不足: 

          (1) select語句的數目太多,需要頻繁的訪問數據庫,會影響檢索性能。如果需要查詢n個Customer對象,那么必須執(zhí)行n+1次select查詢語 句。這就是經典的n+1次select查詢問題。這種檢索策略沒有利用SQL的連接查詢功能,例如以上5條select語句完全可以通過以下1條 select語句來完成: 

          select * from CUSTOMERS left outer join ORDERS 
          on CUSTOMERS.ID=ORDERS.CUSTOMER_ID 

          以上select語句使用了SQL的左外連接查詢功能,能夠在一條select語句中查詢出CUSTOMERS表的所有記錄,以及匹配的ORDERS表的記錄。 

          (2)在應用邏輯只需要訪問Customer對象,而不需要訪問Order對象的場合,加載Order對象完全是多余的操作,這些多余的Order對象白白浪費了許多內存空間。 
          為了解決以上問題,Hibernate提供了其他兩種檢索策略:延遲檢索策略和迫切左外連接檢索策略。延遲檢索策略能避免多余加載應用程序不需要訪問的關聯對象,迫切左外連接檢索策略則充分利用了SQL的外連接查詢功能,能夠減少select語句的數目。


          對數據庫訪問還是必須考慮性能問題的, 在設定了1 對多這種關系之后, 查詢就會出現傳說中的n +1 問題。 
          1 )1 對多,在1 方,查找得到了n 個對象, 那么又需要將n 個對象關聯的集合取出,于是本來的一條sql查詢變成了n +1 條 
          2)多對1 ,在多方,查詢得到了m個對象,那么也會將m個對象對應的1 方的對象取出, 也變成了m+1

          怎么解決n +1 問題? 
          1 )lazy=true, hibernate3開始已經默認是lazy=true了;lazy=true時不會立刻查詢關聯對象,只有當需要關聯對象(訪問其屬性,非id字段)時才會發(fā)生查詢動作。 

          2)二級緩存, 在對象更新,刪除,添加相對于查詢要少得多時, 二級緩存的應用將不怕n +1 問題,因為即使第一次查詢很慢,之后直接緩存命中也是很快的。 
          不同解決方法,不同的思路,第二條卻剛好又利用了n +1 。

          3) 當然你也可以設定fetch=join(annotation : @ManyToOne() @Fetch(FetchMode.JOIN))

          posted @ 2012-01-30 14:20 RoyPayne 閱讀(10912) | 評論 (1)編輯 收藏
          1. 在web.xml文件中加入Filter聲明 
          <!-- Spring security Filter -->
          <filter>
              <filter-name>springSecurityFilterChain</filter-name>
              <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
          </filter>
          <filter-mapping>
              <filter-name>springSecurityFilterChain</filter-name>
              <url-pattern>/*</url-pattern>
          </filter-mapping>

          這個Filter會攔截所有的URL請求,并且對這些URL請求進行Spring Security的驗證。 

          注意,springSecurityFilterChain這個名稱是由命名空間默認創(chuàng)建的用于處理web安全的一個內部的bean的id。所以你在你的Spring配置文件中,不應該再使用這個id作為你的bean。 

          與Acegi的配置不同,Acegi需要自行聲明一個Spring的bean來作為Filter的實現,而使用Spring Security后,無需再額外定義bean,而是使用<http>元素進行配置。 

          通過擴展Spring Security的默認實現來進行用戶和權限的管理 

          事實上,Spring Security提供了2個認證的接口,分別用于模擬用戶和權限,以及讀取用戶和權限的操作方法。這兩個接口分別是:UserDetails和UserDetailsService。 

          public interface UserDetails extends Serializable {
              
              GrantedAuthority[] getAuthorities();

              String getPassword();

              String getUsername();

              boolean isAccountNonExpired();

              boolean isAccountNonLocked();

              boolean isCredentialsNonExpired();

              boolean isEnabled();
          }

          public interface UserDetailsService {
              UserDetails loadUserByUsername(String username)
                  throws UsernameNotFoundException, DataAccessException;
          }

          非常清楚,一個接口用于模擬用戶,另外一個用于模擬讀取用戶的過程。所以我們可以通過實現這兩個接口,來完成使用數據庫對用戶和權限進行管理的需求。在這里,我將給出一個使用Hibernate來定義用戶和權限之間關系的示例。 
          posted @ 2012-01-20 10:41 RoyPayne 閱讀(1721) | 評論 (1)編輯 收藏
               摘要: Quartz是一個強大的企業(yè)級任務調度框架,Spring中繼承并簡化了Quartz,下面就看看在Spring中怎樣配置Quartz:  閱讀全文
          posted @ 2012-01-19 14:53 RoyPayne 閱讀(317) | 評論 (0)編輯 收藏
          1.自定義攔截器繼承AbstractInterceptor,重寫public String intercept(ActionInvocation invocation)方法。
          intercept方法有ActionInvocation對象,可以獲取當前的Action請求。
          public class AuthorityInterceptor extends AbstractInterceptor {
              private static final long serialVersionUID = 1L; 
              private Logger LOG = Logger.getLogger(AuthorityInterceptor.class.getName()); 
              
              private AuthorityUtil authorityUtil;
              
              public String intercept(ActionInvocation invocation) throws Exception {
                  if (authorityUtil == null) {
                      authorityUtil = new AuthorityUtil();
                  }
                  
                  //獲取當前用戶所有的權限
                  List<OperatorPurviewDO> operatorPurviews = getCurrentOperatorPurviews();
                  
                  //獲取當前操作的url
                  String currentUrl = getCurrentUrl(); 
                  
                   //如果是超級管理員或有當前url的權限,那么直接返回。
                  if (OperatorUtil.getIsSuperAdmin() ||(OperatorUtil.getLoginName()!=null&&authorityUtil.checkUrl(operatorPurviews, currentUrl))){
                       return invocation.invoke();
                  }
                   
                  if (!OperatorUtil.getIsSuperAdmin()&&operatorPurviews.size()==0) {
                      LOG.info("此用戶:" + OperatorUtil.getLoginName() + " 沒有任何角色,沒有權限執(zhí)行任何功能"); 
                      return "loginErr"; 
                  }   
                      return "authorityErr";
              }

          2.struts2.xml 配置interceptor

            2.1 定義自定義攔截器
          <interceptor name="authorityInterceptor" class="com.wasu.eis.authority.AuthorityInterceptor" /> 
            2.2 加上struts2默認攔截器,形成攔截器棧
                      <interceptor-stack name="eisManagerBasicStack">
                          <interceptor-ref name="exception"/>
                          <interceptor-ref name="alias"/>
                          <interceptor-ref name="servletConfig"/>
                          <interceptor-ref name="prepare"/>
                          <interceptor-ref name="i18n"/>
                          <interceptor-ref name="chain"/>
                          <interceptor-ref name="debugging"/>
                          <interceptor-ref name="profiling"/>
                          <interceptor-ref name="scopedModelDriven"/>
                          <interceptor-ref name="modelDriven"/>
                          <interceptor-ref name="checkbox"/>
                          <interceptor-ref name="staticParams"/>
                          <interceptor-ref name ="fileUploadStack" /> 
                          <interceptor-ref name="params">
                            <param name="excludeParams">dojo\..*</param>
                          </interceptor-ref>
                          <interceptor-ref name="conversionError"/>
                          <interceptor-ref name="validation">
                              <param name="excludeMethods">input,back,cancel,browse</param>
                          </interceptor-ref>
                          <interceptor-ref name="workflow">
                              <param name="excludeMethods">input,back,cancel,browse</param>
                          </interceptor-ref>
                      </interceptor-stack>
                      
                      <interceptor-stack name="authorityInterceptorStack">
                          <interceptor-ref name="authorityInterceptor" />
                          <interceptor-ref name="eisManagerBasicStack" />
                      </interceptor-stack>

          3.設置為缺省的攔截器

          <default-interceptor-ref name="authorityInterceptorStack"/>
          posted @ 2012-01-17 16:35 RoyPayne 閱讀(2759) | 評論 (0)編輯 收藏
               摘要: 分頁顯示一直是web開發(fā)中一大煩瑣的難題,傳統的網頁設計只在一個JSP或者ASP頁面中書寫所有關于數據庫操作的代碼,那樣做分頁可能簡單一點,但當把網站分層開發(fā)后,分頁就比較困難了,下面是我做Spring+Hibernate+Struts2項目時設計的分頁代碼,與大家分享交流。  閱讀全文
          posted @ 2012-01-17 13:56 RoyPayne 閱讀(657) | 評論 (1)編輯 收藏

          1.第一個例子:

          <s:select list="{'aa','bb','cc'}" theme="simple" headerKey="00" headerValue="00"></s:select>

          2.第二個例子:

          <s:select list="#{1:'aa',2:'bb',3:'cc'}"  label="abc" listKey="key" listValue="value"  headerKey="0" headerValue="aabb">

          3.第三個例子:

          <%
          java.util.HashMap map = new java.util.LinkedHashMap();
          map.put(1,"aaa");
          map.put(2,"bbb");
          map.put(3,"ccc");
          request.setAttribute("map",map);
          request.setAttribute("aa","2");
          %>
          <s:select list="#request.map"  label="abc" listKey="key" listValue="value"
           value="#request.aa"  headerKey="0" headerValue="aabb"></
          s:select
          >
          headerKey headerValue 為設置缺省值

          4.第四個例子

          public class Program implements Serializable {
              /**    serialVersionUID */
              private static final long serialVersionUID = 1L;
              private int programid;
              private String programName;
              public int getProgramid() {
                  return programid;
              }
              public void setProgramid(int programid) {
                  this.programid = programid;
              }
                  public String getProgramName() {
                  return programName;
              }
              public void setProgramName(String programName) {
                  this.programName = programName;
              }
          }

          在 xxx extends  extends ActionSupport {
              private  List<Program> programs ;
                 public List<Program> getPrograms() {
                  return programs;
              }
              public void setPrograms(List<Program> programs) {
                      this.programs = programs;
              }
          }


          在jsp頁面
                <s:select list="programs "  listValue="programName " listKey="programid "  name="program" id="program"
                       headerKey="0l" headerValue="    "   value="bean.programid "
                       ></s:select>  
          紅色部分為在action里面的list,黃色為<option value="xxx">value</option>對應bean里面的字段programName 
          綠色為<option value="xxx",對應bean里面的字段programid

          紫色為設定select被選中的值,s:select 會自動在 bean選中 key對應的值

          posted @ 2012-01-12 15:10 RoyPayne 閱讀(250) | 評論 (0)編輯 收藏
          工作中碰到個ConcurrentModificationException。代碼如下:
          List list = ...;
          for(Iterator iter = list.iterator(); iter.hasNext();) {
              Object obj = iter.next();
              ...
              if(***) {
                  list.remove(obj);
              }
          }
          在執(zhí)行了remove方法之后,再去執(zhí)行循環(huán),iter.next()的時候,報java.util.ConcurrentModificationException(當然,如果remove的是最后一條,就不會再去執(zhí)行next()操作了)

          下面來看一下源碼
          public interface Iterator<E> {
              boolean hasNext();
              E next();
              void remove();
          }

          public interface Collection<E> extends Iterable<E> {
              ...
              Iterator<E> iterator();
              boolean add(E o);
              boolean remove(Object o);
              ...
          }

          這里有兩個remove方法

          接下來來看看AbstractList
          public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {  
          //AbstractCollection和List都繼承了Collection
              protected transient int modCount = 0;
              private class Itr implements Iterator<E> {  //內部類Itr
                  int cursor = 0;
                  int lastRet = -1;
                  int expectedModCount = modCount;

                  public boolean hasNext() {
                      return cursor != size();
                  }

                  public E next() {
                      checkForComodification();  //特別注意這個方法
                      try {
                          E next = get(cursor);
                          lastRet = cursor++;
                          return next;
                      } catch(IndexOutOfBoundsException e) {
                          checkForComodification();
                          throw new NoSuchElementException();
                      }
                  }

                  public void remove() {
                      if (lastRet == -1)
                          throw new IllegalStateException();
                      checkForComodification();

                      try {
                          AbstractList.this.remove(lastRet);  //執(zhí)行remove對象的操作
                          if (lastRet < cursor)
                              cursor--;
                          lastRet = -1;
                          expectedModCount = modCount;  //重新設置了expectedModCount的值,避免了ConcurrentModificationException的產生
                      } catch(IndexOutOfBoundsException e) {
                          throw new ConcurrentModificationException();
                      }
                  }

                  final void checkForComodification() {
                      if (modCount != expectedModCount)  //當expectedModCount和modCount不相等時,就拋出ConcurrentModificationException
                          throw new ConcurrentModificationException();
                  }
              }    
          }


          remove(Object o)在ArrayList中實現如下:
          public boolean remove(Object o) {
              if (o == null) {
                      for (int index = 0; index < size; index++)
                  if (elementData[index] == null) {
                      fastRemove(index);
                      return true;
                  }
              } else {
                  for (int index = 0; index < size; index++)
                      if (o.equals(elementData[index])) {
                          fastRemove(index);
                          return true;
                      }
              }
              return false;
          }
          private void fastRemove(int index) {
              modCount++;  //只增加了modCount
              ....
          }

          所以,產生ConcurrentModificationException的原因就是:
          執(zhí)行remove(Object o)方法之后,modCount和expectedModCount不相等了。然后當代碼執(zhí)行到next()方法時,判斷了checkForComodification(),發(fā)現兩個數值不等,就拋出了該Exception。
          要避免這個Exception,就應該使用remove()方法。

          這里我們就不看add(Object o)方法了,也是同樣的原因,但沒有對應的add()方法。一般嘛,就另建一個List了


          下面是網上的其他解釋,更能從本質上解釋原因:
          Iterator 是工作在一個獨立的線程中,并且擁有一個 mutex 鎖。 Iterator 被創(chuàng)建之后會建立一個指向原來對象的單鏈索引表,當原來的對象數量發(fā)生變化時,這個索引表的內容不會同步改變,所以當索引指針往后移動的時候就找不到要迭代的對象,所以按照 fail-fast 原則 Iterator 會馬上拋出 java.util.ConcurrentModificationException 異常。
          所以 Iterator 在工作的時候是不允許被迭代的對象被改變的。但你可以使用 Iterator 本身的方法 remove() 來刪除對象, Iterator.remove() 方法會在刪除當前迭代對象的同時維護索引的一致性。
          posted @ 2012-01-06 17:14 RoyPayne 閱讀(208) | 評論 (0)編輯 收藏
          import java.util.concurrent.ArrayBlockingQueue;
          import java.util.concurrent.BlockingQueue;
          import java.util.concurrent.ExecutorService;
          import java.util.concurrent.Executors;
           
          /**
              本例介紹一個特殊的隊列:BlockingQueue,如果BlockQueue是空的,從BlockingQueue取東西的操作將會被阻斷進入等待狀態(tài),直到BlockingQueue進了東西才會被喚醒.同樣,如果BlockingQueue是滿的,任何試圖往里存東西的操作也會被阻斷進入等待狀態(tài),直到BlockingQueue里有空間才會被喚醒繼續(xù)操作.
              本例再次實現11.4線程----條件Condition中介紹的籃子程序,不過這個籃子中最多能放的蘋果數不是1,可以隨意指定.當籃子滿時,生產者進入等待狀態(tài),當籃子空時,消費者等待.
           
          */
          /**
              使用BlockingQueue的關鍵技術點如下:
              1.BlockingQueue定義的常用方法如下:
                  1)add(anObject):把anObject加到BlockingQueue里,即如果BlockingQueue可以容納,則返回true,否則招聘異常
                  2)offer(anObject):表示如果可能的話,將anObject加到BlockingQueue里,即如果BlockingQueue可以容納,則返回true,否則返回false.
                  3)put(anObject):把anObject加到BlockingQueue里,如果BlockQueue沒有空間,則調用此方法的線程被阻斷直到BlockingQueue里面有空間再繼續(xù).
                  4)poll(time):取走BlockingQueue里排在首位的對象,若不能立即取出,則可以等time參數規(guī)定的時間,取不到時返回null
                  5)take():取走BlockingQueue里排在首位的對象,若BlockingQueue為空,阻斷進入等待狀態(tài)直到Blocking有新的對象被加入為止
              2.BlockingQueue有四個具體的實現類,根據不同需求,選擇不同的實現類
                  1)ArrayBlockingQueue:規(guī)定大小的BlockingQueue,其構造函數必須帶一個int參數來指明其大小.其所含的對象是以FIFO(先入先出)順序排序的.
                  2)LinkedBlockingQueue:大小不定的BlockingQueue,若其構造函數帶一個規(guī)定大小的參數,生成的BlockingQueue有大小限制,若不帶大小參數,所生成的BlockingQueue的大小由Integer.MAX_VALUE來決定.其所含的對象是以FIFO(先入先出)順序排序的
                  3)PriorityBlockingQueue:類似于LinkedBlockQueue,但其所含對象的排序不是FIFO,而是依據對象的自然排序順序或者是構造函數的Comparator決定的順序.
                  4)SynchronousQueue:特殊的BlockingQueue,對其的操作必須是放和取交替完成的.
              3.LinkedBlockingQueue和ArrayBlockingQueue比較起來,它們背后所用的數據結構不一樣,導致LinkedBlockingQueue的數據吞吐量要大于ArrayBlockingQueue,但在線程數量很大時其性能的可預見性低于ArrayBlockingQueue.         
           
          */
          public class BlockingQueueTest {
                 /**定義裝蘋果的籃子*/
                 public static class Basket{
                        //籃子,能夠容納3個蘋果
                        BlockingQueue<String> basket = new ArrayBlockingQueue<String>(3);
                        //生產蘋果,放入籃子
                        public void produce() throws InterruptedException{
                               //put方法放入一個蘋果,若basket滿了,等到basket有位置
                               basket.put("An apple");
                        }
                        //消費蘋果,從籃子中取走
                        public String consume() throws InterruptedException{
                               //take方法取出一個蘋果,若basket為空,等到basket有蘋果為止
                               return basket.take();
                        }
                 }
                 //測試方法
                 public static void testBasket(){
                        final Basket basket = new Basket();//建立一個裝蘋果的籃子
                        
          //定義蘋果生產者
                        class Producer implements Runnable{
                               public void run(){
                                      try{
                                             while(true){
                                                    //生產蘋果
                                                    System.out.println("生產者準備生產蘋果: " + System.currentTimeMillis());
                                                    basket.produce();
                                                    System.out.println("生產者生產蘋果完畢: " + System.currentTimeMillis());
                                                    //休眠300ms
                                                    Thread.sleep(300);
                                             }
                                      }catch(InterruptedException ex){
                                      }
                               }
                        }
                        //定義蘋果消費者
                        class Consumer implements Runnable{
                               public void run(){
                                      try{
                                             while(true){
                                                    //消費蘋果
                                                    System.out.println("消費者準備消費蘋果: " + System.currentTimeMillis());
                                                    basket.consume();
                                                    System.out.println("消費者消費蘋果完畢: " + System.currentTimeMillis());
                                                    //休眠1000ms
                                                    Thread.sleep(1000);
                                             }
                                      }catch(InterruptedException ex){
                                      }
                               }
                        }
                        ExecutorService service = Executors.newCachedThreadPool();
                        Producer producer = new Producer();
                        Consumer consumer = new Consumer();
                        service.submit(producer);
                        service.submit(consumer);
                        //程序運行5s后,所有任務停止
                        try{
                               Thread.sleep(5000);
                        }catch(InterruptedException ex){
                        }
                        service.shutdownNow();
                 }
                 public static void main(String[] args){
                        BlockingQueueTest.testBasket();
                 }
          }
          posted @ 2012-01-06 16:32 RoyPayne 閱讀(235) | 評論 (0)編輯 收藏
             Java? 語言包含兩種內在的同步機制:同步塊(或方法)和 volatile 變量。這兩種機制的提出都是為了實現代碼線程的安全性。其中 Volatile 變量的同步性較差(但有時它更簡單并且開銷更低),而且其使用也更容易出錯。在這期的 Java 理論與實踐中,Brian Goetz 將介紹幾種正確使用 volatile 變量的模式,并針對其適用性限制提出一些建議。
            Java 語言中的 volatile 變量可以被看作是一種 “程度較輕的 synchronized”;與 synchronized 塊相比,volatile 變量所需的編碼較少,并且運行時開銷也較少,但是它所能實現的功能也僅是 synchronized 的一部分。本文介紹了幾種有效使用 volatile 變量的模式,并強調了幾種不適合使用 volatile 變量的情形。
            鎖提供了兩種主要特性:互斥(mutual exclusion)可見性(visibility)?;コ饧匆淮沃辉试S一個線程持有某個特定的鎖,因此可使用該特性實現對共享數據的協調訪問協議,這樣,一次就只有一個線程能夠使用該共享數據。可見性要更加復雜一些,它必須確保釋放鎖之前對共享數據做出的更改對于隨后獲得該鎖的另一個線程是可見的 —— 如果沒有同步機制提供的這種可見性保證,線程看到的共享變量可能是修改前的值或不一致的值,這將引發(fā)許多嚴重問題。

          Volatile 變量

            Volatile 變量具有 synchronized 的可見性特性,但是不具備原子特性。這就是說線程能夠自動發(fā)現 volatile 變量的最新值。Volatile 變量可用于提供線程安全,但是只能應用于非常有限的一組用例:多個變量之間或者某個變量的當前值與修改后值之間沒有約束。因此,單獨使用 volatile 還不足以實現計數器、互斥鎖或任何具有與多個變量相關的不變式(Invariants)的類(例如 “start <=end”)。
            出于簡易性或可伸縮性的考慮,您可能傾向于使用 volatile 變量而不是鎖。當使用 volatile 變量而非鎖時,某些習慣用法(idiom)更加易于編碼和閱讀。此外,volatile 變量不會像鎖那樣造成線程阻塞,因此也很少造成可伸縮性問題。在某些情況下,如果讀操作遠遠大于寫操作,volatile 變量還可以提供優(yōu)于鎖的性能優(yōu)勢。

          正確使用 volatile 變量的條件

            您只能在有限的一些情形下使用 volatile 變量替代鎖。要使 volatile 變量提供理想的線程安全,必須同時滿足下面兩個條件:
            ● 對變量的寫操作不依賴于當前值。
            ● 該變量沒有包含在具有其他變量的不變式中。
            實際上,這些條件表明,可以被寫入 volatile 變量的這些有效值獨立于任何程序的狀態(tài),包括變量的當前狀態(tài)。
            第一個條件的限制使 volatile 變量不能用作線程安全計數器。雖然增量操作(x++)看上去類似一個單獨操作,實際上它是一個由讀?。薷模瓕懭氩僮餍蛄薪M成的組合操作,必須以原子方式執(zhí)行,而 volatile 不能提供必須的原子特性。實現正確的操作需要使 x 的值在操作期間保持不變,而 volatile 變量無法實現這點。(然而,如果將值調整為只從單個線程寫入,那么可以忽略第一個條件。)
            大多數編程情形都會與這兩個條件的其中之一沖突,使得 volatile 變量不能像 synchronized 那樣普遍適用于實現線程安全。清單 1 顯示了一個非線程安全的數值范圍類。它包含了一個不變式 —— 下界總是小于或等于上界。
                 
                 
          清單 1. 非線程安全的數值范圍類
          @NotThreadSafe 
          public class NumberRange { 
          private int lower, upper; 
          public int getLower() { return lower; } 
          public int getUpper() { return upper; } 
          public void setLower(int value) { 
          if (value > upper) 
          throw new IllegalArgumentException(); 
          lower = value; 

          public void setUpper(int value) { 
          if (value < lower) 
          throw new IllegalArgumentException(); 
          upper = value; 

          }

          這種方式限制了范圍的狀態(tài)變量,因此將 lower 和 upper 字段定義為 volatile 類型不能夠充分實現類的線程安全;從而仍然需要使用同步。否則,如果湊巧兩個線程在同一時間使用不一致的值執(zhí)行 setLower 和 setUpper 的話,則會使范圍處于不一致的狀態(tài)。例如,如果初始狀態(tài)是 (0, 5),同一時間內,線程 A 調用 setLower(4) 并且線程 B 調用 setUpper(3),顯然這兩個操作交叉存入的值是不符合條件的,那么兩個線程都會通過用于保護不變式的檢查,使得最后的范圍值是 (4, 3) —— 一個無效值。至于針對范圍的其他操作,我們需要使 setLower() 和 setUpper() 操作原子化 —— 而將字段定義為 volatile 類型是無法實現這一目的的。

          性能考慮

            使用 volatile 變量的主要原因是其簡易性:在某些情形下,使用 volatile 變量要比使用相應的鎖簡單得多。使用 volatile 變量次要原因是其性能:某些情況下,volatile 變量同步機制的性能要優(yōu)于鎖。
            很難做出準確、全面的評價,例如 “X 總是比 Y 快”,尤其是對 JVM 內在的操作而言。(例如,某些情況下 VM 也許能夠完全刪除鎖機制,這使得我們難以抽象地比較 volatile和 synchronized 的開銷。)就是說,在目前大多數的處理器架構上,volatile 讀操作開銷非常低 —— 幾乎和非 volatile 讀操作一樣。而 volatile 寫操作的開銷要比非 volatile 寫操作多很多,因為要保證可見性需要實現內存界定(Memory Fence),即便如此,volatile 的總開銷仍然要比鎖獲取低。
            volatile 操作不會像鎖一樣造成阻塞,因此,在能夠安全使用 volatile 的情況下,volatile 可以提供一些優(yōu)于鎖的可伸縮特性。如果讀操作的次數要遠遠超過寫操作,與鎖相比,volatile 變量通常能夠減少同步的性能開銷。

          正確使用 volatile 的模式

            很多并發(fā)性專家事實上往往引導用戶遠離 volatile 變量,因為使用它們要比使用鎖更加容易出錯。然而,如果謹慎地遵循一些良好定義的模式,就能夠在很多場合內安全地使用 volatile 變量。要始終牢記使用 volatile 的限制 —— 只有在狀態(tài)真正獨立于程序內其他內容時才能使用 volatile —— 這條規(guī)則能夠避免將這些模式擴展到不安全的用例。
            模式 #1:狀態(tài)標志 也許實現 volatile 變量的規(guī)范使用僅僅是使用一個布爾狀態(tài)標志,用于指示發(fā)生了一個重要的一次性事件,例如完成初始化或請求停機。
            很多應用程序包含了一種控制結構,形式為 “在還沒有準備好停止程序時再執(zhí)行一些工作”,如清單 2 所示:
            清單 2. 將 volatile 變量作為狀態(tài)標志使用

          volatile boolean shutdownRequested; 
           
          public void shutdown() { shutdownRequested = true; } 
          public void doWork() { 
          while (!shutdownRequested) { 
          // do stuff 

          }
          很可能會從循環(huán)外部調用 shutdown() 方法 —— 即在另一個線程中 —— 因此,需要執(zhí)行某種同步來確保正確實現 shutdownRequested 變量的可見性。(可能會從 JMX 偵聽程序、GUI 事件線程中的操作偵聽程序、通過 RMI 、通過一個 Web 服務等調用)。然而,使用 synchronized 塊編寫循環(huán)要比使用清單 2 所示的 volatile 狀態(tài)標志編寫麻煩很多。由于 volatile 簡化了編碼,并且狀態(tài)標志并不依賴于程序內任何其他狀態(tài),因此此處非常適合使用 volatile。
            這種類型的狀態(tài)標記的一個公共特性是:通常只有一種狀態(tài)轉換;shutdownRequested 標志從 false 轉換為 true,然后程序停止。這種模式可以擴展到來回轉換的狀態(tài)標志,但是只有在轉換周期不被察覺的情況下才能擴展(從 false 到 true,再轉換到 false)。此外,還需要某些原子狀態(tài)轉換機制,例如原子變量。
            模式 #2:一次性安全發(fā)布(one-time safe publication)
            缺乏同步會導致無法實現可見性,這使得確定何時寫入對象引用而不是原語值變得更加困難。在缺乏同步的情況下,可能會遇到某個對象引用的更新值(由另一個線程寫入)和該對象狀態(tài)的舊值同時存在。(這就是造成著名的雙重檢查鎖定(double-checked-locking)問題的根源,其中對象引用在沒有同步的情況下進行讀操作,產生的問題是您可能會看到一個更新的引用,但是仍然會通過該引用看到不完全構造的對象)。
            實現安全發(fā)布對象的一種技術就是將對象引用定義為 volatile 類型。清單 3 展示了一個示例,其中后臺線程在啟動階段從數據庫加載一些數據。其他代碼在能夠利用這些數據時,在使用之前將檢查這些數據是否曾經發(fā)布過。
            清單 3. 將 volatile 變量用于一次性安全發(fā)布

          public class BackgroundFloobleLoader { 
          public volatile Flooble theFlooble; 
          public void initInBackground() { 
          // do lots of stuff 
          theFlooble = new Flooble(); // this is the only write to theFlooble 


          public class SomeOtherClass { 
          public void doWork() { 
          while (true) { 
          // do some stuff 
          // use the Flooble, but only if it is ready 
          if (floobleLoader.theFlooble != null
          doSomething(floobleLoader.theFlooble); 


          }

          如果 theFlooble 引用不是 volatile 類型,doWork() 中的代碼在解除對 theFlooble 的引用時,將會得到一個不完全構造的 Flooble。
            該模式的一個必要條件是:被發(fā)布的對象必須是線程安全的,或者是有效的不可變對象(有效不可變意味著對象的狀態(tài)在發(fā)布之后永遠不會被修改)。volatile 類型的引用可以確保對象的發(fā)布形式的可見性,但是如果對象的狀態(tài)在發(fā)布后將發(fā)生更改,那么就需要額外的同步。
            模式 #3:獨立觀察(independent observation)
            安全使用 volatile 的另一種簡單模式是:定期 “發(fā)布” 觀察結果供程序內部使用。例如,假設有一種環(huán)境傳感器能夠感覺環(huán)境溫度。一個后臺線程可能會每隔幾秒讀取一次該傳感器,并更新包含當前文檔的 volatile 變量。然后,其他線程可以讀取這個變量,從而隨時能夠看到最新的溫度值。
            使用該模式的另一種應用程序就是收集程序的統計信息。清單 4 展示了身份驗證機制如何記憶最近一次登錄的用戶的名字。將反復使用 lastUser 引用來發(fā)布值,以供程序的其他部分使用。
            清單 4. 將 volatile 變量用于多個獨立觀察結果的發(fā)布
          public class UserManager { 
          public volatile String lastUser; 
          public boolean authenticate(String user, String password) { 
          boolean valid = passwordIsValid(user, password); 
          if (valid) { 
          User u = new User(); 
          activeUsers.add(u); 
          lastUser = user; 

          return valid; 

          }

          該模式是前面模式的擴展;將某個值發(fā)布以在程序內的其他地方使用,但是與一次性事件的發(fā)布不同,這是一系列獨立事件。這個模式要求被發(fā)布的值是有效不可變的 —— 即值的狀態(tài)在發(fā)布后不會更改。使用該值的代碼需要清楚該值可能隨時發(fā)生變化。
            模式 #4:“volatile bean” 模式
            volatile bean 模式適用于將 JavaBeans 作為“榮譽結構”使用的框架。在 volatile bean 模式中,JavaBean 被用作一組具有 getter 和/或 setter 方法 的獨立屬性的容器。volatile bean 模式的基本原理是:很多框架為易變數據的持有者(例如 HttpSession)提供了容器,但是放入這些容器中的對象必須是線程安全的。
            在 volatile bean 模式中,JavaBean 的所有數據成員都是 volatile 類型的,并且 getter 和 setter 方法必須非常普通 —— 除了獲取或設置相應的屬性外,不能包含任何邏輯。此外,對于對象引用的數據成員,引用的對象必須是有效不可變的。(這將禁止具有數組值的屬性,因為當數組引用被聲明為 volatile 時,只有引用而不是數組本身具有 volatile 語義)。對于任何 volatile 變量,不變式或約束都不能包含 JavaBean 屬性。清單 5 中的示例展示了遵守 volatile bean 模式的 JavaBean:
            清單 5. 遵守 volatile bean 模式的 Person 對象

          @ThreadSafe 
          public class Person { 
          private volatile String firstName; 
          private volatile String lastName; 
          private volatile int age; 
          public String getFirstName() { return firstName; } 
          public String getLastName() { return lastName; } 
          public int getAge() { return age; } 
          public void setFirstName(String firstName) { 
          this.firstName = firstName; 

          public void setLastName(String lastName) { 
          this.lastName = lastName; 

          public void setAge(int age) { 
          this.age = age; 

          }

          volatile 的高級模式
            前面幾節(jié)介紹的模式涵蓋了大部分的基本用例,在這些模式中使用 volatile 非常有用并且簡單。這一節(jié)將介紹一種更加高級的模式,在該模式中,volatile 將提供性能或可伸縮性優(yōu)勢。
            volatile 應用的的高級模式非常脆弱。因此,必須對假設的條件仔細證明,并且這些模式被嚴格地封裝了起來,因為即使非常小的更改也會損壞您的代碼!同樣,使用更高級的 volatile 用例的原因是它能夠提升性能,確保在開始應用高級模式之前,真正確定需要實現這種性能獲益。需要對這些模式進行權衡,放棄可讀性或可維護性來換取可能的性能收益 —— 如果您不需要提升性能(或者不能夠通過一個嚴格的測試程序證明您需要它),那么這很可能是一次糟糕的交易,因為您很可能會得不償失,換來的東西要比放棄的東西價值更低。
            模式 #5:開銷較低的讀-寫鎖策略
            目前為止,您應該了解了 volatile 的功能還不足以實現計數器。因為 ++x 實際上是三種操作(讀、添加、存儲)的簡單組合,如果多個線程湊巧試圖同時對 volatile 計數器執(zhí)行增量操作,那么它的更新值有可能會丟失。
            然而,如果讀操作遠遠超過寫操作,您可以結合使用內部鎖和 volatile 變量來減少公共代碼路徑的開銷。清單 6 中顯示的線程安全的計數器使用 synchronized 確保增量操作是原子的,并使用 volatile 保證當前結果的可見性。如果更新不頻繁的話,該方法可實現更好的性能,因為讀路徑的開銷僅僅涉及 volatile 讀操作,這通常要優(yōu)于一個無競爭的鎖獲取的開銷。
            清單 6. 結合使用 volatile 和 synchronized 實現 “開銷較低的讀-寫鎖”
          @ThreadSafe 
          public class CheesyCounter { 
          // Employs the cheap read-write lock trick 
          // All mutative operations MUST be done with the 'this' lock held 
          @GuardedBy("this") private volatileint value; 
          public int getValue() { return value; } 
          public synchronizedint increment() { 
          return value++; 

          }

          之所以將這種技術稱之為 “開銷較低的讀-寫鎖” 是因為您使用了不同的同步機制進行讀寫操作。因為本例中的寫操作違反了使用 volatile 的第一個條件,因此不能使用 volatile 安全地實現計數器 —— 您必須使用鎖。然而,您可以在讀操作中使用 volatile 確保當前值的可見性,因此可以使用鎖進行所有變化的操作,使用 volatile 進行只讀操作。其中,鎖一次只允許一個線程訪問值,volatile 允許多個線程執(zhí)行讀操作,因此當使用 volatile 保證讀代碼路徑時,要比使用鎖執(zhí)行全部代碼路徑獲得更高的共享度 —— 就像讀-寫操作一樣。然而,要隨時牢記這種模式的弱點:如果超越了該模式的最基本應用,結合這兩個競爭的同步機制將變得非常困難。
            結束語
            與鎖相比,Volatile 變量是一種非常簡單但同時又非常脆弱的同步機制,它在某些情況下將提供優(yōu)于鎖的性能和伸縮性。如果嚴格遵循 volatile 的使用條件 —— 即變量真正獨立于其他變量和自己以前的值 —— 在某些情況下可以使用 volatile 代替 synchronized 來簡化代碼。然而,使用 volatile 的代碼往往比使用鎖的代碼更加容易出錯。本文介紹的模式涵蓋了可以使用 volatile 代替 synchronized 的最常見的一些用例。遵循這些模式(注意使用時不要超過各自的限制)可以幫助您安全地實現大多數用例,使用 volatile 變量獲得更佳性能。


          posted @ 2012-01-06 10:44 RoyPayne 閱讀(302) | 評論 (1)編輯 收藏
               摘要: JSP內置對象:我們在使用JSP進行頁面編程時可以直接使用而不需自己創(chuàng)建的一些Web容器已為用戶創(chuàng)建好的JSP內置對象。如request,session,response,out等。下面就JSP2.0給出的9個內置對象: 內置對象類型作用域requestjavax.servlet.http.HttpServletRequestrequestresponsejavax.servlet.ht...  閱讀全文
          posted @ 2012-01-05 16:36 RoyPayne 閱讀(18588) | 評論 (1)編輯 收藏
          一、Propagation (事務的傳播屬性)

          Propagation :  key屬性確定代理應該給哪個方法增加事務行為。這樣的屬性最重要的部份是傳播行為。有以下選項可供使用:PROPAGATION_REQUIRED--支持當前事務,如果當前沒有事務,就新建一個事務。這是最常見的選擇。
          PROPAGATION_SUPPORTS--支持當前事務,如果當前沒有事務,就以非事務方式執(zhí)行。
          PROPAGATION_MANDATORY--支持當前事務,如果當前沒有事務,就拋出異常。
          PROPAGATION_REQUIRES_NEW--新建事務,如果當前存在事務,把當前事務掛起。
          PROPAGATION_NOT_SUPPORTED--以非事務方式執(zhí)行操作,如果當前存在事務,就把當前事務掛起。
          PROPAGATION_NEVER--以非事務方式執(zhí)行,如果當前存在事務,則拋出異常。

          1: PROPAGATION_REQUIRED
          加入當前正要執(zhí)行的事務不在另外一個事務里,那么就起一個新的事務
          比如說,ServiceB.methodB的事務級別定義為PROPAGATION_REQUIRED, 那么由于執(zhí)行ServiceA.methodA的時候,
          ServiceA.methodA已經起了事務,這時調用ServiceB.methodB,ServiceB.methodB看到自己已經運行在ServiceA.methodA
          的事務內部,就不再起新的事務。而假如ServiceA.methodA運行的時候發(fā)現自己沒有在事務中,他就會為自己分配一個事務。
          這樣,在ServiceA.methodA或者在ServiceB.methodB內的任何地方出現異常,事務都會被回滾。即使ServiceB.methodB的事務已經被
          提交,但是ServiceA.methodA在接下來fail要回滾,ServiceB.methodB也要回滾

          2: PROPAGATION_SUPPORTS
          如果當前在事務中,即以事務的形式運行,如果當前不再一個事務中,那么就以非事務的形式運行


          3: PROPAGATION_MANDATORY
          必須在一個事務中運行。也就是說,他只能被一個父事務調用。否則,他就要拋出異常

          4: PROPAGATION_REQUIRES_NEW
          這個就比較繞口了。 比如我們設計ServiceA.methodA的事務級別為PROPAGATION_REQUIRED,ServiceB.methodB的事務級別為PROPAGATION_REQUIRES_NEW,
          那么當執(zhí)行到ServiceB.methodB的時候,ServiceA.methodA所在的事務就會掛起,ServiceB.methodB會起一個新的事務,等待ServiceB.methodB的事務完成以后,
          他才繼續(xù)執(zhí)行。他與PROPAGATION_REQUIRED 的事務區(qū)別在于事務的回滾程度了。因為ServiceB.methodB是新起一個事務,那么就是存在
          兩個不同的事務。如果ServiceB.methodB已經提交,那么ServiceA.methodA失敗回滾,ServiceB.methodB是不會回滾的。如果ServiceB.methodB失敗回滾,
          如果他拋出的異常被ServiceA.methodA捕獲,ServiceA.methodA事務仍然可能提交。

          5: PROPAGATION_NOT_SUPPORTED
          當前不支持事務。比如ServiceA.methodA的事務級別是PROPAGATION_REQUIRED ,而ServiceB.methodB的事務級別是PROPAGATION_NOT_SUPPORTED ,
          那么當執(zhí)行到ServiceB.methodB時,ServiceA.methodA的事務掛起,而他以非事務的狀態(tài)運行完,再繼續(xù)ServiceA.methodA的事務。

          6: PROPAGATION_NEVER
          不能在事務中運行。假設ServiceA.methodA的事務級別是PROPAGATION_REQUIRED, 而ServiceB.methodB的事務級別是PROPAGATION_NEVER ,
          那么ServiceB.methodB就要拋出異常了。

          7: PROPAGATION_NESTED
          理解Nested的關鍵是savepoint。他與PROPAGATION_REQUIRES_NEW的區(qū)別是,PROPAGATION_REQUIRES_NEW另起一個事務,將會與他的父事務相互獨立,
          而Nested的事務和他的父事務是相依的,他的提交是要等和他的父事務一塊提交的。也就是說,如果父事務最后回滾,他也要回滾的。
          而Nested事務的好處是他有一個savepoint。
          *****************************************
          ServiceA {

          /**
          * 事務屬性配置為 PROPAGATION_REQUIRED
          */
          void methodA() {
          try {
          //savepoint
          ServiceB.methodB(); //PROPAGATION_NESTED 級別
          } catch (SomeException) {
          // 執(zhí)行其他業(yè)務, 如 ServiceC.methodC();
          }
          }

          }
          ********************************************
          也就是說ServiceB.methodB失敗回滾,那么ServiceA.methodA也會回滾到savepoint點上,ServiceA.methodA可以選擇另外一個分支,比如
          ServiceC.methodC,繼續(xù)執(zhí)行,來嘗試完成自己的事務。
          但是這個事務并沒有在EJB標準中定義。

          Spring事務的隔離級別
           1. ISOLATION_DEFAULT: 這是一個PlatfromTransactionManager默認的隔離級別,使用數據庫默認的事務隔離級別.
                另外四個與JDBC的隔離級別相對應
           2. ISOLATION_READ_UNCOMMITTED: 這是事務最低的隔離級別,它充許令外一個事務可以看到這個事務未提交的數據。
                這種隔離級別會產生臟讀,不可重復讀和幻像讀。
           3. ISOLATION_READ_COMMITTED: 保證一個事務修改的數據提交后才能被另外一個事務讀取。另外一個事務不能讀取該事務未提交的數據
           4. ISOLATION_REPEATABLE_READ: 這種事務隔離級別可以防止臟讀,不可重復讀。但是可能出現幻像讀。
                它除了保證一個事務不能讀取另一個事務未提交的數據外,還保證了避免下面的情況產生(不可重復讀)。
           5. ISOLATION_SERIALIZABLE 這是花費最高代價但是最可靠的事務隔離級別。事務被處理為順序執(zhí)行。
                除了防止臟讀,不可重復讀外,還避免了幻像讀。

          什么是臟數據,臟讀,不可重復讀,幻覺讀?
           臟讀: 指當一個事務正在訪問數據,并且對數據進行了修改,而這種修改還沒有提交到數據庫中,這時,
               另外一個事務也訪問這個數據,然后使用了這個數據。因為這個數據是還沒有提交的數據, 那么另外一
               個事務讀到的這個數據是臟數據,依據臟數據所做的操作可能是不正確的。
              
           不可重復讀: 指在一個事務內,多次讀同一數據。在這個事務還沒有結束時,另外一個事務也訪問該同一數據。
                       那么,在第一個事務中的兩次讀數據之間,由于第二個事務的修改,那么第一個事務兩次讀到的數據
                       可能是不一樣的。這樣就發(fā)生了在一個事務內兩次讀到的數據是不一樣的,因此稱為是不可重復讀。
                      
           幻覺讀: 指當事務不是獨立執(zhí)行時發(fā)生的一種現象,例如第一個事務對一個表中的數據進行了修改,這種修改涉及
                   到表中的全部數據行。同時,第二個事務也修改這個表中的數據,這種修改是向表中插入一行新數據。那么,
                   以后就會發(fā)生操作第一個事務的用戶發(fā)現表中還有沒有修改的數據行,就好象發(fā)生了幻覺一樣。
          posted @ 2012-01-05 15:25 RoyPayne 閱讀(394) | 評論 (0)編輯 收藏
          兩者的區(qū)別有:
          1、最主要是sleep方法沒有釋放鎖,而wait方法釋放了鎖,使得其他線程可以使用同步控制塊或者方法。 2、這兩個方法來自不同的類分別是Thread和Object

          3、wait,notify和notifyAll只能在同步控制方法或者同步控制塊里面使用,而sleep可以在
          任何地方使用
          synchronized(x){
          x.notify()
          //或者wait()
          }
          4、sleep必須捕獲異常,而wait,notify和notifyAll不需要捕獲異常
          posted @ 2012-01-05 14:32 RoyPayne 閱讀(464) | 評論 (0)編輯 收藏

          public class CeilAndFloor {
              public static void main(String[] args) {
              /*
                  這兩個寶貝函數的主要任務是截掉小數以后的位數.
                  區(qū)別是: floor總是把數字變得越來越小,而ceil總是把數字變大。
                          其實名字可以理解floor是地板,ceil是天花板。
              
          */

                  System.out.println("==============Math.floor()==============");
                  System.out.println("Math.floor(99.1) = " + Math.floor(99.1));
                  System.out.println("Math.floor(-99.1) = " + Math.floor(-99.1));
                  System.out.println("Math.floor(99.9) = " + Math.floor(99.9));
                  System.out.println("Math.floor(99.9) = " + Math.floor(-99.9));
                  
                  System.out.println("\n\n==============Math.ceil()==============");
                  System.out.println("Math.ceil(99.1) = " + Math.ceil(99.1));
                  System.out.println("Math.ceil(-99.1) = " + Math.ceil(-99.1));
                  System.out.println("Math.ceil(99.9) = " + Math.ceil(99.9));
                  System.out.println("Math.ceil(99.9) = " + Math.ceil(-99.9));
                  
              }
          }
          結果
          ==============Math.floor()==============
          Math.floor(99.1) = 99.0
          Math.floor(-99.1) = -100.0
          Math.floor(99.9) = 99.0
          Math.floor(99.9) = -100.0

          ==============Math.ceil()==============
          Math.ceil(99.1) = 100.0
          Math.ceil(-99.1) = -99.0
          Math.ceil(99.9) = 100.0
          Math.ceil(99.9) = -99.0
          posted @ 2012-01-05 09:20 RoyPayne 閱讀(367) | 評論 (0)編輯 收藏
              在Java中,可以獲得總的物理內存、剩余的物理內存、已使用的物理內存等信息,本例講解如何取得這些信息,并且獲得在Windows下的內存使用率。
               首先編寫一個MonitorInfoBean類,用來裝載監(jiān)控的一些信息,包括物理內存、剩余的物理內存、已使用的物理內存、內存使用率等字段,該類的代碼如下:
                

          package com.amigo.performance;

          /**
           * 監(jiān)視信息的JavaBean類.
           * 
          @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
           * 
          @version 1.0 
           * Creation date: 2008-4-25 - 上午10:37:00
           
          */
          public class MonitorInfoBean {
              /** 可使用內存. */
              private long totalMemory;
              
              /** 剩余內存. */
              private long freeMemory;
              
              /** 最大可使用內存. */
              private long maxMemory;
              
              /** 操作系統. */
              private String osName;
              
              /** 總的物理內存. */
              private long totalMemorySize;
              
              /** 剩余的物理內存. */
              private long freePhysicalMemorySize;
              
              /** 已使用的物理內存. */
              private long usedMemory;
              
              /** 線程總數. */
              private int totalThread;
              
              /** cpu使用率. */
              private double cpuRatio;

              public long getFreeMemory() {
                  return freeMemory;
              }

              public void setFreeMemory(long freeMemory) {
                  this.freeMemory = freeMemory;
              }

              public long getFreePhysicalMemorySize() {
                  return freePhysicalMemorySize;
              }

              public void setFreePhysicalMemorySize(long freePhysicalMemorySize) {
                  this.freePhysicalMemorySize = freePhysicalMemorySize;
              }

              public long getMaxMemory() {
                  return maxMemory;
              }

              public void setMaxMemory(long maxMemory) {
                  this.maxMemory = maxMemory;
              }

              public String getOsName() {
                  return osName;
              }

              public void setOsName(String osName) {
                  this.osName = osName;
              }

              public long getTotalMemory() {
                  return totalMemory;
              }

              public void setTotalMemory(long totalMemory) {
                  this.totalMemory = totalMemory;
              }

              public long getTotalMemorySize() {
                  return totalMemorySize;
              }

              public void setTotalMemorySize(long totalMemorySize) {
                  this.totalMemorySize = totalMemorySize;
              }

              public int getTotalThread() {
                  return totalThread;
              }

              public void setTotalThread(int totalThread) {
                  this.totalThread = totalThread;
              }

              public long getUsedMemory() {
                  return usedMemory;
              }

              public void setUsedMemory(long usedMemory) {
                  this.usedMemory = usedMemory;
              }

              public double getCpuRatio() {
                  return cpuRatio;
              }

              public void setCpuRatio(double cpuRatio) {
                  this.cpuRatio = cpuRatio;
              }
          }

          接著編寫一個獲得當前的監(jiān)控信息的接口,該類的代碼如下所示:

          package com.amigo.performance;

          /**
           * 獲取系統信息的業(yè)務邏輯類接口.
           * 
          @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
           * 
          @version 1.0 
           * Creation date: 2008-3-11 - 上午10:06:06
           
          */
          public interface IMonitorService {
              /**
               * 獲得當前的監(jiān)控對象.
               * 
          @return 返回構造好的監(jiān)控對象
               * 
          @throws Exception
               * 
          @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
               * Creation date: 2008-4-25 - 上午10:45:08
               
          */
              public MonitorInfoBean getMonitorInfoBean() throws Exception;

          }

          該類的實現類MonitorServiceImpl如下所示:


          package com.amigo.performance;

          import java.io.InputStreamReader;
          import java.io.LineNumberReader;

          import sun.management.ManagementFactory;

          import com.sun.management.OperatingSystemMXBean;

          /**
           * 獲取系統信息的業(yè)務邏輯實現類.
           * 
          @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
           * 
          @version 1.0 Creation date: 2008-3-11 - 上午10:06:06
           
          */
          public class MonitorServiceImpl implements IMonitorService {
              
              private static final int CPUTIME = 30;

              private static final int PERCENT = 100;

              private static final int FAULTLENGTH = 10;

              /**
               * 獲得當前的監(jiān)控對象.
               * 
          @return 返回構造好的監(jiān)控對象
               * 
          @throws Exception
               * 
          @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
               * Creation date: 2008-4-25 - 上午10:45:08
               
          */
              public MonitorInfoBean getMonitorInfoBean() throws Exception {
                  int kb = 1024;
                  
                  // 可使用內存
                  long totalMemory = Runtime.getRuntime().totalMemory() / kb;
                  // 剩余內存
                  long freeMemory = Runtime.getRuntime().freeMemory() / kb;
                  // 最大可使用內存
                  long maxMemory = Runtime.getRuntime().maxMemory() / kb;

                  OperatingSystemMXBean osmxb = (OperatingSystemMXBean) ManagementFactory
                          .getOperatingSystemMXBean();

                  // 操作系統
                  String osName = System.getProperty("os.name");
                  // 總的物理內存
                  long totalMemorySize = osmxb.getTotalPhysicalMemorySize() / kb;
                  // 剩余的物理內存
                  long freePhysicalMemorySize = osmxb.getFreePhysicalMemorySize() / kb;
                  // 已使用的物理內存
                  long usedMemory = (osmxb.getTotalPhysicalMemorySize() - osmxb
                          .getFreePhysicalMemorySize())
                          / kb;

                  // 獲得線程總數
                  ThreadGroup parentThread;
                  for (parentThread = Thread.currentThread().getThreadGroup(); parentThread
                          .getParent() != null; parentThread = parentThread.getParent())
                      ;
                  int totalThread = parentThread.activeCount();

                  double cpuRatio = 0;
                  if (osName.toLowerCase().startsWith("windows")) {
                      cpuRatio = this.getCpuRatioForWindows();
                  }
                  
                  // 構造返回對象
                  MonitorInfoBean infoBean = new MonitorInfoBean();
                  infoBean.setFreeMemory(freeMemory);
                  infoBean.setFreePhysicalMemorySize(freePhysicalMemorySize);
                  infoBean.setMaxMemory(maxMemory);
                  infoBean.setOsName(osName);
                  infoBean.setTotalMemory(totalMemory);
                  infoBean.setTotalMemorySize(totalMemorySize);
                  infoBean.setTotalThread(totalThread);
                  infoBean.setUsedMemory(usedMemory);
                  infoBean.setCpuRatio(cpuRatio);
                  return infoBean;
              }

              /**
               * 獲得CPU使用率.
               * 
          @return 返回cpu使用率
               * 
          @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
               * Creation date: 2008-4-25 - 下午06:05:11
               
          */
              private double getCpuRatioForWindows() {
                  try {
                      String procCmd = System.getenv("windir")
                              + "\\system32\\wbem\\wmic.exe process get Caption,CommandLine,"
                              + "KernelModeTime,ReadOperationCount,ThreadCount,UserModeTime,WriteOperationCount";
                      // 取進程信息
                      long[] c0 = readCpu(Runtime.getRuntime().exec(procCmd));
                      Thread.sleep(CPUTIME);
                      long[] c1 = readCpu(Runtime.getRuntime().exec(procCmd));
                      if (c0 != null && c1 != null) {
                          long idletime = c1[0] - c0[0];
                          long busytime = c1[1] - c0[1];
                          return Double.valueOf(
                                  PERCENT * (busytime) / (busytime + idletime))
                                  .doubleValue();
                      } else {
                          return 0.0;
                      }
                  } catch (Exception ex) {
                      ex.printStackTrace();
                      return 0.0;
                  }
              }

              /**
               * 讀取CPU信息.
               * 
          @param proc
               * 
          @return
               * 
          @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
               * Creation date: 2008-4-25 - 下午06:10:14
               
          */
              private long[] readCpu(final Process proc) {
                  long[] retn = new long[2];
                  try {
                      proc.getOutputStream().close();
                      InputStreamReader ir = new InputStreamReader(proc.getInputStream());
                      LineNumberReader input = new LineNumberReader(ir);
                      String line = input.readLine();
                      if (line == null || line.length() < FAULTLENGTH) {
                          return null;
                      }
                      int capidx = line.indexOf("Caption");
                      int cmdidx = line.indexOf("CommandLine");
                      int rocidx = line.indexOf("ReadOperationCount");
                      int umtidx = line.indexOf("UserModeTime");
                      int kmtidx = line.indexOf("KernelModeTime");
                      int wocidx = line.indexOf("WriteOperationCount");
                      long idletime = 0;
                      long kneltime = 0;
                      long usertime = 0;
                      while ((line = input.readLine()) != null) {
                          if (line.length() < wocidx) {
                              continue;
                          }
                          // 字段出現順序:Caption,CommandLine,KernelModeTime,ReadOperationCount,
                          
          // ThreadCount,UserModeTime,WriteOperation
                          String caption = Bytes.substring(line, capidx, cmdidx - 1)
                                  .trim();
                          String cmd = Bytes.substring(line, cmdidx, kmtidx - 1).trim();
                          if (cmd.indexOf("wmic.exe") >= 0) {
                              continue;
                          }
                          // log.info("line="+line);
                          if (caption.equals("System Idle Process")
                                  || caption.equals("System")) {
                              idletime += Long.valueOf(
                                      Bytes.substring(line, kmtidx, rocidx - 1).trim())
                                      .longValue();
                              idletime += Long.valueOf(
                                      Bytes.substring(line, umtidx, wocidx - 1).trim())
                                      .longValue();
                              continue;
                          }

                          kneltime += Long.valueOf(
                                  Bytes.substring(line, kmtidx, rocidx - 1).trim())
                                  .longValue();
                          usertime += Long.valueOf(
                                  Bytes.substring(line, umtidx, wocidx - 1).trim())
                                  .longValue();
                      }
                      retn[0] = idletime;
                      retn[1] = kneltime + usertime;
                      return retn;
                  } catch (Exception ex) {
                      ex.printStackTrace();
                  } finally {
                      try {
                          proc.getInputStream().close();
                      } catch (Exception e) {
                          e.printStackTrace();
                      }
                  }
                  return null;
              }
              
              /**
               * 測試方法.
               * 
          @param args
               * 
          @throws Exception
               * 
          @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
               * Creation date: 2008-4-30 - 下午04:47:29
               
          */
              public static void main(String[] args) throws Exception {
                  IMonitorService service = new MonitorServiceImpl();
                  MonitorInfoBean monitorInfo = service.getMonitorInfoBean();
                  System.out.println("cpu占有率=" + monitorInfo.getCpuRatio());
                  
                  System.out.println("可使用內存=" + monitorInfo.getTotalMemory());
                  System.out.println("剩余內存=" + monitorInfo.getFreeMemory());
                  System.out.println("最大可使用內存=" + monitorInfo.getMaxMemory());
                  
                  System.out.println("操作系統=" + monitorInfo.getOsName());
                  System.out.println("總的物理內存=" + monitorInfo.getTotalMemorySize() + "kb");
                  System.out.println("剩余的物理內存=" + monitorInfo.getFreeMemory() + "kb");
                  System.out.println("已使用的物理內存=" + monitorInfo.getUsedMemory() + "kb");
                  System.out.println("線程總數=" + monitorInfo.getTotalThread() + "kb");
              }
          }

          該實現類中需要用到一個自己編寫byte的工具類,該類的代碼如下所示:


          package com.amigo.performance;

          /**
           * byte操作類.
           * 
          @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
           * 
          @version 1.0 
           * Creation date: 2008-4-30 - 下午04:57:23
           
          */
          public class Bytes {
              /**
               * 由于String.subString對漢字處理存在問題(把一個漢字視為一個字節(jié)),因此在
               * 包含漢字的字符串時存在隱患,現調整如下:
               * 
          @param src 要截取的字符串
               * 
          @param start_idx 開始坐標(包括該坐標)
               * 
          @param end_idx   截止坐標(包括該坐標)
               * 
          @return
               
          */
              public static String substring(String src, int start_idx, int end_idx){
                  byte[] b = src.getBytes();
                  String tgt = "";
                  for(int i=start_idx; i<=end_idx; i++){
                      tgt +=(char)b[i];
                  }
                  return tgt;
              }
          }

          運行下MonitorBeanImpl類,讀者將會看到當前的內存、cpu利用率等信息。











          posted @ 2012-01-04 14:54 RoyPayne 閱讀(1992) | 評論 (1)編輯 收藏
               摘要: 1.java的System.getProperty()方法可以獲取的值java.versionJava 運行時環(huán)境版本java.vendorJava 運行時環(huán)境供應商java.vendor.urlJava 供應商的 URLjava.homeJava 安裝目錄java.vm.specification.versionJava 虛擬機規(guī)范版本java....  閱讀全文
          posted @ 2012-01-04 14:37 RoyPayne 閱讀(8339) | 評論 (0)編輯 收藏
              ListResourceBundle 是 ResourceBundle 的一個抽象類,用于管理方便而又易于使用的列表中的語言環(huán)境資源。有關資源包的常規(guī)信息,請參閱 ResourceBundle
              
          子類必須重寫 getContents 并提供一個數組,其中數組中的每個項都是一個對象對。每對的第一個元素是鍵,該鍵必須是一個 String,并且第二個元素是和該鍵相關聯的值。
                下面的示例顯示了具有基本名稱 "MyResources" 的資源包系列的兩個成員。"MyResources" 是資源包系列的默認成員,"MyResources_fr" 是 French 成員。這些成員是基于ListResourceBundle(一個相關的示例顯示了如何把一個資源包添加到基于屬性文件的此系列)。此示例中的鍵形式為 "s1" 等。實際的鍵完全取決于您的選擇,只要它們和程序中用于從資源包中獲取對象的鍵相同。鍵區(qū)分大小寫。
               

          public class MyResources extends ListResourceBundle {
               protected Object[][] getContents() {
                   return new Object[][] = {
               // LOCALIZE THIS
                   {"s1", "The disk \"{1}\" contains {0}."},  // MessageFormat pattern
                   {"s2", "1"},                               // location of {0} in pattern
                   {"s3", "My Disk"},                         // sample disk name
                   {"s4", "no files"},                        // first ChoiceFormat choice
                   {"s5", "one file"},                        // second ChoiceFormat choice
                   {"s6", "{0,number} files"},                // third ChoiceFormat choice
                   {"s7", "3 Mar 96"},                        // sample date
                   {"s8", new Dimension(1,5)}                 // real object, not just string
               
          // END OF MATERIAL TO LOCALIZE
               };
             }
           }

           public class MyResources_fr extends ListResourceBundle {
               protected Object[][] getContents() {
                   return new Object[][] = {
               // LOCALIZE THIS
                   {"s1", "Le disque \"{1}\" {0}."},          // MessageFormat pattern
                   {"s2", "1"},                               // location of {0} in pattern
                   {"s3", "Mon disque"},                      // sample disk name
                   {"s4", "ne contient pas de fichiers"},     // first ChoiceFormat choice
                   {"s5", "contient un fichier"},             // second ChoiceFormat choice
                   {"s6", "contient {0,number} fichiers"},    // third ChoiceFormat choice
                   {"s7", "3 mars 1996"},                     // sample date
                   {"s8", new Dimension(1,3)}                 // real object, not just string
               
          // END OF MATERIAL TO LOCALIZE
               };
             }
          }
          posted @ 2012-01-04 14:29 RoyPayne 閱讀(315) | 評論 (0)編輯 收藏

          ORACLE日期時間函數大全

             TO_DATE格式(以時間:2007-11-02   13:45:25為例)
             
                  Year:      
                  yy two digits 兩位年                顯示值:07
                  yyy three digits 三位年                顯示值:007
                  yyyy four digits 四位年                顯示值:2007
                      
                  Month:      
                  mm    number     兩位月              顯示值:11
                  mon    abbreviated 字符集表示          顯示值:11月,若是英文版,顯示nov     
                  month spelled out 字符集表示          顯示值:11月,若是英文版,顯示november 
                    
                  Day:      
                  dd    number         當月第幾天        顯示值:02
                  ddd    number         當年第幾天        顯示值:02
                  dy    abbreviated 當周第幾天簡寫    顯示值:星期五,若是英文版,顯示fri
                  day    spelled out   當周第幾天全寫    顯示值:星期五,若是英文版,顯示friday        
                  ddspth spelled out, ordinal twelfth 
                       
                        Hour:
                        hh    two digits 12小時進制            顯示值:01
                        hh24 two digits 24小時進制            顯示值:13
                        
                        Minute:
                        mi    two digits 60進制                顯示值:45
                        
                        Second:
                        ss    two digits 60進制                顯示值:25
                        
                        其它
                        Q     digit         季度                  顯示值:4
                        WW    digit         當年第幾周            顯示值:44
                        W    digit          當月第幾周            顯示值:1
                        
                  24小時格式下時間范圍為: 0:00:00 - 23:59:59....      
                  12小時格式下時間范圍為: 1:00:00 - 12:59:59 .... 
                      
          1. 日期和字符轉換函數用法(to_date,to_char)
                   
          select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') as nowTime from dual;   //日期轉化為字符串   
          select to_char(sysdate,'yyyy') as nowYear   from dual;   //獲取時間的年   
          select to_char(sysdate,'mm')    as nowMonth from dual;   //獲取時間的月   
          select to_char(sysdate,'dd')    as nowDay    from dual;   //獲取時間的日   
          select to_char(sysdate,'hh24') as nowHour   from dual;   //獲取時間的時   
          select to_char(sysdate,'mi')    as nowMinute from dual;   //獲取時間的分   
          select to_char(sysdate,'ss')    as nowSecond from dual;   //獲取時間的秒

              
          select to_date('2004-05-07 13:23:44','yyyy-mm-dd hh24:mi:ss')    from dual//

          2.      
              select to_char( to_date(222,'J'),'Jsp') from dual      
              
              顯示Two Hundred Twenty-Two    

          3.求某天是星期幾      
             select to_char(to_date('2002-08-26','yyyy-mm-dd'),'day') from dual;      
             星期一      
             select to_char(to_date('2002-08-26','yyyy-mm-dd'),'day','NLS_DATE_LANGUAGE = American') from dual;      
             monday      
             設置日期語言      
             ALTER SESSION SET NLS_DATE_LANGUAGE='AMERICAN';      
             也可以這樣      
             TO_DATE ('2002-08-26', 'YYYY-mm-dd', 'NLS_DATE_LANGUAGE = American')    

          4. 兩個日期間的天數      
              select floor(sysdate - to_date('20020405','yyyymmdd')) from dual;    

          5. 時間為null的用法      
             select id, active_date from table1      
             UNION      
             select 1, TO_DATE(null) from dual;      
             
             注意要用TO_DATE(null)    

          6.月份差   
             a_date between to_date('20011201','yyyymmdd') and to_date('20011231','yyyymmdd')      
             那么12月31號中午12點之后和12月1號的12點之前是不包含在這個范圍之內的。      
             所以,當時間需要精確的時候,覺得to_char還是必要的 
                
          7. 日期格式沖突問題      
              輸入的格式要看你安裝的ORACLE字符集的類型, 比如: US7ASCII, date格式的類型就是: '01-Jan-01'      
              alter system set NLS_DATE_LANGUAGE = American      
              alter session set NLS_DATE_LANGUAGE = American      
              或者在to_date中寫      
              select to_char(to_date('2002-08-26','yyyy-mm-dd'),'day','NLS_DATE_LANGUAGE = American') from dual;      
              注意我這只是舉了NLS_DATE_LANGUAGE,當然還有很多,      
              可查看      
              select * from nls_session_parameters      
              select * from V$NLS_PARAMETERS    

          8.      
             select count(*)      
             from ( select rownum-1 rnum      
                 from all_objects      
                 where rownum <= to_date('2002-02-28','yyyy-mm-dd') - to_date('2002-      
                 02-01','yyyy-mm-dd')+1      
                )      
             where to_char( to_date('2002-02-01','yyyy-mm-dd')+rnum-1, 'D' )      
                  not in ( '1', '7' )      
             
             查找2002-02-28至2002-02-01間除星期一和七的天數      
             在前后分別調用DBMS_UTILITY.GET_TIME, 讓后將結果相減(得到的是1/100秒, 而不是毫秒).    

          9. 查找月份     
              select months_between(to_date('01-31-1999','MM-DD-YYYY'),to_date('12-31-1998','MM-DD-YYYY')) "MONTHS" FROM DUAL;      
              1      
             select months_between(to_date('02-01-1999','MM-DD-YYYY'),to_date('12-31-1998','MM-DD-YYYY')) "MONTHS" FROM DUAL;      
              1.03225806451613 
                 
          10. Next_day的用法      
              Next_day(date, day)      
              
              Monday-Sunday, for format code DAY      
              Mon-Sun, for format code DY      
              1-7, for format code D    

          11      
             select to_char(sysdate,'hh:mi:ss') TIME from all_objects      
             注意:第一條記錄的TIME 與最后一行是一樣的      
             可以建立一個函數來處理這個問題      
             create or replace function sys_date return date is      
             begin      
             return sysdate;      
             end;      
             
             select to_char(sys_date,'hh:mi:ss') from all_objects;   
               
          12.獲得小時數      
               extract()找出日期或間隔值的字段值
              SELECT EXTRACT(HOUR FROM TIMESTAMP '2001-02-16 2:38:40') from offer      
              SQL> select sysdate ,to_char(sysdate,'hh') from dual;      
              
              SYSDATE TO_CHAR(SYSDATE,'HH')      
              -------------------- ---------------------      
              2003-10-13 19:35:21 07      
              
              SQL> select sysdate ,to_char(sysdate,'hh24') from dual;      
              
              SYSDATE TO_CHAR(SYSDATE,'HH24')      
              -------------------- -----------------------      
              2003-10-13 19:35:21 19    

                 
          13.年月日的處理      
             select older_date,      
                 newer_date,      
                 years,      
                 months,      
                 abs(      
                  trunc(      
                   newer_date-      
                   add_months( older_date,years*12+months )      
                  )      
                 ) days 
                 
             from ( select      
                  trunc(months_between( newer_date, older_date )/12) YEARS,      
                  mod(trunc(months_between( newer_date, older_date )),12 ) MONTHS,      
                  newer_date,      
                  older_date      
                  from ( 
                        select hiredate older_date, add_months(hiredate,rownum)+rownum newer_date      
                        from emp 
                       )      
                )    

          14.處理月份天數不定的辦法      
             select to_char(add_months(last_day(sysdate) +1, -2), 'yyyymmdd'),last_day(sysdate) from dual    

          16.找出今年的天數      
             select add_months(trunc(sysdate,'year'), 12) - trunc(sysdate,'year') from dual    

             閏年的處理方法      
             to_char( last_day( to_date('02'    | | :year,'mmyyyy') ), 'dd' )      
             如果是28就不是閏年    

          17.yyyy與rrrr的區(qū)別      
             'YYYY99 TO_C      
             ------- ----      
             yyyy 99 0099      
             rrrr 99 1999      
             yyyy 01 0001      
             rrrr 01 2001    

          18.不同時區(qū)的處理      
             select to_char( NEW_TIME( sysdate, 'GMT','EST'), 'dd/mm/yyyy hh:mi:ss') ,sysdate      
             from dual;    

          19.5秒鐘一個間隔      
             Select TO_DATE(FLOOR(TO_CHAR(sysdate,'SSSSS')/300) * 300,'SSSSS') ,TO_CHAR(sysdate,'SSSSS')      
             from dual    

             2002-11-1 9:55:00 35786      
             SSSSS表示5位秒數    

          20.一年的第幾天      
             select TO_CHAR(SYSDATE,'DDD'),sysdate from dual
                  
             310 2002-11-6 10:03:51    

          21.計算小時,分,秒,毫秒      
              select      
               Days,      
               A,      
               TRUNC(A*24) Hours,      
               TRUNC(A*24*60 - 60*TRUNC(A*24)) Minutes,      
               TRUNC(A*24*60*60 - 60*TRUNC(A*24*60)) Seconds,      
               TRUNC(A*24*60*60*100 - 100*TRUNC(A*24*60*60)) mSeconds      
              from      
              (      
               select      
               trunc(sysdate) Days,      
               sysdate - trunc(sysdate) A      
               from dual      
             )    


             select * from tabname      
             order by decode(mode,'FIFO',1,-1)*to_char(rq,'yyyymmddhh24miss');      
             
             //      
             floor((date2-date1) /365) 作為年      
             floor((date2-date1, 365) /30) 作為月      
             d(mod(date2-date1, 365), 30)作為日.

          23.next_day函數      返回下個星期的日期,day為1-7或星期日-星期六,1表示星期日
             next_day(sysdate,6)是從當前開始下一個星期五。后面的數字是從星期日開始算起。      
             1 2 3 4 5 6 7      
             日 一 二 三 四 五 六    
             
             --------------------------------------------------------------- 
             
             select    (sysdate-to_date('2003-12-03 12:55:45','yyyy-mm-dd hh24:mi:ss'))*24*60*60 from ddual
             日期 返回的是天 然后 轉換為ss
               
          24,round[舍入到最接近的日期](day:舍入到最接近的星期日)
             select sysdate S1,
             round(sysdate) S2 ,
             round(sysdate,'year') YEAR,
             round(sysdate,'month') MONTH ,
             round(sysdate,'day') DAY from dual

          25,trunc[截斷到最接近的日期,單位為天] ,返回的是日期類型
             select sysdate S1,                     
               trunc(sysdate) S2,                 //返回當前日期,無時分秒
               trunc(sysdate,'year') YEAR,        //返回當前年的1月1日,無時分秒
               trunc(sysdate,'month') MONTH ,     //返回當前月的1日,無時分秒
               trunc(sysdate,'day') DAY           //返回當前星期的星期天,無時分秒
             from dual

          26,返回日期列表中最晚日期
             select greatest('01-1月-04','04-1月-04','10-2月-04') from dual

          27.計算時間差
               注:oracle時間差是以天數為單位,所以換算成年月,日
               
                select floor(to_number(sysdate-to_date('2007-11-02 15:55:03','yyyy-mm-dd hh24:mi:ss'))/365) as spanYears from dual        //時間差-年
                select ceil(moths_between(sysdate-to_date('2007-11-02 15:55:03','yyyy-mm-dd hh24:mi:ss'))) as spanMonths from dual        //時間差-月
                select floor(to_number(sysdate-to_date('2007-11-02 15:55:03','yyyy-mm-dd hh24:mi:ss'))) as spanDays from dual             //時間差-天
                select floor(to_number(sysdate-to_date('2007-11-02 15:55:03','yyyy-mm-dd hh24:mi:ss'))*24) as spanHours from dual         //時間差-時
                select floor(to_number(sysdate-to_date('2007-11-02 15:55:03','yyyy-mm-dd hh24:mi:ss'))*24*60) as spanMinutes from dual    //時間差-分
                select floor(to_number(sysdate-to_date('2007-11-02 15:55:03','yyyy-mm-dd hh24:mi:ss'))*24*60*60) as spanSeconds from dual //時間差-秒

          28.更新時間
               注:oracle時間加減是以天數為單位,設改變量為n,所以換算成年月,日
               select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss'),to_char(sysdate+n*365,'yyyy-mm-dd hh24:mi:ss') as newTime from dual        //改變時間-年
               select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss'),add_months(sysdate,n) as newTime from dual                                 //改變時間-月
               select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss'),to_char(sysdate+n,'yyyy-mm-dd hh24:mi:ss') as newTime from dual            //改變時間-日
               select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss'),to_char(sysdate+n/24,'yyyy-mm-dd hh24:mi:ss') as newTime from dual         //改變時間-時
               select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss'),to_char(sysdate+n/24/60,'yyyy-mm-dd hh24:mi:ss') as newTime from dual      //改變時間-分
               select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss'),to_char(sysdate+n/24/60/60,'yyyy-mm-dd hh24:mi:ss') as newTime from dual   //改變時間-秒

          29.查找月的第一天,最后一天
               SELECT Trunc(Trunc(SYSDATE, 'MONTH') - 1, 'MONTH') First_Day_Last_Month,
                 Trunc(SYSDATE, 'MONTH') - 1 / 86400 Last_Day_Last_Month,
                 Trunc(SYSDATE, 'MONTH') First_Day_Cur_Month,
                 LAST_DAY(Trunc(SYSDATE, 'MONTH')) + 1 - 1 / 86400 Last_Day_Cur_Month
             FROM dual;


          三. 字符函數(可用于字面字符或數據庫列)

          1,字符串截取
             select substr('abcdef',1,3) from dual

          2,查找子串位置
             select instr('abcfdgfdhd','fd') from dual

          3,字符串連接
             select 'HELLO'||'hello world' from dual;

          4, 1)去掉字符串中的空格
              select ltrim(' abc') s1,
              rtrim('zhang ') s2,
              trim(' zhang ') s3 from dual
             2)去掉前導和后綴
              select trim(leading 9 from 9998767999) s1,
              trim(trailing 9 from 9998767999) s2,
              trim(9 from 9998767999) s3 from dual;
             
          5,返回字符串首字母的Ascii值
             select ascii('a') from dual

          6,返回ascii值對應的字母
             select chr(97) from dual

          7,計算字符串長度 
             select length('abcdef') from dual

          8,initcap(首字母變大寫) ,lower(變小寫),upper(變大寫)
             select lower('ABC') s1, 
                 upper('def') s2, 
                 initcap('efg') s3
             from dual;

          9,Replace
             select replace('abc','b','xy') from dual;

          10,translate
             select translate('abc','b','xx') from dual; -- x是1位

          11,lpad [左添充] rpad [右填充](用于控制輸出格式)
             select lpad('func',15,'=') s1, rpad('func',15,'-') s2 from dual;
             select lpad(dname,14,'=') from dept;

          12, decode[實現if ..then 邏輯]   注:第一個是表達式,最后一個是不滿足任何一個條件的值
             select deptno,decode(deptno,10,'1',20,'2',30,'3','其他') from dept;
             例:
             select seed,account_name,decode(seed,111,1000,200,2000,0) from t_userInfo//如果seed為111,則取1000;為200,取2000;其它取0
             select seed,account_name,decode(sign(seed-111),1,'big seed',-1,'little seed','equal seed') from t_userInfo//如果seed>111,則顯示大;為200,則顯示小;其它則顯

          示相等

          13 case[實現switch ..case 邏輯]
              SELECT CASE X-FIELD 
                   WHEN X-FIELD < 40 THEN 'X-FIELD 小于 40'
                   WHEN X-FIELD < 50 THEN 'X-FIELD 小于 50'
                   WHEN X-FIELD < 60 THEN 'X-FIELD 小于 60'
                   ELSE 'UNBEKNOWN'
                  END
             FROM DUAL 
             
             注:CASE語句在處理類似問題就顯得非常靈活。當只是需要匹配少量數值時,用Decode更為簡潔。

          四.數字函數
          1,取整函數(ceil 向上取整,floor 向下取整)
             select ceil(66.6) N1,floor(66.6) N2 from dual;

          2, 取冪(power) 和 求平方根(sqrt)
             select power(3,2) N1,sqrt(9) N2 from dual;

          3,求余
             select mod(9,5) from dual;

          4,返回固定小數位數 (round:四舍五入,trunc:直接截斷)
             select round(66.667,2) N1,trunc(66.667,2) N2 from dual;

          5,返回值的符號(正數返回為1,負數為-1)
             select sign(-32),sign(293) from dual;

          五.轉換函數
          1,to_char()[將日期和數字類型轉換成字符類型]
             1) select to_char(sysdate) s1,
                  to_char(sysdate,'yyyy-mm-dd') s2,
                  to_char(sysdate,'yyyy') s3,
                  to_char(sysdate,'yyyy-mm-dd hh12:mi:ss') s4,
                  to_char(sysdate, 'hh24:mi:ss') s5,
                  to_char(sysdate,'DAY') s6 
              from dual;
             2) select sal,to_char(sal,'$99999') n1,to_char(sal,'$99,999') n2 from emp

          2, to_date()[將字符類型轉換為日期類型] 
              insert into emp(empno,hiredate) values(8000,to_date('2004-10-10','yyyy-mm-dd'));
             
          3, to_number() 轉換為數字類型 
              select to_number(to_char(sysdate,'hh12')) from dual; //以數字顯示的小時數
             
          六.其他函數
             1.user: 
              返回登錄的用戶名稱 
              select user from dual;
              
             2.vsize: 
              返回表達式所需的字節(jié)數
              select vsize('HELLO') from dual;
             
             3.nvl(ex1,ex2):  
              ex1值為空則返回ex2,否則返回該值本身ex1(常用) 
              例:如果雇員沒有傭金,將顯示0,否則顯示傭金 
              select comm,nvl(comm,0) from emp;
             
             4.nullif(ex1,ex2): 
              值相等返空,否則返回第一個值
              例:如果工資和傭金相等,則顯示空,否則顯示工資
              select nullif(sal,comm),sal,comm from emp;
             
             5.coalesce:  
              返回列表中第一個非空表達式
              select comm,sal,coalesce(comm,sal,sal*10) from emp;
             
             6.nvl2(ex1,ex2,ex3) :
              如果ex1不為空,顯示ex2,否則顯示ex3
              如:查看有傭金的雇員姓名以及他們的傭金 
                select nvl2(comm,ename,') as HaveCommName,comm from emp;
             
             
          七.分組函數
          max min avg count sum
          1,整個結果集是一個組
             1) 求部門30 的最高工資,最低工資,平均工資,總人數,有工作的人數,工種數量及工資總和
               select max(ename),max(sal), 
               min(ename),min(sal),
               avg(sal),
               count(*) ,count(job),count(distinct(job)) ,
               sum(sal) from emp where deptno=30;
          2, 帶group by 和 having 的分組
             1)按部門分組求最高工資,最低工資,總人數,有工作的人數,工種數量及工資總和
              select deptno, max(ename),max(sal),
              min(ename),min(sal),
              avg(sal),
              count(*) ,count(job),count(distinct(job)) ,
              sum(sal) from emp group by deptno;
             
             2)部門30的最高工資,最低工資,總人數,有工作的人數,工種數量及工資總和 
              select deptno, max(ename),max(sal),
              min(ename),min(sal),
              avg(sal),
              count(*) ,count(job),count(distinct(job)) ,
              sum(sal) from emp group by deptno having deptno=30;
             
          3, stddev 返回一組值的標準偏差
              select deptno,stddev(sal) from emp group by deptno;
              variance 返回一組值的方差差
              select deptno,variance(sal) from emp group by deptno;

          4, 帶有rollup和cube操作符的Group By
              rollup 按分組的第一個列進行統計和最后的小計
              cube 按分組的所有列的進行統計和最后的小計
              select deptno,job ,sum(sal) from emp group by deptno,job;
              select deptno,job ,sum(sal) from emp group by rollup(deptno,job); 
              cube 產生組內所有列的統計和最后的小計
              select deptno,job ,sum(sal) from emp group by cube(deptno,job);

          八、臨時表
             只在會話期間或在事務處理期間存在的表.
             臨時表在插入數據時,動態(tài)分配空間 
             create global temporary table temp_dept
             (dno number,
             dname varchar2(10))
             on commit delete rows;
             insert into temp_dept values(10,'ABC');
             commit;
             select * from temp_dept; --無數據顯示,數據自動清除
             on commit preserve rows:在會話期間表一直可以存在(保留數據)
             on commit delete rows:事務結束清除數據(在事務結束時自動刪除表的數據)

          posted @ 2011-12-31 13:59 RoyPayne 閱讀(260) | 評論 (0)編輯 收藏
          主站蜘蛛池模板: 肇庆市| 卫辉市| 从化市| 连平县| 济南市| 龙门县| 麟游县| 盐边县| 祁连县| 雅安市| 蒙城县| 扬中市| 博客| 丰宁| 福鼎市| 滨海县| 蓝田县| 象州县| 黄浦区| 香河县| 息烽县| 股票| 安丘市| 台湾省| 疏附县| 东阿县| 正蓝旗| 仙游县| 台北市| 星座| 无锡市| 洞头县| 荥阳市| 保康县| 洱源县| 象州县| 无锡市| 赤峰市| 澜沧| 巫溪县| 山东省|