如何學好java

          如何學好java,其實很簡單,只要用心體會,慢慢積累!
          posts - 106, comments - 7, trackbacks - 0, articles - 3
            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

          1.列出至少有一個員工的所有部門。(兩個表聯合查詢,及group by...having的用法)
          select dname from dept where deptno in(select deptno from emp group by deptno having count(*)>1);

          2.列出薪金比“SMITH”多的所有員工。(經典的自連接查詢)
          select ename from emp where sal>(select sal from emp where ename like'SMITH');

          3.列出所有員工的姓名及其直接上級的姓名。(多次對自己查詢,為表的取個別名,內部查詢可以像對象一樣引用外部的對象的字段,這里引用與編程中的作用域相似,即與{}類比)

          select ename,(select ename from emp where empno in(a.mgr)) from emp a ;

          4.列出受雇日期早于其直接上級的所有員工。(同上,日期可直接拿來比較)

          select ename from emp a where HIREDATE<(select HIREDATE from emp where empno in(a.mgr));

          5.列出部門名稱和這些部門的員工信息,同時列出那些沒有員工的部門(以emp表為主,左連接查詢)

          select dname,emp.* from dept left join emp on dept.deptno=emp.deptno;

          6.列出所有“CLERK”(辦事員)的姓名及其部門名稱。(域,注意())

          select ename,(select dname from dept where deptno in(a.deptno)) as dname from emp a where JOB like'CLERK';

          7.列出最低薪金大于1500的各種工作。
          select job from emp where sal>1500;

          8.列出在部門“SALES”(銷售部)工作的員工的姓名,假定不知道銷售部的部門編號。(經典的兩個表連接)

          select ename from emp where deptno=(select deptno from dept where dname like'SALES');

          9.列出薪金高于公司平均薪金的所有員工。(反復查自己)

          select ename from emp where sal>( select avg( sal) from emp);

          10.列出與“SCOTT”從事相同工作的所有員工。(排除自己)

          select ename from emp where job in(select job from emp where ename like'SCOTT') and ename!='SCOTT' ;

          11.列出薪金等于部門30中員工的薪金的所有員工的姓名和薪金。(any的用法,且排擠)

          select ename,sal from emp where sal=any(select sal from emp wheredeptno=30) and deptno!=30;

          12.列出薪金高于在部門30工作的所有員工的薪金的員工姓名和薪金。(max的用法)

          select sal,ename from emp where sal>(select max(sal) from emp where deptno=30);


          13.列出在每個(每個是關鍵字,對此group by)部門工作的員工數量、平均工資和平均服務期限。(經典的group by用法)

          select deptno,count(*),avg(a.sal),avg(sysdate-HIREDATE) from emp a group by deptno;

          14.列出所有員工的姓名、部門名稱和工資.(經典的兩個表的連接查詢,用具體的名稱替換一個表中的主鍵的id (解決很多人在實際運用中會遇到的不能綁定多列的問題),也可用where來查詢 ,與題5比較)

          select ename,sal,(select dname from dept a where a.deptno=b.deptno)as dname from emp b;

          15.列出所有部門的詳細信息和部門人數。(因為是*,將顯示dept和后面臨時表b的全部字段(注意:不只是dept的字段,注意*號))

          select * from dept a left join (select deptno,count(*) from emp group by deptno) b on a.deptno=b.deptno ;

          16.列出各種(與每個同義(參看題13))工作的最低工資。

          select job,min(sal) from emp group by job ;


          17.列出各個部門的MANAGER(經理,經理唯一,不用group by)的最低薪金。

          select min(sal) from emp where job like'MANAGER';(因為MANAGER是值不是字段,所以不能用小寫)

          18.列出所有員工的年工資,按年薪從低到高排序。(nvl:空轉化函數)

          select ename,sal+nvl(comm,0) as sal from emp order by sal ;

          posted @ 2011-05-28 16:33 哈希 閱讀(175) | 評論 (0)編輯 收藏

          簡單的說:

          struts 控制用的

          hibernate 操作數據庫的

          spring 用解耦的

          詳細的說:

          STRUTS 在 SSH 框架中起控制的作用 , 其核心是 Controller, 即 ActionServlet, 而 ActionServlet 的核心就是 Struts-confi g.xml. 主要控制邏輯關系的處理 .

          hibernate 是數據持久化層 , 是一種新的對象、關系的映射工具 , 提供了從 Java 類到數據表的映射,也提供了數據查詢和恢復等機制 , 大大減少數據訪問的復雜度。把對數據庫的直接操作 , 轉換為對持久對象的操作 .

          SPRING 是一個輕量級的控制反轉 (IoC) 和面向切面 (AOP) 的容器框架 , 面向接口的編程 , 由容器控制程序之間的(依賴)關系,而非傳統實現中,由程序代碼直接操控。這也就是所謂 “ 控制反轉 ” 的概念所在:(依賴)控制權由應用代碼中轉到了外部容器,控制權的轉移,是所謂反轉。依賴注入,即組件之間的依賴關系由容器在運行期決定,形象的來說,即由容器動態的將某種依賴關系注入到組件之中

          起到的主要作用是解耦

          Struts 、 spring 、 Hibernate 在各層的作用

          1 ) struts 負責 web 層 .

          ActionFormBean 接收網頁中表單提交的數據,然后通過 Action 進行處理,再 Forward 到對應的網頁。

          在 struts-config.xml 中定義 <action-mapping>, ActionServlet 會加載。

          2 ) spring 負責業務層管理,即 Service (或 Manager).

          1 . service 為 action 提供統計的調用接口,封裝持久層的 DAO.

          2 .可以寫一些自己的業務方法。

          3 .統一的 javabean 管理方法

          4 .聲明式事務管理(http://www.cnblogs.com/rushoooooo/archive/2011/08/28/2155960.html

          5. 集成 Hiberante

          3 ) Hiberante ,負責持久化層,完成數據庫的 crud 操作

          hibernate 為持久層,提供 OR/Mapping 。

          它有一組 .hbm.xml 文件和 POJO, 是跟數據庫中的表相對應的。然后定義 DAO ,這些是跟數據庫打交道的類,它們會使用 PO 。

          在 struts+spring+hibernate 的系統中,

          對象的調用流程是: jsp-> Action - > Service ->DAO ->Hibernate 。

          數據的流向是 ActionFormBean 接受用戶的數據, Action 將數據從 ActionFromBean 中取出,封裝成 VO 或 PO,

          再調用業務層的 Bean 類,完成各種業務處理后再 forward 。而業務層 Bean 收到這個 PO 對象之后,會調用 DAO 接口方法,進行持久化操作。

           

           

           

          spring:Aop管理事務控制,IoC管理各個組件的耦合,DaoTemplate作為常規持久層的快速開發模板!

          struts:控制層Action,頁面標簽和Model數據,調用業務層

          Hibernate:負責數據庫和對象的映射,負責DAO層(Data Access Object:數據訪問)

           

          spring整合hibernate和struts,只要在配好了applicationContext.xml,在struts的action中直接調用就可以了。hibernate訪問數據庫的操作都在spring中實現了,spring的調用又在stuts的action中實現了。這個ssh框架就連到了一起……

           

           

          1 SSH在開發中的位置

          現在J2EE的開源框架多的數不清楚,目前(已經、正在)比較流行的常用框架大概有struts,spring,hibernate,jsf,webwork,而 struts+spring+hibernate(SSH)這種輕量級架構被譽為“黃金組合”。spring和hibernate更是被許多人認為是未來五年內不會被淘汰的技術,猶如當年的struts,今天的開發中依然被廣泛采用。

          2 為什么使用SSH  

          其實,就算用Java建造一個不是很煩瑣的web應用,也不是件輕松的事情。 在構架的一開始就有很多事情要考慮。從高處看,擺在開發者面前有很多問題:要考慮是怎樣建立用戶接口?在哪里處理業務邏輯? 怎樣持久化的數據。 而這三層構架中,每一層都有他們要仔細考慮的。 各個層該使用什么技術?怎樣的設計能松散耦合還能靈活改變? 怎樣替換某個層而不影響整體構架?應用程序如何做各種級別的業務處理(比如事務處理)?

              構架一個Web應用需要弄明白好多問題。 幸運的是,已經有不少開發者已經遇到過這類問題,并且建立了處理這類問題的框架。 一個好框架具備以下幾點:減輕開發者處理復雜的問題的負擔("不重復發明輪子");內部有良好的擴展; 并且有一個支持它的強大的用戶團體。 好的構架一般有針對性的處理某一類問題,并且能將它做好(Do One Thing well)。 然而,你的程序中有幾個層可能需要使用特定的框架,已經完成的UI(用戶接口) 并不代表你也可以把你的業務邏輯和持久邏輯偶合到你的UI部分。 舉個例子,你不該在一個Controller(控制器)里面寫JDBC代碼作為你的業務邏輯, 這不是控制器應該提供的。 一個UI 控制器應該委派給其它給在UI范圍之外的輕量級組件。 好的框架應該能指導代碼如何分布。 更重要的是,框架能把開發者從編碼中解放出來,使他們能專心于應用程序的邏輯(這對客戶來說很重要)。 

          他們里面有很我優秀的設計理念及模式應用。比如, struts屬于MVC框架,關鍵是要了解MVC的概念及大致原理,掌握就很容易了;而hibernate屬于orm系統,屬于持久層的解決方案,同樣需要對ORM的概念及原理有一個總體的了解,必要時可以去查查EJB1及EJB2里面用于持久層的Entity Bean的使用。而spring屬于應用程序框架,其核心是IOC容器以及AOP,把這兩個核心概念(也可稱為大模式)了解以后,再加上一定的內力修為,其它就都不難了。Spring中還集成了很多適用東西(不過這些東西80%的在某一個項目中可能一直用不上),比如對JDBC的封裝、自己的MVC、對動態語言的簡潔訪問等,這些你根據自己的項目情況來選擇學習,用到的時候再看看他的文檔,一個項目下來應該就能把握。

          3 對于SSH的理解

          在SSH框架中,struts用來解決MVC中顯示、請求控制部分,spring主要負責訪問數據庫DAO類的事務控制以及它被人稱譽的IOC思想在業務類中的恰當運用,hibernate主要是充當數據訪問層組件。由于spring對hibernate的良好支持,在DAO類主要由spring來完成,hibernate更多關注的應是O/R影射文件上的配置,如級聯關系,延遲加載等如何設置才能使效率更高。見圖1 (框架組合示意圖)

          4 收獲和問題

          4.1 actionform,PO,VO三對象的運用

          討論最多的是actionform,PO,VO三對象的運用,本人傾向的觀點是:在SSH框架中,PO和VO可以不必區分,即業務層和持久層都可以使用hibernate產生的PO對象,我暫時把對象分成actionform和po兩種來分析,action 應該是actionform和po的分界點,po不能穿透業務層,突破action到達頁面顯示層,同樣actionform也不能突破action傳到后臺業務、持久層。(原因:po是持久對象,到達頁面后就脫離了session成為無狀態(暫理解為脫管態)的對象,而hibernate的持久對象是有狀態(包含數據庫主鍵)的,無狀態的對象傳到后臺在調用hibernate的保存方法時會出錯,一定要把無狀態的對象先轉化成持久態對象才能保存)在action中應該對兩對象進行轉化,轉化的方法目前我還沒發現有什么非常好的方法(歡迎高手不惜賜教),最普通的就是用get(),set()方法,也可以使用struts提供的屬性復制方法BeanUtils類,但這個好象只支持單個類的轉化,對于集合對象不行,需要我們自己擴展。

          4.2 spring事務管理

          在配置spring的事務管理中,最好把事務控制配置在業務類上,而不要配置在DAO類(需要保證多個原子事務操作同時失敗回滾時這是一種解決辦法);

          4.3 action如何獲取業務類

          action中如何獲取業務類:寫一個父類action,在父類中通過spring的webapplicationcontent獲得業務類的實例。struts中的具體action繼承該父類,通過調用父類的getService()直接獲得業務類的實例。

          4.4 理解AOP思想

          深入理解AOP思想,我暫時感覺到的就是盡量面向接口編程,不管是域對象還是業務類或者是DAO類都設計出接口,在各方法中我們盡量傳入對象的接口,這對我們重用這些方法,擴展是很有好處的。

          4.5 分頁處理 level

          5 系統包劃分

          posted @ 2011-05-20 17:00 哈希 閱讀(318) | 評論 (0)編輯 收藏

               摘要: Eclipse快速上手Hibernate--1. 入門實例 < language="javascript" type="text/javascript">document.title="Eclipse快速上手Hibernate--1. 入門實例 - "+document.title     這篇文章主要談談Hibernate的入門開發,例子很簡單,就是...  閱讀全文

          posted @ 2011-05-20 15:30 哈希 閱讀(160) | 評論 (0)編輯 收藏

               摘要: 這篇文章將教你快速地上手使用 Spring 框架. 如果你手上有一本《Spring in Action》, 那么你最好從第三部分"Spring 在 Web 層的應用--建立 Web 層"開始看, 否則那將是一場惡夢! 首先, 我需要在你心里建立起 Spring MVC 的基本概念. 基于 Spring 的 Web 應用程序接收到 http://localhost:8080/...  閱讀全文

          posted @ 2011-05-17 22:23 哈希 閱讀(250) | 評論 (0)編輯 收藏

          所用數據:
          SELECT a.deptno, a.employename, a.salary
            FROM t_salary a

          000001         李可                              1000
          000001         李強                              2000
          000001         楊彥軍                            4000
          000002         童家道                            3000
          000002         姜文                              3000
          000002         羅文                              3000
          000003         窨嫡                              3000
          000003         童家道                            3000
          000003         童家道                            3000
          000004         于名                              4000
          SELECT A.deptno, A.employename,A.salary,
          --1 按照名稱進行分區,同時按照名稱進行合計 
          SUM(A.salary)OVER(PARTITION BY A.employename) AS SUM_INC_ONLY,
          --2 按照名稱進行累計 
          SUM(A.salary)OVER(ORDER BY A.employename) AS SUM_INC,
          --3   和 1 效果相同 
          SUM(A.salary)OVER(PARTITION BY A.employename ORDER BY A.employename) AS SUM_INC_NAME,
          --4 按照部門分組,部門內進行合計。名稱相同時進行累計 
          SUM(A.salary)OVER(PARTITION BY A.deptno ORDER BY A.employename) AS SUM_INC_DEP,
          --5 按照部門,名稱分組,部門名稱相同時進行合計 
          SUM(A.salary)OVER(PARTITION BY A.deptno,A.employename ) AS SUM_INC_DEP_NAM
          FROM t_salary A


          所得結果:
          DEPTNO     EMPLOYENAME     SALARY     SUM_INC_ONLY     SUM_INC     SUM_INC_NAME     SUM_INC_DEP     SUM_INC_DEP_NAM
          000002     姜文    3000    3000    3000    3000    3000    3000
          000001     李可    1000    1000    4000    1000    1000    1000
          000001     李強    2000    2000    6000    2000    3000    2000
          000002     羅文    3000    3000    9000    3000    6000    3000
          000002     童家道    3000    9000    18000    9000    9000    3000
          000003     童家道    3000    9000    18000    9000    6000    6000
          000003     童家道    3000    9000    18000    9000    6000    6000
          000001     楊彥軍    4000    4000    22000    4000    7000    4000
          000004     于名    4000    4000    26000    4000    4000    4000
          000003     窨嫡    3000    3000    29000    3000    9000    3000

          posted @ 2011-05-13 17:01 哈希 閱讀(176) | 評論 (0)編輯 收藏

          緩存是位于應用程序與物理數據源之間,用于臨時存放復制數據的內存區域,目的是為了減少應用程序對物理數據源訪問的次數,從而提高應用程序的運行性能.
            Hibernate在查詢數據時,首先到緩存中去查找,如果找到就直接使用,找不到的時候就會從物理數據源中檢索,所以,把頻繁使用的數據加載到緩存區后,就可以大大減少應用程序對物理數據源的訪問,使得程序的運行性能明顯的提升.

           
          Hibernate緩存分類:

          Session緩存,一級緩存.

          SessionFactory的緩存分為內置緩存和外置緩存.內置緩存中存放的是SessionFactory對象的一些集合屬性包含的數據(映射元素據 及預定義SQL語句等),對于應用程序來說,它是只讀的.外置緩存中存放的是數據庫數據的副本,其作用和一級緩存類似.二級緩存除了以內存作為存儲介質 外,還可以選用硬盤等外部存儲設備.

          Hibernate的緩存范圍

          Hibernate的一級緩存和二級緩存都位于均位于持久層,且均用于存放數據庫數據的副本,最大的區別就是緩存的范圍各不一樣.

          緩存的范圍分為3類:

          1.事務范圍
             事務范圍的緩存只能被當前事務訪問,每個事務都有各自的緩存,緩存內的數據通常采用相互關聯的對象形式.緩存的生命周期依賴于事務的生命周期,只有當事務結束時,緩存的生命周期才會結束.事務范圍的緩存使用內存作為存儲介質,一級緩存就屬于事務范圍.
          2.應用范圍
             應用程序的緩存可以被應用范圍內的所有事務共享訪問.緩存的生命周期依賴于應用的生命周期,只有當應用結束時,緩存的生命周期才會結束.應用范圍的緩存可以使用內存或硬盤作為存儲介質,二級緩存就屬于應用范圍.
          3.集群范圍
             在集群環境中,緩存被一個機器或多個機器的進程共享,緩存中的數據被復制到集群環境中的每個進程節點,進程間通過遠程通信來保證緩存中的數據的一致,緩存中的數據通常采用對象的松散數據形式.

            Hibernate的緩存管理

          一級緩存的管理:

            evit(Object obj)  將指定的持久化對象從一級緩存中清除,釋放對象所占用的內存資源,指定對象從持久化狀態變為脫管狀態,從而成為游離對象.
            clear()  將一級緩存中的所有持久化對象清除,釋放其占用的內存資源
            contains(Object obj) 判斷指定的對象是否存在于一級緩存中.
            flush() 刷新一級緩存區的內容,使之與數據庫數據保持同步.

            二級緩存的管理:
            
             evict(Class arg0, Serializable arg1)  將某個類的指定ID的持久化對象從二級緩存中清除,釋放對象所占用的資源.
            
          Java代碼  收藏代碼
          1. sessionFactory.evict(Customer.class, new Integer(1));  

             evict(Class arg0)  將指定類的所有持久化對象從二級緩存中清除,釋放其占用的內存資源.
            
          Java代碼  收藏代碼
          1. sessionFactory.evict(Customer.class);  

             evictCollection(String arg0)  將指定類的所有持久化對象的指定集合從二級緩存中清除,釋放其占用的內存資源.
            
          Java代碼  收藏代碼
          1. sessionFactory.evictCollection("Customer.orders");  


          Hibernate的二級緩存的配置

          首先,不是所有的數據都適合放在二級緩存中,看一下,什么樣的數據適合放在二級緩存中來?什么樣的數據不適合放在二級緩存中來?
            下面這幾種情況就不適合加載到二級緩存中:
            1.經常被修改的數據
            2.絕對不允許出現并發訪問的數據
            3.與其他應用共享的數據
            下面這己種情況合適加載到二級緩存中:
            1.數據更新頻率低
            2.允許偶爾出現并發問題的非重要數據
            3.不會被并發訪問的數據
            4.常量數據
            5.不會被第三方修改的數據

          Hibernate的二級緩存功能是靠配置二級緩存插件來實現的,Hibernate為了集成這些插件,Hibernate提供了org.hibernate.cache.CacheProvider借口,它充當緩存插件與Hibernate之間的適配器 .

          常用的二級緩存插件
          EHCache  org.hibernate.cache.EhCacheProvider
          OSCache  org.hibernate.cache.OSCacheProvider
          SwarmCahe  org.hibernate.cache.SwarmCacheProvider
          JBossCache  org.hibernate.cache.TreeCacheProvider

          簡單介紹一下EHCache的配置
          hibernate.cfg.xml
          Xml代碼  收藏代碼
          1. <hibernate-configuration>  
          2.    <session-factory>  
          3.       <!-- 設置二級緩存插件EHCache的Provider類-->  
          4.       <property name="hibernate.cache.provider_class">  
          5.          org.hibernate.cache.EhCacheProvider  
          6.       </property>  
          7.       <!-- 啟動"查詢緩存" -->  
          8.       <property name="hibernate.cache.use_query_cache">  
          9.          true  
          10.       </property>  
          11.    </session-factory>  
          12.  </hibernate-configuration>  


          ehcache.xml

          Xml代碼  收藏代碼
          1. <ehcache>  
          2.   <!-- maxElementsInMemory為緩存對象的最大數目, eternal設置是否永遠不過期,timeToIdleSeconds對象處于空閑狀態的最多秒數,timeToLiveSeconds對象處于緩存狀態的最多秒數 -->  
          3.   <diskStore path="java.io.tmpdir"/>  
          4.     <defaultCache maxElementsInMemory="10000" eternal="false"  timeToIdleSeconds="300" timeToLiveSeconds="600" overflowToDisk="true"/>  
          5. </ehcache>  


          ****.hbm.xml

          Xml代碼  收藏代碼
          1. <?xml version="1.0" encoding='UTF-8'?>  
          2. <!DOCTYPE hibernate-mapping PUBLIC  
          3.                             "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
          4.                             "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >  
          5.   
          6. <hibernate-mapping>  
          7.        
          8.    <class>  
          9.        <!-- 設置該持久化類的二級緩存并發訪問策略 read-only read-write nonstrict-read-write transactional-->  
          10.        <cache usage="read-write"/>      
          11.    </class>  
          12.   
          13. </hibernate-mapping>  


          最近用上了,看看了,有什么不妥的地方,多謝指出.

          posted @ 2011-05-10 18:03 哈希 閱讀(194) | 評論 (0)編輯 收藏

          1.關于spring ioc

          這段時間也著實好好的看了下spring的相關書籍,對其也有了大概和初步的認識和理解,雖然之前也一直聽說spring是一個非常優秀的開源 框架,可一直沒有機會學習和使用(是不是有點落伍了?呵呵),所以呢,這段時間就重點學習了spring(一個星期的時間當然是入門級的啦~~)

          大家一直都說spring的IOC如何如何的強大,其實我倒覺得不是IOC如何的強大,說白了IOC其實也非常的簡單。我們先從IOC說起, 這個概念其實是從我們平常new一個對象的對立面來說的,我們平常使用對象的時候,一般都是直接使用關鍵字類new一個對象,那這樣有什么壞處呢?其實很 顯然的,使用new那么就表示當前模塊已經不知不覺的和new的對象耦合了,而我們通常都是更高層次的抽象模塊調用底層的實現模塊,這樣也就產生了模塊依 賴于具體的實現,這樣與我們JAVA中提倡的面向接口面向抽象編程是相沖突的,而且這樣做也帶來系統的模塊架構問題。很簡單的例子,我們在進行數據庫操作 的時候,總是業務層調用DAO層,當然我們的DAO一般都是會采用接口開發,這在一定程度上滿足了松耦合,使業務邏輯層不依賴于具體的數據庫DAO層。但 是我們在使用的時候還是會new一個特定數據庫的DAO層,這無形中也與特定的數據庫綁定了,雖然我們可以使用抽象工廠模式來獲取DAO實現類,但除非我 們一次性把所有數據庫的DAO寫出來,否則在進行數據庫遷移的時候我們還是得修改DAO工廠類。

          那我們使用IOC能達到什么呢?IOC,就是DAO接口的實現不再是業務邏輯層調用工廠類去獲取,而是通過容器(比如spring)來自動的 為我們的業務層設置DAO的實現類。這樣整個過程就反過來,以前是我們業務層主動去獲取DAO,而現在是DAO主動被設置到業務邏輯層中來了,這也就是反 轉控制的由來。通過IOC,我們就可以在不修改任何代碼的情況下,無縫的實現數據庫的換庫遷移,當然前提還是必須得寫一個實現特定數據庫的DAO。我們把 DAO普遍到更多的情況下,那么IOC就為我們帶來更大的方便性,比如一個接口的多個實現,我們只需要配置一下就ok了,而不需要再一個個的寫工廠來來獲 取了。這就是IOC為我們帶來的模塊的松耦合和應用的便利性。

          那為什么說IOC很簡單呢?說白了其實就是由我們平常的new轉成了使用反射來獲取類的實例,相信任何人只要會用java的反射機制,那么自己寫一個IOC框架也不是不可能的。比如:

          ……
          public ObjectgetInstance(String className) throws Exception
          {
          Object obj = Class.forName(className).newInstance();
          Method[] methods = obj.getClass().getMethods();
          for (Method method : methods) {
          if (method.getName().intern() == "setString") {
          method.invoke(obj, "hello world!");
          }
          }
          }
          ……

          上面的一個方法我們就很簡單的使用了反射為指定的類的setString方法來設置一個hello world!字符串。其實可以看到IOC真的很簡單,當然了IOC簡單并不表示spring的IOC就簡單,spring的IOC的功能強大就在于有一系 列非常強大的配置文件維護類,它們可以維護spring配置文件中的各個類的關系,這才是spring的IOC真正強大的地方。在spring的Bean 定義文件中,不僅可以為定義Bean設置屬性,還支持Bean之間的繼承、Bean的抽象和不同的獲取方式等等功能。

          下次俺再把spring的Bean配置的相關心得和大家一起分享下,如果說的不好,大家可以提意見哦,可千萬不要仍臭雞蛋,嘿嘿~~~~


          2.關于spring aop

          反射實現 AOP 動態代理模式(Spring AOP 的實現 原理)
          好長時間沒有用過Spring了. 突然拿起書.我都發現自己對AOP都不熟悉了.
          其實AOP的意思就是面向切面編程.
          OO注重的是我們解決問題的方法(封裝成Method),而AOP注重的是許多解決解決問題的方法中的共同點,是對OO思想的一種補充!
          還是拿人家經常舉的一個例子講解一下吧:
          比如說,我們現在要開發的一個應用里面有很多的業務方法,但是,我們現在要對這個方法的執行做全面監控,或部分監控.也許我們就會在要一些方法前去加上一條日志記錄,
          我們寫個例子看看我們最簡單的解決方案
          我們先寫一個接口IHello.java代碼如下:
          1package sinosoft.dj.aop.staticaop;
          2
          3public interface IHello {
          4    /** *//**
          5     * 假設這是一個業務方法
          6     * @param name
          7     */
          8    void sayHello(String name);
          9}
          10
          里面有個方法,用于輸入"Hello" 加傳進來的姓名;我們去寫個類實現IHello接口
          package sinosoft.dj.aop.staticaop;

          public class Hello implements IHello {

              public void sayHello(String name) {
                  System.out.println("Hello " + name);
              }

          }

          現在我們要為這個業務方法加上日志記錄的業務,我們在不改變原代碼的情況下,我們會去怎么做呢?也許,你會去寫一個類去實現IHello接口,并依賴Hello這個類.代碼如下:
          1package sinosoft.dj.aop.staticaop;
          2
          3public class HelloProxy implements IHello {
          4    private IHello hello;
          5
          6    public HelloProxy(IHello hello) {
          7        this.hello = hello;
          8    }
          9
          10    public void sayHello(String name) {
          11        Logger.logging(Level.DEBUGE, "sayHello method start.");
          12        hello.sayHello(name);
          13        Logger.logging(Level.INFO, "sayHello method end!");
          14
          15    }
          16
          17}
          18
          其中.Logger類和Level枚舉代碼如下:
          Logger.java
          1package sinosoft.dj.aop.staticaop;
          2
          3import java.util.Date;
          4
          5public class Logger{
          6    /** *//**
          7     * 根據等級記錄日志
          8     * @param level
          9     * @param context
          10     */
          11    public static void logging(Level level, String context) {
          12        if (level.equals(Level.INFO)) {
          13            System.out.println(new Date().toLocaleString() + " " + context);
          14        }
          15        if (level.equals(Level.DEBUGE)) {
          16            System.err.println(new Date() + " " + context);
          17        }
          18    }
          19
          20}
          21Level.java

          1package sinosoft.dj.aop.staticaop;
          2
          3public enum Level {
          4    INFO,DEBUGE;
          5}
          6那我們去寫個測試類看看,代碼如下:
          Test.java
          1package sinosoft.dj.aop.staticaop;
          2
          3public class Test {
          4    public static void main(String[] args) {
          5        IHello hello = new HelloProxy(new Hello());
          6        hello.sayHello("Doublej");
          7    }
          8}
          9運行以上代碼我們可以得到下面結果:

          Tue Mar 04 20:57:12 CST 2008 sayHello method start.
          Hello Doublej
          2008-3-4 20:57:12 sayHello method end!
          從上面的代碼我們可以看出,hello對象是被HelloProxy這個所謂的代理態所創建的.這樣,如果我們以后要把日志記錄的功能去掉.那我們只要把得到hello對象的代碼改成以下:
          1package sinosoft.dj.aop.staticaop;
          2
          3public class Test {
          4    public static void main(String[] args) {
          5        IHello hello = new Hello();
          6        hello.sayHello("Doublej");
          7    }
          8}
          9
          上面代碼,可以說是AOP最簡單的實現!
          但是我們會發現一個問題,如果我們像Hello這樣的類很多,那么,我們是不是要去寫很多個HelloProxy這樣的類呢.沒錯,是的.其實也 是一種很麻煩的事.在jdk1.3以后.jdk跟我們提供了一個API   java.lang.reflect.InvocationHandler的類. 這個類可以讓我們在JVM調用某個類的方法時動態的為些方法做些什么事.讓我們把以上的代碼改一下來看看效果.
          同樣,我們寫一個IHello的接口和一個Hello的實現類.在接口中.我們定義兩個方法;代碼如下 :

          IHello.java
          1package sinosoft.dj.aop.proxyaop;
          2
          3public interface IHello {
          4    /** *//**
          5     * 業務處理A方法
          6     * @param name
          7     */
          8    void sayHello(String name);
          9    /** *//**
          10     * 業務處理B方法
          11     * @param name
          12     */
          13    void sayGoogBye(String name);
          14}
          15

          Hello.java

          1package sinosoft.dj.aop.proxyaop;
          2
          3public class Hello implements IHello {
          4
          5    public void sayHello(String name) {
          6        System.out.println("Hello " + name);
          7    }
          8    public void sayGoogBye(String name) {
          9        System.out.println(name+" GoodBye!");
          10    }
          11}
          12
          我們一樣的去寫一個代理類.只不過.讓這個類去實現java.lang.reflect.InvocationHandler接口,代碼如下:
          1package sinosoft.dj.aop.proxyaop;
          2
          3import java.lang.reflect.InvocationHandler;
          4import java.lang.reflect.Method;
          5import java.lang.reflect.Proxy;
          6
          7public class DynaProxyHello implements InvocationHandler {
          8
          9    /** *//**
          10     * 要處理的對象(也就是我們要在方法的前后加上業務邏輯的對象,如例子中的Hello)
          11     */
          12    private Object delegate;
          13
          14    /** *//**
          15     * 動態生成方法被處理過后的對象 (寫法固定)
          16     *
          17     * @param delegate
          18     * @param proxy
          19     * @return
          20     */
          21    public Object bind(Object delegate) {
          22        this.delegate = delegate;
          23        return Proxy.newProxyInstance(
          24                this.delegate.getClass().getClassLoader(), this.delegate
          25                        .getClass().getInterfaces(), this);
          26    }
          27    /** *//**
          28     * 要處理的對象中的每個方法會被此方法送去JVM調用,也就是說,要處理的對象的方法只能通過此方法調用
          29     * 此方法是動態的,不是手動調用的
          30     */
          31    public Object invoke(Object proxy, Method method, Object[] args)
          32            throws Throwable {
          33        Object result = null;
          34        try {
          35            //執行原來的方法之前記錄日志
          36            Logger.logging(Level.DEBUGE, method.getName() + " Method end .");
          37           
          38            //JVM通過這條語句執行原來的方法(反射機制)
          39            result = method.invoke(this.delegate, args);
          40            //執行原來的方法之后記錄日志
          41            Logger.logging(Level.INFO, method.getName() + " Method Start!");
          42        } catch (Exception e) {
          43            e.printStackTrace();
          44        }
          45        //返回方法返回值給調用者
          46        return result;
          47    }
          48
          49}
          50
          上面類中出現的Logger類和Level枚舉還是和上一上例子的實現是一樣的.這里就不貼出代碼了.

          讓我們寫一個Test類去測試一下.代碼如下:
          Test.java
          1package sinosoft.dj.aop.proxyaop;
          2
          3public class Test {
          4    public static void main(String[] args) {
          5        IHello hello = (IHello)new DynaProxyHello().bind(new Hello());
          6        hello.sayGoogBye("Double J");
          7        hello.sayHello("Double J");
          8       
          9    }
          10}
          11
          運行輸出的結果如下:
          Tue Mar 04 21:24:03 CST 2008 sayGoogBye Method end .
          Double J GoodBye!
          2008-3-4 21:24:03 sayGoogBye Method Start!
          Tue Mar 04 21:24:03 CST 2008 sayHello Method end .
          Hello Double J
          2008-3-4 21:24:03 sayHello Method Start!
          由于線程的關系,第二個方法的開始出現在第一個方法的結束之前.這不是我們所關注的!
          從上面的例子我們看出.只要你是采用面向接口編程,那么,你的任何對象的方法執行之前要加上記錄日志的操作都是可以的.他 (DynaPoxyHello)自動去代理執行被代理對象(Hello)中的每一個方法,一個 java.lang.reflect.InvocationHandler接口就把我們的代理對象和被代理對象解藕了.但是,我們又發現還有一個問題,這 個DynaPoxyHello對象只能跟我們去在方法前后加上日志記錄的操作.我們能不能把DynaPoxyHello對象和日志操作對象 (Logger)解藕呢?
          結果是肯定的.讓我們來分析一下我們的需求.
          我們要在被代理對象的方法前面或者后面去加上日志操作代碼(或者是其它操作的代碼),
          那么,我們可以抽象出一個接口,這個接口里就只有兩個方法,一個是在被代理對象要執行方法之前執行的方法,我們取名為start,第二個方法就是在被代理對象執行方法之后執行的方法,我們取名為end .接口定義如下 :
          1package sinosoft.dj.aop.proxyaop;
          2
          3import java.lang.reflect.Method;
          4
          5public interface IOperation {
          6    /** *//**
          7     * 方法執行之前的操作
          8     * @param method
          9     */
          10    void start(Method method);
          11    /** *//**
          12     * 方法執行之后的操作
          13     * @param method
          14     */
          15    void end(Method method);
          16}
          17
          我們去寫一個實現上面接口的類.我們把作他真正的操作者,如下面是日志操作者的一個類:
          LoggerOperation.java
          package sinosoft.dj.aop.proxyaop;

          import java.lang.reflect.Method;

          public class LoggerOperation implements IOperation {

              public void end(Method method) {
                  Logger.logging(Level.DEBUGE, method.getName() + " Method end .");
              }

              public void start(Method method) {
                  Logger.logging(Level.INFO, method.getName() + " Method Start!");
              }

          }

          然后我們要改一下代理對象DynaProxyHello中的代碼.如下:
          1package sinosoft.dj.aop.proxyaop;
          2
          3import java.lang.reflect.InvocationHandler;
          4import java.lang.reflect.Method;
          5import java.lang.reflect.Proxy;
          6
          7public class DynaProxyHello implements InvocationHandler {
          8    /** *//**
          9     * 操作者
          10     */
          11    private Object proxy;
          12    /** *//**
          13     * 要處理的對象(也就是我們要在方法的前后加上業務邏輯的對象,如例子中的Hello)
          14     */
          15    private Object delegate;
          16
          17    /** *//**
          18     * 動態生成方法被處理過后的對象 (寫法固定)
          19     *
          20     * @param delegate
          21     * @param proxy
          22     * @return
          23     */
          24    public Object bind(Object delegate,Object proxy) {
          25       
          26        this.proxy = proxy;
          27        this.delegate = delegate;
          28        return Proxy.newProxyInstance(
          29                this.delegate.getClass().getClassLoader(), this.delegate
          30                        .getClass().getInterfaces(), this);
          31    }
          32    /** *//**
          33     * 要處理的對象中的每個方法會被此方法送去JVM調用,也就是說,要處理的對象的方法只能通過此方法調用
          34     * 此方法是動態的,不是手動調用的
          35     */
          36    public Object invoke(Object proxy, Method method, Object[] args)
          37            throws Throwable {
          38        Object result = null;
          39        try {
          40            //反射得到操作者的實例
          41            Class clazz = this.proxy.getClass();
          42            //反射得到操作者的Start方法
          43            Method start = clazz.getDeclaredMethod("start",
          44                    new Class[] { Method.class });
          45            //反射執行start方法
          46            start.invoke(this.proxy, new Object[] { method });
          47            //執行要處理對象的原本方法
          48            result = method.invoke(this.delegate, args);
          49//            反射得到操作者的end方法
          50            Method end = clazz.getDeclaredMethod("end",
          51                    new Class[] { Method.class });
          52//            反射執行end方法
          53            end.invoke(this.proxy, new Object[] { method });
          54
          55        } catch (Exception e) {
          56            e.printStackTrace();
          57        }
          58        return result;
          59    }
          60
          61}
          62
          然后我們把Test.java中的代碼改一下.測試一下:
          package sinosoft.dj.aop.proxyaop;

          public class Test {
              public static void main(String[] args) {
                  IHello hello = (IHello)new DynaProxyHello().bind(new Hello(),new LoggerOperation());
                  hello.sayGoogBye("Double J");
                  hello.sayHello("Double J");
                 
              }
          }
          結果還是一樣的吧.

          如果你想在每個方法之前加上日志記錄,而不在方法后加上日志記錄.你就把LoggerOperation類改成如下:
          1package sinosoft.dj.aop.proxyaop;
          2
          3import java.lang.reflect.Method;
          4
          5public class LoggerOperation implements IOperation {
          6
          7    public void end(Method method) {
          8        //Logger.logging(Level.DEBUGE, method.getName() + " Method end .");
          9    }
          10
          11    public void start(Method method) {
          12        Logger.logging(Level.INFO, method.getName() + " Method Start!");
          13    }
          14
          15}
          16
          運行一下.你就會發現,每個方法之后沒有記錄日志了. 這樣,我們就把代理者和操作者解藕了!

          下面留一個問題給大家,如果我們不想讓所有方法都被日志記錄,我們應該怎么去解藕呢.?
          我的想法是在代理對象的public Object invoke(Object proxy, Method method, Object[] args)方法里面加上個if(),對傳進來的method的名字進行判斷,判斷的條件存在XML里面.這樣我們就可以配置文件時行解藕了.如果有興趣的 朋友可以把操作者,被代理者,都通過配置文件進行配置 ,那么就可以寫一個簡單的SpringAOP框架了.

          posted @ 2011-05-10 17:49 哈希 閱讀(339) | 評論 (0)編輯 收藏

          首先來說一下rownum與rowid含義:

          顧名思義rownum就是行數/行號,而rowid就是編碼/編號/唯一識別號,所以他是類似“AAAR8gAAEAAAAErAAK”的編號,注意他是沒有先后順序的,也就是說他和數據入庫時間沒有任何關系,打個比方:他就像磁盤、內存存儲數據用的是16進制的地址一樣。

          他們都是偽列,可以理解成表中的一個列只是他們并不是你創建的。同樣是偽列區別是什么呢?

          rowid是你錄入數據時有數據庫自動為這條記錄添加的唯一的18位編號是一個物理編號用于找到這條記錄(順便說一句這也是為什么數據優調的時候強 調盡量使用rowid的原因),他是不會隨著查詢而改變的 除非在表發生移動(比如表空間變化,數據導入/導出以后),才會發生變化。

          rownum是根據sql查詢后得到的結果自動加上去的,但是他卻不受到sql中order by排序的影響,因為他和rowid的順序一樣是系統按照記錄插入時的順序給記錄排的號(順序的、無跳躍)。 但是如果你想讓rownum和order by一樣的順序 那么可以使用子查詢,形如:select rownum,t.* from (select * from 表空間名 order by 字段名) t  這樣的話rownum就是根據該字段進行排序的編號了,為什么會這樣呢,本人理解:rownum是根據表記錄輸出的行號,與篩選語句、排序語句都無關所以 當用子查詢時等于生成了一個表于是就按照這張表從1開始排序了。 同樣,也可以用下面要提得到的分析函數中的row_number() over(order by 需要排序的字段名)。

            

          值得一提的是MSSQL是沒有rownum和rowid的。

          下面說說分析函數row_number()、rank()、dense_rank()

          ROW_NUMBER():
          Row_number函數返回一個唯一的值,當碰到相同數據時,排名按照記錄集中記錄的順序依次遞增。 row_number()和rownum差不多,功能更強一點(可以在各個分組內從1開時排序),因為row_number()是分析函數而rownum是偽列所以row_number()一定要over而rownum不能over。

          RANK():
          Rank函數返回一個唯一的值,除非遇到相同的數據,此時所有相同數據的排名是一樣的,同時會在最后一條相同記錄和下一條不同記錄的排名之間空出排名。rank()是跳躍排序,有兩個第二名時接下來就是第四名(同樣是在各個分組內)。

          DENSE_RANK():
          Dense_rank函數返回一個唯一的值,除非當碰到相同數據,此時所有相同數據的排名都是一樣的。
          dense_rank()是連續排序,有兩個第二名時仍然跟著第三名。他和row_number的區別在于row_number是沒有重復值的。

          一,什么是偽列RowID?

          1,首先是一種數據類型,唯一標識一條記錄物理位置的一個id,基于64位編碼的18個字符顯示。

          2,未存儲在表中,可以從表中查詢,但不支持插入,更新,刪除它們的值。

          二,RowID的用途

          1,在開發中使用頻率應該是挺多的,特別在一些update語句中使用更加頻繁。所以oracle ERP中大部份的視圖都會加入rowid這個字段。

             在一些cursor定義時也少不了加入rowid。但往往我們在開發過程中,由于連接的表很多,再加上程序的復制,有時忽略了rowid對應的是那一個表中rowid,所以有時過程出錯,

             往往發上很多時間去查錯,最后查出來既然是update時帶的rowid并非此表的rowid,所以在發現很多次的錯誤時,重視rowid起來了,開發中一定要注意rowid的匹配

          2,能以做快的方式訪問表中的一行。

          3,能顯示表的行是如何存儲的。

          4,作為表中唯一標識。

          三,RowID的組成

          rowid確定了每條記錄是在Oracle中的哪一個數據對象,數據文件、塊、行上。

          ROWID 的格式如下:

             數據對象編號        文件編號        塊編號            行編號

             OOOOOO             FFF                BBBBBB    RRR

             由 data_object_id# + rfile# + block# + row#   組成,占用10個bytes的空間,

              32bit的 data_object_id#,

              10 bit 的 rfile#,

              22bit 的 block#,

              16 bit 的 row#.

             所以每個表空間不能超過1023個 數據文件。

          四,RowID的應用

          1,查找和刪除重復記錄

             當試圖對庫表中的某一列或幾列創建唯一索引時,

             系統提示 ORA-01452 :不能創建唯一索引,發現重復記錄。

              /*conn scott/tiger

              Create table empa as select * from emp;

              插入重復記錄

              insert into empa select * from emp where empno = 7369;

              insert into empa select * from emp where empno = 7839;

              insert into empa select * from emp where empno = 7934;

              */

             查找重復記錄的幾種方法:

              查找大量重復記錄

              select empno from empa group by empno having count(*) >1;

              Select * From empa Where ROWID Not In(Select Min(ROWID) From empa Group By empno);

              查找少量重復記錄

              select * from empa a where rowid<>(select max(rowid) from empa where empno=a.empno );

             刪除重復記錄的幾種方法:

              (1).適用于有大量重復記錄的情況(列上建有索引的時候,用以下語句效率會很高):

              Delete empa Where empno In (Select empno From empa Group By empno Having Count(*) > 1)

              And ROWID Not In (Select Min(ROWID) From empa Group By empno Having Count(*) > 1);

            

              Delete empa Where ROWID Not In(Select Min(ROWID) From empa Group By empno);

            

              (2).適用于有少量重復記錄的情況(注意,對于有大量重復記錄的情況,用以下語句效率會很低):

              Delete empa a where rowid<>(select max(rowid) from empa where empno=a.empno );

          ---------------------------------------------------------------------------------------------------------------------------------------------------

          注意:rownum從1開始;

                     rownum按照記錄插入時的順序給記錄排序,所以有order by的子句時一定要注意?。?/p>

                     使用時rownum,order by字段是否為主鍵有什么影響?

                     子查詢中rownum rn,而rn用到外查詢中到底是怎樣的序列?

                      若id主鍵是按照從小到大的順序插入的,select語句沒有group by 和order by的子句時,rownum的順序和id順序基本一致。

          對于 Oracle 的 rownum 問題,很多資料都說不支持>,>=,=,between...and,只能用以上符號(<、<=、!=),并非說用>,& gt;=,=,between..and 時會提示SQL語法錯誤,而是經常是查不出一條記錄來,還會出現似乎是莫名其妙的結果來,其實您只要理解好了這個 rownum 偽列的意義就不應該感到驚奇,同樣是偽列,rownum 與 rowid 可有些不一樣,下面以例子說明

          假設某個表 t1(c1) 有 20 條記錄

          如果用 select rownum,c1 from t1 where rownum < 10, 只要是用小于號,查出來的結果很容易地與一般理解在概念上能達成一致,應該不會有任何疑問的。

          可如果用 select rownum,c1 from t1 where rownum > 10 (如果寫下這樣的查詢語句,這時候在您的頭腦中應該是想得到表中后面10條記錄),你就會發現,顯示出來的結果要讓您失望了,也許您還會懷疑是不誰刪了一 些記錄,然后查看記錄數,仍然是 20 條啊?那問題是出在哪呢?

          先好好理解 rownum 的意義吧。因為ROWNUM是對結果集加的一個偽列,即先查到結果集之后再加上去的一個列 (強調:先要有結果集)。簡單的說 rownum 是對符合條件結果的序列號。它總是從1開始排起的。所以你選出的結果不可能沒有1,而有其他大于1的值。所以您沒辦法期望得到下面的結果集:

          11 aaaaaaaa

          12 bbbbbbb

          13 ccccccc

          .................

          rownum >10 沒有記錄,因為第一條不滿足去掉的話,第二條的ROWNUM又成了1,所以永遠沒有滿足條件的記錄。或者可以這樣理解:

          ROWNUM是一個序列,是oracle數據庫從數據文件或緩沖區中讀取數據的順序。它取得第 一條記錄則rownum值為1,第二條為2,依次類推。如果你用>,>=,=,between...and這些條件,因為從緩沖區或數據文件 中得到的第一條記錄的rownum為1,則被刪除,接著取下條,可是它的rownum還是1,又被刪除,依次類推,便沒有了數據。

          有了以上從不同方面建立起來的對 rownum 的概念,那我們可以來認識使用 rownum 的幾種現像

          1. select rownum,c1 from t1 where rownum != 10 為何是返回前9條數據呢?它與 select rownum,c1 from tablename where rownum < 10 返回的結果集是一樣的呢?

                因為是在查詢到結果集后,顯示完第 9 條記錄后,之后的記錄也都是 != 10,或者 >=10,所以只顯示前面9條記錄。也可以這樣理解,rownum 為9后的記錄的 rownum為10,因條件為 !=10,所以去掉,其后記錄補上,rownum又是10,也去掉,如果下去也就只會顯示前面9條記錄了。

          2. 為什么 rownum >1 時查不到一條記錄,而 rownum >0 或 rownum >=1 卻總顯示所有的記錄?

                因為 rownum 是在查詢到的結果集后加上去的,它總是從1開始。

          3. 為什么 between 1 and 10 或者 between 0 and 10 能查到結果,而用 between 2 and 10 卻得不到結果?

                 原因同上一樣,因為 rownum 總是從 1 開始。從上可以看出,任何時候想把 rownum = 1 這條記錄拋棄是不對的,它在結果集中是不可或缺的,少了rownum=1 就像空中樓閣一般不能存在,所以你的 rownum 條件要包含到 1 。

          但如果就是想要用 rownum > 10 這種條件的話話就要用嵌套語句,把 rownum 先生成,然后對他進行查詢。

          select *

          from (selet rownum as rn,t1.* from a where ...)

          where rn >10

          一般代碼中對結果集進行分頁就是這么干的。

          另外:rowid 與 rownum 雖都被稱為偽列,但它們的存在方式是不一樣的,rowid 可以說是物理存在的,表示記錄在表空間中的唯一位置ID,在DB中唯一。只要記錄沒被搬動過,rowid是不變的。rowid 相對于表來說又像表中的一般列,所以以 rowid 為條件就不會有 rownum那些情況發生。

          另外還要注意:rownum不能以任何基表的名稱作為前綴。

          對于rownum來說它是oracle系統順序分配為從查詢返回的行的編號,返回的第一行分配的是1,第二行是2,依此類推,這個偽字段可以用于限制查詢返回的總行數,且rownum不能以任何表的名稱作為前綴。

          (1) rownum 對于等于某值的查詢條件

          如果希望找到學生表中第一條學生的信息,可以使用rownum=1作為條件。但是想找到學生表 中第二條學生的信息,使用rownum=2結果查不到數據。因為rownum都是從1開始,但是1以上的自然數在rownum做等于判斷是時認為都是 false條件,所以無法查到rownum = n(n>1的自然數)。

          SQL> select rownum,id,name from student where rownum=1;(可以用在限制返回記錄條數的地方,保證不出錯,如:隱式游標)

          SQL> select rownum,id,name from student where rownum =2;

              ROWNUM ID     NAME

          (2)rownum對于大于某值的查詢條件

             如果想找到從第二行記錄以后的記錄,當使用rownum>2是查不出記錄的,原因是由于rownum是一個總是從1開始的偽列,Oracle 認為rownum> n(n>1的自然數)這種條件依舊不成立,所以查不到記錄。

          查找到第二行以后的記錄可使用以下的子查詢方法來解決。注意子查詢中的rownum必須要有別名,否則還是不會查出記錄來,這是因為rownum不是某個表的列,如果不起別名的話,無法知道rownum是子查詢的列還是主查詢的列。

          SQL>select * from(select rownum no ,id,name from student) where no>2;

                  NO ID     NAME

          ---------- ------ ---------------------------------------------------

                   3 200003 李三

                   4 200004 趙四

          (3)rownum對于小于某值的查詢條件

          rownum對于rownum<n((n>1的自然數)的條件認為是成立的,所以可以找到記錄。

          SQL> select rownum,id,name from student where rownum <3;

              ROWNUM ID     NAME

          ---------- ------ ---------------------------------------------------

                  1 200001 張一

                  2 200002 王二

          查詢rownum在某區間的數據,必須使用子查詢。例如要查詢rownum在第二行到第三行之 間的數據,包括第二行和第三行數據,那么我們只能寫以下語句,先讓它返回小于等于三的記錄行,然后在主查詢中判斷新的rownum的別名列大于等于二的記 錄行。但是這樣的操作會在大數據集中影響速度。

          SQL> select * from (select rownum no,id,name from student where rownum<=3 ) where no >=2;

                  NO ID     NAME

          ---------- ------ ---------------------------------------------------

                   2 200002 王二

                   3 200003 李三

          (4)rownum和排序  

          Oracle中的rownum的是在取數據的時候產生的序號,所以想對指定排序的數據去指定的rowmun行數據就必須注意了。

          SQL> select rownum ,id,name from student order by name;

              ROWNUM ID     NAME

          ---------- ------ ---------------------------------------------------

                   3 200003 李三

                   2 200002 王二

                   1 200001 張一

                   4 200004 趙四

          可以看出,rownum并不是按照name列來生成的序號。系統是按照記錄插入時的順序給記錄排的號,rowid也是順序分配的。為了解決這個問題,必須使用子查詢;

          SQL> select rownum ,id,name from (select * from student order by name);

              ROWNUM ID     NAME

          ---------- ------ ---------------------------------------------------

                   1 200003 李三

                   2 200002 王二

                   3 200001 張一

                   4 200004 趙四

          這樣就成了按name排序,并且用rownum標出正確序號(有小到大)

          筆者在工作中有一上百萬條記錄的表,在jsp頁面中需對該表進行分頁顯示,便考慮用rownum來作,下面是具體方法(每頁顯示20條):

          “select * from tabname where rownum<20 order by name" 但卻發現oracle卻不能按自己的意愿來執行,而是先隨便取20條記錄,然后再order by,后經咨詢oracle,說rownum確實就這樣,想用的話,只能用子查詢來實現先排序,后rownum,方法如下:

          "select * from (select * from tabname order by name) where rownum<20",但這樣一來,效率會低很多。

          后經筆者試驗,只需在order by 的字段上加主鍵或索引即可讓oracle先按該字段排序,然后再rownum;方法不變:    “select * from tabname where rownum<20 order by name"

          取得某列中第N大的行

          select column_name from

          (select table_name.*,dense_rank() over (order by column desc) rank from table_name)

          where rank = &N;

          假如要返回前5條記錄:

          select * from tablename where rownum<6;(或是rownum <= 5 或是rownum != 6)

          假如要返回第5-9條記錄:

          select * from tablename

          where …

          and rownum<10

          minus

          select * from tablename

          where …

          and rownum<5

          order by name

          選出結果后用name排序顯示結果。(先選再排序)

          注意:只能用以上符號(<、<=、!=)。

          select * from tablename where rownum != 10;返回的是前9條記錄。

          不能用:>,>=,=,Between...and。由于rownum是一個總是從1開始的偽列,Oracle 認為這種條件不成立。

          另外,這個方法更快:

          select * from (

          select rownum r,a from yourtable

          where rownum <= 20

          order by name )

          where r > 10

          這樣取出第11-20條記錄!(先選再排序再選)

          要先排序再選則須用select嵌套:內層排序外層選。

          rownum是隨著結果集生成的,一旦生成,就不會變化了;同時,生成的結果是依次遞加的,沒有1就永遠不會有2!

          rownum 是在查詢集合產生的過程中產生的偽列,并且如果where條件中存在 rownum 條件的話,則:

          1: 假如判定條件是常量,則:

          只能 rownum = 1, <= 大于1 的自然數, = 大于1 的數是沒有結果的;大于一個數也是沒有結果的

          即 當出現一個 rownum 不滿足條件的時候則 查詢結束 this is stop key(一個不滿足,系統將該記錄過濾掉,則下一條記錄的rownum還是這個,所以后面的就不再有滿足記錄,this is stop key);

          2: 假如判定值不是常量,則:

          若條件是 = var , 則只有當 var 為1 的時候才滿足條件,這個時候不存在 stop key ,必須進行full scan ,對每個滿足其他where條件的數據進行判定,選出一行后才能去選rownum=2的行……

          以下摘自《中國IT實驗室》

          1.在oracle中實現select top n

             由于oracle不支持select top語句,所以在oracle中經常是用order by跟rownum的組合來實現select top n的查詢。

          簡單地說,實現方法如下所示:

          select 列名1...列名n from   

          (select 列名1...列名n from 表名 order by 列名1...列名n)

          where rownum<=n(抽出記錄數)

          order by rownum asc

             下面舉個例子簡單說明一下。

          顧客表customer(id,name)有如下數據:

          ID NAME

             01 first

             02 Second

             03 third

             04 forth

             05 fifth

             06 sixth

             07 seventh

             08 eighth

             09 ninth

             10 last

             則按NAME的字母順抽出前三個顧客的SQL語句如下所示:

          select * from

             (select * from customer order by name)

             where rownum<=3

             order by rownum asc

             輸出結果為:

             ID NAME

             08 eighth

             05 fifth

             01 first

          posted @ 2011-05-10 17:32 哈希 閱讀(472) | 評論 (0)編輯 收藏

          一、String,StringBuffer, StringBuilder 的區別是什么?String為什么是不可變的?
          二、VECTOR,ARRAYLIST, LINKEDLIST的區別是什么?
          三、HASHTABLE, HASGMAQ,TreeMap區別
          四、ConcurrentMap和HashMap的區別
          五、Tomcat,apache,jboss的區別
          六、GET POST區別
          七、SESSION, COOKIE區別
          八、Servlet的生命周期
          九、HTTP 報文包含內容
          十、Statement與PreparedStatement的區別,什么是SQL注入,如何防止SQL注入
          十一、redirect, foward區別
          十二、關于JAVA內存模型,一個對象(兩個屬性,四個方法)實例化100次,現在內存中的存儲狀態,
          幾個對象,幾個屬性,幾個方法。
          十三、談談Hibernate的理解,一級和二級緩存的作用,在項目中Hibernate都是怎么使用緩存的
          十四、反射講一講,主要是概念,都在哪需要反射機制,反射的性能,如何優化
          十五、談談Hibernate與Ibatis的區別,哪個性能會更高一些
          十六、對Spring的理解,項目中都用什么?怎么用的?對IOC、和AOP的理解及實現原理
          十七、線程同步,并發操作怎么控制
          十八、描述struts的工作流程。
          十九、Tomcat的session處理,如果讓你實現一個tomcatserver,如何實現session機制
          二十、關于Cache(Ehcache,Memcached)
          二一、sql的優化相關問題
          二二、oracle中 rownum與rowid的理解,一千條記錄我查200到300的記錄怎么查?
          二三、如何分析ORACLE的執行計劃?
          二四、 DB中索引原理,種類,使用索引的好處和問題是什么?
          二五、JVM垃圾回收實現原理。垃圾回收的線程優先級。
          二六、jvm 最大內存設置。設置的原理。結合垃圾回收講講。


          1、了解j2EE規范,選擇幾點進行重點消化。
          2、異常分類,一般性異常和運行期異常,異常捕獲。
          3、了解spring mvc框架,和struts mvc框架的區別。
          4、要對spring和ibatis非常熟悉,必須,熟知。
          5、應適當關注需求分析和產品方面的知識。
          6、了解多線程相關知識
          7、了解java5以及java6新特性
          8、熟悉linux相關命令操作。
          9、工廠模式,簡單工廠、抽象工廠的區別
          10、動態代理模式
          11、

          一、String,StringBuffer, StringBuilder 的區別是什么?String為什么是不可變的?
          二、VECTOR,ARRAYLIST, LINKEDLIST的區別是什么?
          三、HASHTABLE, HASGMAQ,TreeMap區別
          四、ConcurrentMap和HashMap的區別
          五、Tomcat,apache,jboss的區別
          六、GET POST區別
          七、SESSION, COOKIE區別
          八、Servlet的生命周期
          九、HTTP 報文包含內容
          十、Statement與PreparedStatement的區別,什么是SQL注入,如何防止SQL注入
          十一、redirect, foward區別
          十二、關于JAVA內存模型,一個對象(兩個屬性,四個方法)實例化100次,現在內存中的存儲狀態,
          幾個對象,幾個屬性,幾個方法。
          十三、談談Hibernate的理解,一級和二級緩存的作用,在項目中Hibernate都是怎么使用緩存的
          十四、反射講一講,主要是概念,都在哪需要反射機制,反射的性能,如何優化
          十五、談談Hibernate與Ibatis的區別,哪個性能會更高一些
          十六、對Spring的理解,項目中都用什么?怎么用的?對IOC、和AOP的理解及實現原理
          十七、線程同步,并發操作怎么控制
          十八、描述struts的工作流程。
          十九、Tomcat的session處理,如果讓你實現一個tomcatserver,如何實現session機制
          二十、關于Cache(Ehcache,Memcached)
          二一、sql的優化相關問題
          二二、oracle中 rownum與rowid的理解,一千條記錄我查200到300的記錄怎么查?
          二三、如何分析ORACLE的執行計劃?
          二四、 DB中索引原理,種類,使用索引的好處和問題是什么?
          二五、JVM垃圾回收實現原理。垃圾回收的線程優先級。
          二六、jvm 最大內存設置。設置的原理。結合垃圾回收講講。


          廣州java開發工程師,昨天下午1,2面,今天3,4面,感覺效率挺高的,就等通知了
          簡單說一下流程吧
            1面,一個挺帥氣的面試官,不斷地問一個算法題,一個基礎知識問題,一個項目問題,循環地進行,
          一共5,6輪吧,中間還問了一題情景題,大概一個小時,算法題不難,比如找出亂序數組中的相同元素,整數求二進制的1的個數等,
          感覺考的是你寫程序的習慣和思維是否周密,基礎題就是jdk,gc,jvm之類的問題,考的很細。最后的問題是內存里一個hashmap
          和一個文本里的內容同步的實現方法,當時答不上來,面試就結束了,后來回學校才想到一個方法。
            2面,兩個男的面試官輪流問我問題,同樣是問技術的,spring里一些核心原理,jdk1.5的新類庫,分布式系統,數據庫,linux(這個不懂...)等等,
          感覺是車輪戰,看你的知識廣度和反應力....
            3面, 產品經理的面試,更多的是針對我項目里的問題提問,會問深入的問題,比如spring的aop是如何用java實現的....
            4面,hr面,比較輕松吧,拉拉家常,隨便談談,問問我的西裝,身高之類的

          感覺我自己盡力了,會的都答上,現在就看淘寶發不發offer給我了,后來還去了阿里巴巴b2b面試,考的內容基本差不多,而且更注重你是如何學習的
          一直覺得java的面經很少,希望這可以幫到大家

          posted @ 2011-05-10 17:31 哈希 閱讀(4090) | 評論 (0)編輯 收藏

          1.觸發器的作用?
           答:觸發器是一中特殊的存儲過程,主要是通過事件來觸發而被執行的。它可以強化約束,來維護數據的完整性和一致性,可以跟蹤數據庫內的操作從而不允許未經許可的更新和變化。可以聯級運算。如,某表上的觸發器上包含對另一個表的數據操作,而該操作又會導致該表觸發器被觸發。
          2。什么是存儲過程?用什么來調用?
          答:存儲過程是一個預編譯的SQL語句,優點是允許模塊化的設計,就是說只需創建一次,以后在該程序中就可以調用多次。如果某次操作需要執行多次SQL,使用存儲過程比單純SQL語句執行要快。可以用一個命令對象來調用存儲過程。
          3。索引的作用?和它的優點缺點是什么?
          答:索引就一種特殊的查詢表,數據庫的搜索引擎可以利用它加速對數據的檢索。它很類似與現實生活中書的目錄,不需要查詢整本書內容就可以找到想要的數據。索引可以是唯一的,創建索引允許指定單個列或者是多個列。缺點是它減慢了數據錄入的速度,同時也增加了數據庫的尺寸大小。
          3。什么是內存泄漏?
          答:一般我們所說的內存泄漏指的是堆內存的泄漏。堆內存是程序從堆中為其分配的,大小任意的,使用完后要顯示釋放內存。當應用程序用關鍵字new等創建對象時,就從堆中為它分配一塊內存,使用完后程序調用free或者delete釋放該內存,否則就說該內存就不能被使用,我們就說該內存被泄漏了。
          4。維護數據庫的完整性和一致性,你喜歡用觸發器還是自寫業務邏輯?為什么?
          答:我是這樣做的,盡可能使用約束,如check,主鍵,外鍵,非空字段等來約束,這樣做效率最高,也最方便。其次是使用觸發器,這種方法可以保證,無論什么業務系統訪問數據庫都可以保證數據的完整新和一致性。最后考慮的是自寫業務邏輯,但這樣做麻煩,編程復雜,效率低下。
          5。什么是事務?什么是鎖?
          答:事務就是被綁定在一起作為一個邏輯工作單元的SQL語句分組,如果任何一個語句操作失敗那么整個操作就被失敗,以后操作就會回滾到操作前狀態,或者是上有個節點。為了確保要么執行,要么不執行,就可以使用事務。要將有組語句作為事務考慮,就需要通過ACID測試,即原子性,一致性,隔離性和持久性。
           鎖:在所以的DBMS中,鎖是實現事務的關鍵,鎖可以保證事務的完整性和并發性。與現實生活中鎖一樣,它可以使某些數據的擁有者,在某段時間內不能使用某些數據或數據結構。當然鎖還分級別的。
          6。什么叫視圖?游標是什么?
          答:視圖是一種虛擬的表,具有和物理表相同的功能??梢詫σ晥D進行增,改,查,操作,試圖通常是有一個表或者多個表的行或列的子集。對視圖的修改不影響基本表。它使得我們獲取數據更容易,相比多表查詢。
           游標:是對查詢出來的結果集作為一個單元來有效的處理。游標可以定在該單元中的特定行,從結果集的當前行檢索一行或多行。可以對結果集當前行做修改。一般不使用游標,但是需要逐條處理數據的時候,游標顯得十分重要。
          7。為管理業務培訓信息,建立3個表:

              S(S#,SN,SD,SA)S#,SN,SD,SA分別代表學號,學員姓名,所屬單位,學員年齡

              C(C#,CN)C#,CN分別代表課程編號,課程名稱

               SC(S#,C#,G) S#,C#,G分別代表學號,所選的課程編號,學習成績

             (1)使用標準SQL嵌套語句查詢選修課程名稱為’稅收基礎’的學員學號和姓名?

                   答案:select s# ,sn from s where S# in(select S# from c,sc where c.c#=sc.c# and cn=’稅收基礎’)

               (2) 使用標準SQL嵌套語句查詢選修課程編號為’C2’的學員姓名和所屬單位?

          答:select sn,sd from s,sc where s.s#=sc.s# and sc.c#=’c2’

               (3) 使用標準SQL嵌套語句查詢不選修課程編號為’C5’的學員姓名和所屬單位?

          答:select sn,sd from s where s# not in(select s# from sc where c#=’c5’)

                (4)查詢選修了課程的學員人數

          答:select 學員人數=count(distinct s#) from sc

                (5) 查詢選修課程超過5門的學員學號和所屬單位?

          答:select sn,sd from s where s# in(select s# from sc group by s# having count(distinct c#)>5)


          posted @ 2011-05-08 08:28 哈希 閱讀(229) | 評論 (0)編輯 收藏

          僅列出標題
          共11頁: First 上一頁 2 3 4 5 6 7 8 9 10 下一頁 Last 
          主站蜘蛛池模板: 宝清县| 哈巴河县| 卢氏县| 冕宁县| 即墨市| 叙永县| 公主岭市| 阳江市| 潜山县| 香格里拉县| 唐河县| 达州市| 蓬溪县| 水城县| 济源市| 凤冈县| 卓尼县| 类乌齐县| 井陉县| 疏勒县| 泰安市| 营口市| 平谷区| 上思县| 磴口县| 铜梁县| 临西县| 永福县| 平谷区| 河源市| 库车县| 丹东市| 宁津县| 错那县| 鄂托克前旗| 黄梅县| 抚州市| 防城港市| 绵阳市| 云安县| 汝阳县|