如何学好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 哈希 阅读(171) | 评论 (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 哈希 阅读(311) | 评论 (0)编辑 收藏

     摘要: Eclipse快速上手Hibernate--1. 入门实例 < language="javascript" type="text/javascript">document.title="Eclipse快速上手Hibernate--1. 入门实例 - "+document.title     这篇文章主要谈谈Hibernate的入门开发,例子很简单,就是...  阅读全文

posted @ 2011-05-20 15:30 哈希 阅读(156) | 评论 (0)编辑 收藏

     摘要: 这篇文章将教你快速地上手使用 Spring 框架. 如果你手上有一本《Spring in Action》, 那么你最好从第三部分"Spring 在 Web 层的应用--建立 Web 层"开始看, 否则那将是一场恶梦! 首先, 我需要在你心里建立起 Spring MVC 的基本概念. 基于 Spring 的 Web 应用程序接收到 http://localhost:8080/...  阅读全文

posted @ 2011-05-17 22:23 哈希 阅读(244) | 评论 (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 哈希 阅读(169) | 评论 (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 哈希 阅读(190) | 评论 (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 哈希 阅读(336) | 评论 (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的子句时一定要注意啊!

           使用时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 哈希 阅读(459) | 评论 (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 哈希 阅读(4085) | 评论 (0)编辑 收藏

1.触发器的作用?
 答:触发器是一中特殊的存储过程,主要是通过事件来触发而被执行的。它可以强化约束,来维护数据的完整性和一致性,可以跟踪数据库内的操作从而不允许未经许可的更新和变化。可以联级运算。如,某表上的触发器上包含对另一个表的数据操作,而该操作又会导致该表触发器被触发。
2。什么是存储过程?用什么来调用?
答:存储过程是一个预编译的SQL语句,优点是允许模块化的设计,就是说只需创建一次,以后在该程序中就可以调用多次。如果某次操作需要执行多次SQL,使用存储过程比单纯SQL语句执行要快。可以用一个命令对象来调用存储过程。
3。索引的作用?和它的优点缺点是什么?
答:索引就一种特殊的查询表,数据库的搜索引擎可以利用它加速对数据的检索。它很类似与现实生活中书的目录,不需要查询整本书内容就可以找到想要的数据。索引可以是唯一的,创建索引允许指定单个列或者是多个列。缺点是它减慢了数据录入的速度,同时也增加了数据库的尺寸大小。
3。什么是内存泄漏?
答:一般我们所说的内存泄漏指的是堆内存的泄漏。堆内存是程序从堆中为其分配的,大小任意的,使用完后要显示释放内存。当应用程序用关键字new等创建对象时,就从堆中为它分配一块内存,使用完后程序调用free或者delete释放该内存,否则就说该内存就不能被使用,我们就说该内存被泄漏了。
4。维护数据库的完整性和一致性,你喜欢用触发器还是自写业务逻辑?为什么?
答:我是这样做的,尽可能使用约束,如check,主键,外键,非空字段等来约束,这样做效率最高,也最方便。其次是使用触发器,这种方法可以保证,无论什么业务系统访问数据库都可以保证数据的完整新和一致性。最后考虑的是自写业务逻辑,但这样做麻烦,编程复杂,效率低下。
5。什么是事务?什么是锁?
答:事务就是被绑定在一起作为一个逻辑工作单元的SQL语句分组,如果任何一个语句操作失败那么整个操作就被失败,以后操作就会回滚到操作前状态,或者是上有个节点。为了确保要么执行,要么不执行,就可以使用事务。要将有组语句作为事务考虑,就需要通过ACID测试,即原子性,一致性,隔离性和持久性。
 锁:在所以的DBMS中,锁是实现事务的关键,锁可以保证事务的完整性和并发性。与现实生活中锁一样,它可以使某些数据的拥有者,在某段时间内不能使用某些数据或数据结构。当然锁还分级别的。
6。什么叫视图?游标是什么?
答:视图是一种虚拟的表,具有和物理表相同的功能。可以对视图进行增,改,查,操作,试图通常是有一个表或者多个表的行或列的子集。对视图的修改不影响基本表。它使得我们获取数据更容易,相比多表查询。
 游标:是对查询出来的结果集作为一个单元来有效的处理。游标可以定在该单元中的特定行,从结果集的当前行检索一行或多行。可以对结果集当前行做修改。一般不使用游标,但是需要逐条处理数据的时候,游标显得十分重要。
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 哈希 阅读(224) | 评论 (0)编辑 收藏

仅列出标题
共11页: First 上一页 2 3 4 5 6 7 8 9 10 下一页 Last