随笔:93 文章:11 评论:22 引用:0
首页 发新随笔
发新文章 联系 聚合管理

在Oracle中,要按特定条件查询前N条记录,用个rownum就搞定了。
select * from emp where rownum <= 5
结果只查询5条记录, oracle会自动展现一个rownum的属性表示记录排序号

而select * from emp where rownum > 5 ;则是失败的。
因为:rownum是oracle预处理字段,默认标序是1,只有记录集已经满足条件后才会进行后续编号。由于第一条记录rownum默认是1,而你的条件是rownum>=6 对第一条记录比较它的rownum肯定不大于6 所以不满足条件 oracle舍弃第一条记录将数据库第二条记录标序为1再进行比较  肯定都不满足rownum>=6  这样循环也就是说由于没有记录满足rownum>=6所以记录一直被舍弃,rownum一直是1 。

解决方案: 利用查询时,自动生成的rownum属性.
排序方法:
  select * from (
       select a1.*, rownum rwn  from emp a1   where rownum <=10
    ) where rwn >= 6;
  或者
  select * from (
    select qx.*,row_number() over(order by qx.empno) rwn from emp qx
  ) where rwn between 6 and 10
-------------------------------------------------------------------------
使用注意:

1排序导致数据重复:


table1中表有字段(其余字段省)
ID  主键
DATA_UPDATE_TIME 数据更新时间(只存储了年月日)

分页查询的语句如下
select *
   from (
        select row_.*, rownum rownum_
           from ( select  p.id from table1 p
             order by  p.DATA_UPDATE_TIME desc )
   row_ where rownum <= )
where rownum_ >

以每页显示10条为例
第一次  rownum <= 10)   where rownum_ > 0
第二次  rownum <= 20)   where rownum_ > 10

发现有一条记录在两次查询结果中重复出现,不知道问题出在哪里,请忙帮看看。

另:
DATA_UPDATE_TIME 的值有重复,不知道跟它有没有关系。
如果按ID排的话就不会出现这个问题


解答:
如果order by 不能唯一确定记录的顺序就会出现这个问题。
解决的方法是把分页部分全部拿到最外层进行。

Java代码 复制代码 收藏代码
  1. select * from (    
  2.   select row_.*, rownum rownum_    
  3.   from (   
  4.     select p.id from table1 p    
  5.     order by p.DATA_UPDATE_TIME desc    
  6.   ) row_   
  7. )    
  8. where rownum_ > ? and rownum_ <= ?   

2 排序的id顺序:
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标出正确序号(有小到大)


------------
参考Oracle的rownum原理和使用  http://tenn.iteye.com/blog/99339

在Oracle中,要按特定条件查询前N条记录,用个rownum就搞定了。
select * from emp where rownum <= 5
而且书上也告诫,不能对rownum用">",这也就意味着,如果你想用
select * from emp where rownum > 5
则是失败的。要知道为什么会失败,则需要了解rownum背后的机制:
1 Oracle executes your query.

2 Oracle fetches the first row and calls it row number 1.

3 Have we gotten past row number meets the criteria? If no, then Oracle discards the row, If yes, then Oracle return the row.

4 Oracle fetches the next row and advances the row number (to 2, and then to 3, and then to 4, and so forth).

5 Go to step 3.

了解了原理,就知道rownum>不会成功,因为在第三步的时候查询出的行已经被丢弃,第四步查出来的rownum仍然是1,这样永远也不会成功。

同样道理,rownum如果单独用=,也只有在rownum=1时才有用。

 

对于rownum来说它是oracle系统顺序分配为从查询返回的行的编号,返回的第一行分配的是1,第二行是2,依此类推,这个伪字段可以用于限制查询返回的总行数,而且rownum不能以任何表的名称作为前缀。
 举例说明:
例如表:student(学生)表,表结构为:
ID       char(6)      --学号
name    VARCHAR2(10)   --姓名
create table student (ID char(6), name VARCHAR2(100));
insert into sale values('200001',‘张一’);
insert into sale values('200002',‘王二’);
insert into sale values('200003',‘李三’);
insert into sale values('200004',‘赵四’);
commit;
(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=1;
    ROWNUM ID     NAME
---------- ------ ---------------------------------------------------
         1 200001 张一
SQL> select rownum,id,name from student where rownum =2;
    ROWNUM ID     NAME
---------- ------ ---------------------------------------------------
(2)rownum对于大于某值的查询条件
   如果想找到从第二行记录以后的记录,当使用rownum>2是查不出记录的,原因是由于rownum是一个总是从1开始的伪列,Oracle 认为rownum> n(n>1的自然数)这种条件依旧不成立,所以查不到记录
SQL> select rownum,id,name from student where rownum >2;
ROWNUM ID     NAME
---------- ------ ---------------------------------------------------
那如何才能找到第二行以后的记录呀。可以使用以下的子查询方法来解决。注意子查询中的rownum必须要有别名,否则还是不会查出记录来,这是因为rownum不是某个表的列,如果不起别名的话,无法知道rownum是子查询的列还是主查询的列。
SQL>select * from(select rownum no ,id,name from student) where no>2;
        NO ID     NAME
---------- ------ ---------------------------------------------------
         3 200003 李三
         4 200004 赵四
SQL> select * from(select rownum,id,name from student)where rownum>2;
    ROWNUM ID     NAME
---------- ------ ---------------------------------------------------
(3)rownum对于小于某值的查询条件
如果想找到第三条记录以前的记录,当使用rownum<3是能得到两条记录的。显然rownum对于rownum<n((n>1的自然数)的条件认为是成立的,所以可以找到记录。
SQL> select rownum,id,name from student where rownum <3;
    ROWNUM ID     NAME
---------- ------ ---------------------------------------------------
1 200001 张一
        2 200002 王二
综上几种情况,可能有时候需要查询rownum在某区间的数据,那怎么办呀从上可以看出rownum对小于某值的查询条件是人为true的,rownum对于大于某值的查询条件直接认为是false的,但是可以间接的让它转为认为是true的。那就必须使用子查询。例如要查询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标出正确序号(有小到大)

posted @ 2011-11-17 16:46 redcoatjk 阅读(312) | 评论 (0)编辑 收藏
 
仅为个人理解.请指正
Hibernate Session, 其作用无需多言.
运用中为避免资源消耗,一般都会手动封装一个HibernateUtil类(未使用Spring管理的前提下).
该类的作用使Hibernate加载配置文件config, 创建sessionFactory等只运行一次.
际运用中,经常需要将当前线程和session绑定.一般的用法为使用ThreadLocal: 在HibernateUtil类中封装hibernate的管理.通过openSession取得
session,并将其放入ThreadLocal变量中. 这样业务逻辑中仅需通过工具类取得当前线程对应的session.使用完毕后,调用工具类closeSession方法将
session关闭,当前线程的ThreadLocal变量置为NULL. 保证线程归还线程池复用后,ThreadLocal为空,以免出现导致其他线程访问到本线程变量.
后,Hibernate的SessionFactory提供获取session的新方法getCurrentSession (获得与当前线程绑定的session). 内部通过代理封装,此方式得到的session
不仅和当前线程绑定,也无需手动开关. 默认在事务提交之后,session自动关闭. 需注意的是,必须在事务开启的前提之下才可使用此种方式获得的session.
此外hibernate.cfg.xml配置文件中也许配置
<property name="current_session_context_class">thread</property> 基于线程
了,引入Spring之后.sessionfactory的创建等都交给spring管理.Spring也提供了HibernateTemplate,HibernateDaoSupport这样的封装方法.
用户可以不再考虑session的管理,事务的开启关闭.只需配置事务即可.
而所谓session关闭后,因延迟加载导致前台无法显示的问题以往解决方式为强制全部加载,现在也可通过在web.xml中配置
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter来解决.



------------------------------以下内容为工地资料-------------------------------------------------------------------------------
OpenSession : 手动打开,需手动关闭.[所以代码中充斥着try catch --sf.openSession --打开事务,提交-回滚 finall关闭session的代码]
threadlocal : hibernate给出的提示. 在HibernateUtil工具类中,new出threadlocal ,放入opensession.这样可以使当前线程绑定session.
使用后需关闭session,将threadlocal中session变量置为null .
3  getCurrentSession: hibernate3的新特性. 无需手动关闭session,自动获取当前线程的session,若无则新建之. 需在配置文件中配置thread属性.表明和当前线程绑定.
    参考网友资料,getCurrentSession模式,内部开启了session自动提交的功能且使用getCurrentSession的session,及时做load操作,也需要打开事务.
Title

1 getCurrentSession创建的session会和绑定到当前线程,而openSession不会。

2 getCurrentSession创建的线程会在事务回滚或事物提交后自动关闭,而openSession必须手动关闭

这里getCurrentSession本地事务(本地事务:jdbc)时 要在配置文件里进行如下设置

 * 如果使用的是本地事务(jdbc事务)
 <property name="hibernate.current_session_context_class">thread</property>
 * 如果使用的是全局事务(jta事务)
 <property name="hibernate.current_session_context_class">jta</property>

getCurrentSession () 使用当前的session
openSession()         重新建立一个新的session

在一个应用程序中,如果DAO 层使用Spring 的hibernate 模板,通过Spring 来控制session 的生命周期,则首选getCurrentSession ()。

使用Hibernate的大多数应用程序需要某种形式的“上下文相关的” session,特定的session在整个特定的上下文范围内始终有效。然而,对不同类型的应用程序而言,要为什么是组成这种“上下文”下一个定义通常 是困难的;不同的上下文对“当前”这个概念定义了不同的范围。在3.0版本 之前,使用Hibernate的程序要么采用自行编写的基于 ThreadLocal的上下文session,要么采用HibernateUtil这样的辅助类,要么采用第三方框架(比如Spring或Pico), 它们提供了基于代理(proxy)或者基于拦截器(interception)的上下文相关session。从3.0.1版本开始,Hibernate增加了SessionFactory.getCurrentSession()方法。一 开始,它假定了采用JTA事务,JTA事务定义了当前session的范围和上下文(scope and context)。Hibernate开发团队坚信,因为有好几个独立的JTA TransactionManager实现稳定可用,不论是否被部署到一个J2EE容器中,大多数(假若不是所有的)应用程序都应该采用JTA事务管理。 基于这一点,采用JTA的上下文相关session可以满足你一切需要。

更好的是,从3.1开始,SessionFactory.getCurrentSession()的后台实现是可拔插的。因此,我们引入了新的扩展 接口 (org.hibernate.context.CurrentSessionContext)和新的配置参数 (hibernate.current_session_context_class),以便对什么是“当前session”的范围和上下文(scope and context)的定义进行拔插。

请参阅 org.hibernate.context.CurrentSessionContext接口的Javadoc,那里有关于它的契约的详细讨论。它定义 了单一的方法,currentSession(),特定的实现用它来负责跟踪当前的上下文session。Hibernate内置了此接口的两种实现。

org.hibernate.context.JTASessionContext - 当前session根据JTA来跟踪和界定。这和以前的仅支持JTA的方法是完全一样的。详情请参阅Javadoc。

org.hibernate.context.ThreadLocalSessionContext - 当前session通过当前执行的线程来跟踪和界定。详情也请参阅Javadoc。

这两种实现都提供了“每数据库事务对应一个session”的编程模型,也称作每次请求一个session。Hibernate session的起始和终结由数据库事务的生存来控制。假若你采用自行编写代码来管理事务(比如,在纯粹的J2SE,或者 JTA/UserTransaction/BMT),建议你使用Hibernate Transaction API来把底层事务实现从你的代码中隐藏掉。如果你在支持CMT的EJB容器中执行,事务边界是声明式定义的,你不需要在代码中进行任何事务或 session管理操作。请参阅第 11 章 事务和并发一节来阅读更多的内容和示例代码。

hibernate.current_session_context_class 配置参数定义了应该采用哪个org.hibernate.context.CurrentSessionContext实现。注意,为了向下兼容,如果未 配置此参数,但是存在org.hibernate.transaction.TransactionManagerLookup的配 置,Hibernate会采用org.hibernate.context.JTASessionContext。一般而言,此参数的值指明了要使用的实 现类的全名,但那两个内置的实现可以使用简写,即"jta"和"thread"。

1、getCurrentSession()与openSession()的区别?

* 采用getCurrentSession()创建的session会绑定到当前线程中,而采用openSession()
创建的session则不会
* 采用getCurrentSession()创建的session在commit或rollback时会自动关闭,而采用openSession()
创建的session必须手动关闭
2、使用getCurrentSession()需要在hibernate.cfg.xml文件中加入如下配置:
* 如果使用的是本地事务(jdbc事务)
<property name="hibernate.current_session_context_class">thread</property>
* 如果使用的是全局事务(jta事务)
<property name="hibernate.current_session_context_class">jta</property>

利于ThreadLocal模式管理Session
   早在Java1.2推出之时,Java平台中就引入了一个新的支持:java.lang.ThreadLocal,给我们在编写多线程程序
   时提供了一种新的选择。ThreadLocal是什么呢?其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,
   而是thread local variable(线程局部变量)。也许把它命名为ThreadLocalVar更加合适。线程局部变量(ThreadLocal)
   其实的功用非常简单,就是为每一个使用某变量的线程都提供一个该变量值的副本,是每一个线程都可以独立地改变自己的副本,
   而不会和其它线程的副本冲突。从线程的角度看,就好像每一个线程都完全拥有一个该变量。
   ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单,在ThreadLocal类中有一个Map,
   用于存储每一个线程的变量的副本。比如下面的示例实现(为了简单,没有考虑集合的泛型):
public class HibernateUtil {

public static final ThreadLocal session =new ThreadLocal();

public static final SessionFactory sessionFactory;
   static {
      try {
        sessionFactory = new Configuration().configure().buildSessionFactory();
      } catch (Throwable ex) {
           throw new ExceptionInInitializerError(ex);
      }   
}

     public static Session currentSession() throws HibernateException {
        Session s = session.get();
        if(s == null) {
          s = sessionFactory.openSession();
          session.set(s);
           }
         return s;
       }

    public static void closeSession() throws HibernateException {
           Session s = session.get();
        if(s != null) {
            s.close();
        }
        session.set(null);
    }
}

以下为ThreadLocal的参考资料
Title

 最近由于需要用到ThreadLocal,在网上搜索了一些相关资料,发现对ThreadLocal经常会有下面几种误解

 一、ThreadLocal是java线程的一个实现
      ThreadLocal的确是和java线程有关,不过它并不是java线程的一个实现,它只是用来维护本地变量。针对每个线程,提供自己的变量版本,主要是为了避免线程冲突,每个线程维护自己的版本。彼此独立,修改不会影响到对方。

 二、ThreadLocal是相对于每个session的

        ThreadLocal顾名思义,是针对线程。在java web编程上,每个用户从开始到会话结束,都有自己的一个session标识。但是ThreadLocal并不是在会话层上。其 实,Threadlocal是独立于用户session的。它是一种服务器端行为,当服务器每生成一个新的线程时,就会维护自己的 ThreadLocal。对于这个误解,个人认为应该是开发人员在本地基于一些应用服务器测试的结果。众所周知,一般的应用服务器都会维护一套线程池,也 就是说,对于每次访问,并不一定就新生成一个线程。而是自己有一个线程缓存池。对于访问,先从缓存池里面找到已有的线程,如果已经用光,才去新生成新的线 程。所以,由于开发人员自己在测试时,一般只有他自己在测,这样服务器的负担很小,这样导致每次访问可能是共用同样一个线程,导致会有这样的误解:每个 session有一个ThreadLocal

 三、ThreadLocal是相对于每个线程的,用户每次访问会有新的ThreadLocal

  理论上来说,ThreadLocal是的确是相对于每个线程,每个线程会有自己的ThreadLocal。但是上面已经讲到,一般的应用服 务器都会维护一套线程池。因此,不同用户访问,可能会接受到同样的线程。因此,在做基于TheadLocal时,需要谨慎,避免出现 ThreadLocal变量的缓存,导致其他线程访问到本线程变量 .[senngr:HibernateUtil工具类中,一般都是通过closesession的方法,里面将opensession对应的session关闭.并将ThreadLocal变量置为NULL.这样线程池中如果再将这个线程分配给别人,对应的ThreadLocal是干净的.]

 四、对每个用户访问,ThreadLocal可以多用
        可以说,ThreadLocal是一把双刃剑,用得来的话可以起到非常好的效果。但是,ThreadLocal如果用得不好,就会跟全局变量一样。代码不 能重用,不能独立测试。因为,一些本来可以重用的类,现在依赖于ThreadLocal变量。如果在其他没有ThreadLocal场合,这些类就变得不 可用了。个人觉得ThreadLocal用得很好的几个应用场合,值得参考

  1、存放当前session用户:quake want的jert

  2、存放一些context变量,比如webwork的ActionContext

  3、存放session,比如Spring hibernate orm的session

posted @ 2011-11-02 01:37 redcoatjk 阅读(17685) | 评论 (3)编辑 收藏
 
http://space.itpub.net/9252210/viewspace-594453
今天在做数据导出的时候,由于用户名的密码使用的是特殊字符,所以遇到了错误代码:“EXP-00056: 遇到 ORACLE 错误 12154”,网上查找原因,需要用引号扩起来,但是os不同,方式也不同:

    windows os: exp username/"""password"""@devdb --3个双引号扩密码

    linux/unix os: exp 'username/"password"@devdb' --1个双引号扩密码,1个单引号扩全部

    实验结果如下:
1.创建带有特殊字符密码的用户
C:\Documents and Settings\Home>sqlplus /nolog
SQL*Plus: Release 10.2.0.1.0 - Production on 星期四 5月 7 17:37:36 2009
Copyright (c) 1982, 2005, Oracle.  All rights reserved.
SQL> connsys/oracle@devdbas sysdba
已连接。
SQL> create user exp identified by "12345!@#$%";
用户已创建。
SQL> grant connect, resource to exp;
授权成功。
SQL> conn exp/"12345!@#$%"@devdb2
已连接。
SQL> create table table1 as select * from dual;
表已创建。
SQL> exit
2.windows os导出测试
C:\Documents and Settings\Home>expexp/12345!@#$%@devdbfile=c:\exp.dmp wner=exp
Export: Release 9.2.0.1.0 - Production on 星期四 5月 7 17:39:42 2009
Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.
EXP-00056: 遇到 ORACLE 错误 12154
ORA-12154: TNS: 无法处理服务名
EXP-00000: 导出终止失败
C:\Documents and Settings\Home>exp exp/"12345!@#$%"@devdb2file=c:\exp.dmp wner=exp
Export: Release 9.2.0.1.0 - Production on 星期四 5月 7 17:39:57 2009
Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.
EXP-00056: 遇到 ORACLE 错误 12154
ORA-12154: TNS: 无法处理服务名
EXP-00000: 导出终止失败
C:\Documents and Settings\Home>exp exp/"""12345!@#$%"""@devdb2file=c:\exp.dmp wner=exp
Export: Release 9.2.0.1.0 - Production on 星期四 5月 7 17:41:54 2009
Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.
连接到: Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - Production
With the Partitioning, Real Application Clusters, OLAP, Data Mining
and Real Application Testing options
已导出 ZHS16GBK 字符集和 AL16UTF16 NCHAR 字符集
. 正在导出 pre-schema 过程对象和操作
. 正在导出用户 EXP 的外部函数库名称
. 导出 PUBLIC 类型同义词
. 导出私有类型同义词
. 正在导出用户 EXP 的对象类型定义
即将导出 EXP 的对象 ...
. 正在导出数据库链接
. 正在导出序号
. 正在导出群集定义
. 即将导出 EXP 的表通过常规路径 ...
. . 正在导出表                          TABLE1          1 行被导出
. 正在导出同义词
. 正在导出视图
. 正在导出存储的过程
. 正在导出运算符
. 正在导出引用完整性约束条件
. 正在导出触发器
. 正在导出索引类型
. 正在导出位图, 功能性索引和可扩展索引
. 正在导出后期表活动
. 正在导出实体化视图
. 正在导出快照日志
. 正在导出作业队列
. 正在导出刷新组和子组
. 正在导出维
. 正在导出 post-schema 过程对象和操作
. 正在导出统计
在没有警告的情况下成功终止导出。

3.linux/unix os导出测试
[oracle@rac2 ~]$ expexp/12345!@#$%@devdbfile=./exp.dmp wner=exp
-bash:!@#$%@devdb: event not found
[oracle@rac2 ~]$ exp exp/"""12345!@#$%"""@devdbfile=./exp.dmp wner=exp
-bash:!@#$%"""@devdb: event not found
[oracle@rac2 ~]$exp 'exp/"12345!@#$%"@devdb'file=./exp.dmp wner=exp 
Export: Release 10.2.0.4.0 - Production on Thu May 7 19:21:32 2009 
Copyright (c) 1982, 2007, Oracle.  All rights reserved. 
Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - Production
With the Partitioning, Real Application Clusters, OLAP, Data Mining
and Real Application Testing options
Export done in US7ASCII character set and AL16UTF16 NCHAR character set
server uses ZHS16GBK character set (possible charset conversion)
. exporting pre-schema procedural objects and actions
. exporting foreign function library names for user EXP
. exporting PUBLIC type synonyms
. exporting private type synonyms
. exporting object type definitions for user EXP
About to export EXP's objects ...
. exporting database links
. exporting sequence numbers
. exporting cluster definitions
. about to export EXP's tables via Conventional Path ...
. . exporting table                         TABLE1          1 rows exported
. exporting synonyms
. exporting views
. exporting stored procedures
. exporting operators
. exporting referential integrity constraints
. exporting triggers
. exporting indextypes
. exporting bitmap, functional and extensible indexes
. exporting posttables actions
. exporting materialized views
. exporting snapshot logs
. exporting job queues
. exporting refresh groups and children
. exporting dimensions
. exporting post-schema procedural objects and actions
. exporting statistics
Export terminated successfully without warnings.

posted @ 2011-10-19 17:03 redcoatjk 阅读(681) | 评论 (0)编辑 收藏
 

关于group by 的应用问题  

数据库内容为下面


 

写一SQL得出下面内容:


 

贴出SQL结果如下:(MySQL版本)

create table gosin_temp(rq varchar(10),shengfu nchar(1));

insert into gosin_temp values('2009-05-09','胜');
insert into gosin_temp values('2009-05-09','胜');
insert into gosin_temp values('2009-05-09','负');
insert into gosin_temp values('2009-05-09','负');
insert into gosin_temp values('2009-05-10','胜');
insert into gosin_temp values('2009-05-10','负');
insert into gosin_temp values('2009-05-10','负');

select * from gosin_temp;

得到结果的SQL:
select a1.rq,a1.胜,b1.负 from
(select a.rq, count(a.shengfu) 胜 from gosin_temp a where a.shengfu='胜' group by a.rq) a1,
(select b.rq, count(b.shengfu) 负 from gosin_temp b where b.shengfu='负' group by b.rq) b1
where a1.rq = b1.rq

类似的题目还有很多,如:

   胜 负
1 a b
2 b a
3 b a

要求写一SQL语句,输出如下结果:
   胜 负
a 1 2
b 2 1

其实都一样 只要熟悉使用group by 就不觉得难了。

posted @ 2011-08-25 17:12 redcoatjk 阅读(213) | 评论 (0)编辑 收藏
 
摘自:   http://www.iteye.com/topic/766418

-----------------------------------------
1,什么是Servlet
2,Servlet有什么作用
3,Servlet的生命周期
4,Servlet怎么处理一个请求
5,Servlet与JSP有什么区别
6,Servlet里的cookie技术
7,Servlet里的过滤器
8,Servlet里的监听器

 


一,什么是Servlet?


Servlet是一个Java编写的程序,此程序是基于Http协议的,在服务器端运行的(如tomcat),

 

是按照Servlet规范编写的一个Java类。



二,Servlet有什么作用?


主要是处理客户端的请求并将其结果发送到客户端。



三,Servlet的生命周期?


Servlet的生命周期是由Servlet的容器来控制的,它可以分为3个阶段;初始化,运行,销毁。

初始化阶段:


1,Servlet容器加载servlet类,把servlet类的.class文件中的数据读到内存中。


2,然后Servlet容器创建一个ServletConfig对象。ServletConfig对象包含了Servlet的初始化配置信息。


3,Servlet容器创建一个servlet对象。


4,Servlet容器调用servlet对象的init方法进行初始化。



运行阶段:


当servlet容器接收到一个请求时,servlet容器会针对这个请求创建servletRequest和servletResponse对象。

 

然后调用service方法。并把这两个参数传递给service方法。Service方法通过servletRequest对象获得请求的

 

信息。并处理该请求。再通过servletResponse对象生成这个请求的响应结果。然后销毁servletRequest和

 

servletResponse对象。我们不管这个请求是post提交的还是get提交的,最终这个请求都会由service方法来处理。


web服务器接受到一个http请求后,web服务器会将请求移交给 servlet容器,servlet容器首先对所请求的URL进行解析并根据
web.xml 配置文件找到相应的处理servlet,同时将request、response对象传递给它,servlet通过request对象可知道客户端
的请求 者、请求信息以及其他的信息等,servlet在处理完请求后会把所有需要返回的信息放入response对象中并返回到客户端,
servlet一旦处理 完请求,servlet容器就会刷新response对象,并把控制权重新返回给web服务器。

 


销毁阶段:


当Web应用被终止时,servlet容器会先调用servlet对象的destrory方法,然后再销毁servlet对象,

 

同时也会销毁与servlet对象相关联的servletConfig对象。我们可以在destroy方法的实现中,释放

 

servlet所占用的资源,如关闭数据库连接,关闭文件输入输出流等。



在这里该注意的地方:


在servlet生命周期中,servlet的初始化和和销毁阶段只会发生一次,而service方法执行的次数则取决于servlet被客户

 

端访问的次数

 

 


四,Servlet怎么处理一个请求?


当用户发送一个请求到某个Servlet的时候,Servlet容器会创建一个ServletRequst和ServletResponse对象。

 

在ServletRequst对象中封装了用户的请求信息,然后Servlet容器把ServletRequst和ServletResponse对象

 

传给用户所请求的Servlet,Servlet把处理好的结果写在ServletResponse中,然后Servlet容器把响应结果传

 

给用户。

 


五,Servlet与JSP有什么区别?


1,jsp经编译后就是servlet,也可以说jsp等于servlet。


2,jsp更擅长页面(表现)。servlet更擅长逻辑编辑。 (最核心的区别)。


3,在实际应用中采用Servlet来控制业务流程,而采用JSP来生成动态网页.在struts框架中,

 

JSP位于MVC设计模式的视图层,而Servlet位于控制层。

 


六,Servlet里的cookie技术?


cookies是一种WEB服务器通过浏览器在访问者的硬盘上存储信息的手段,是由Netscape公司开发出来的。


cookie技术的好处:


    1,Cookie有效期限未到时,Cookie能使用户在不键入密码和用户名的情况下进入曾经浏览过的一些站点。


    2,Cookie能使站点跟踪特定访问者的访问次数、最后访问时间和访问者进入站点的路径。
   
创建一个cookie

Java代码  收藏代码
  1. //里面的两个参数分别是cookie的名和cookie的值  
  2.   
  3. response.addCookie(new Cookie("abc","10000000"));  

 

使用cookie

Java代码  收藏代码
  1. Cookie[] cook =request.getCookies();//用一个Cookie数组来接收  
  2.   
  3. for(int j=0;j<cook.length;j++){//通过循环来打印Cookie  
  4.   
  5.         cook[j].getName()://取cookie的名    
  6.         cook[j].getValue()://去cookie的值  
  7.   
  8. }  
 


七,Servlet里的过滤器?


过滤器的主要作用


1,任何系统或网站都要判断用户是否登录。


2,网络聊天系统或论坛,功能是过滤非法文字


3,统一解决编码


(2)怎么创建一个过滤器:

 

1,生成一个普通的class类,实现Filter接口(javax.servlet.Filter;)。


2,重写接口里面的三个方法:init,doFilter,destroy。


3,然后在web.xml配置过滤器。



八,Servlet里的监听器?


监听器的作用:自动执行一些操作。

三种servlet监听器:

 

对request的监听。对session的监听。对application的监听。

怎么创建一个session监听器:


1,生成一个普通的class类,如果是对session的监听,则实现HttpSessionListener。


2,然后重写里面的五个方法:

 

Java代码  收藏代码
  1. public void sessionCreated(HttpSessionEvent arg0) {} // 创建  
  2.   
  3. public void sessionDestroyed(HttpSessionEvent arg0) {} // 销毁  
  4.   
  5. public void attributeAdded(HttpSessionEvent arg0) {} // 增加  
  6.   
  7. public void attributeRemoved(HttpSessionEvent arg0) {} // 删除  
  8.   
  9. public void attributeReplaced(HttpSessionEvent arg0) {} // 替换 
posted @ 2011-08-25 15:41 redcoatjk 阅读(217) | 评论 (0)编辑 收藏
 
这个写的不错.有的没看懂.
目前没时间细看,暂时先转载.
摘自:
http://www.jdon.com/artichect/state.htm

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

板桥里人 http://www.jdon.com 2006/1/2(转载请保留)

  这是一个实战中非常重要但是容易被忽视的概念,说它重要,是因为它比数据库重要;说它容易被忽视也是同样的原因,它经常被数据库概念替代。

  如果你经验和经历中没有状态这个概念,极端地说:可能你的Java系统经验还未积累到一定程度,状态是每个Java程序员深入Java系统后必然碰到的问题。

  本文我想试图表达的是:状态分两种:活动的状态对象和持久化的状态。而数据库中的数据只是状态的一种持久化结果,而Java系统 运行时,我们更多的可能是和一种活动的状态打交道,这种活动的状态存在内存中,而不是持久化到硬盘上,当然,需要时你可以通过数据库/文件持久化到硬盘上。

  但是,如果你以数据库数据替代状态,那么就可能导致数据库的频繁访问,而且 你的系统会变成一个非对象化的、紧耦合、到处是分散数据块的糟糕系统。这样的系统并不比传统的两层结构好到哪里!也不会比Jsp里嵌入Java代码伪三层系统高明到什么地方。

什么是状态?

  只要有对象就可能有状态,任何一个对象活动时,都有自己的状态属性,类的 字段属性极有可能成为状态,我们现在经常使用的Domain model其实就是一种 包含状态的对象,如果你对状态没有深入掌握,就不可能真正掌握对象系统特点,或者是Domain Model的执行情况。

  对于初学者,经常会疑问:我是将数据放在HttpSession中还是Request中,这里 其实已经开始接触状态,一旦你接触状态,你就要开始小心,因为你可能会将内存泄漏的恶魔导引进来。

  内存泄漏的恶魔爆发时刻取决于你状态的生存周期和系统并发访问量。

  状态的生存周期也就是包含这个状态的对象的生命周期,在简单系统中,我们只 需要通过new创建对象,然后它的消亡就会依靠JVM垃圾回收机制回收,但是事情会这么简单吗?

  状态的危险还会发生在多线程环境下,当多个线程对同一个内存中状态写操作时,这时怎么办?如果这个状 态持久化在数据库中,我们会依赖数据库提供的强大事务机制防止这种并发死锁,但是如果是在内存中,你就很难办,因此,我们就尽量避免发生这种多线程同时访 问一个状态的现象,而Singleton单例模式极容易发生这种现象,因此实践中,单例模式是J2EE开发中需要避免的,相关帖子讨论见:
http://www.jdon.com/jive/article.jsp?forum=91&thread=17578

  我们接触的Web容器或Jsp/Servlet本质就是一个多线程,这也是很多初学者不知道的, 因为多线程编程是复杂或困难的,因此才有jsp/Servlet这样的上层封装,但是我们使用他们
时,实际在进行多线程编程。

  生命周期和多线程并发使得我们简单的面向对象系统变得异常复杂和难以掌握起来。下面我从这个两个角度,给出两种模式思维解决之道。

生命周期(Scope)

  生命周期(Scope)就是指状态的活动周期,状态对象是什么时候被创建;然后什么时候被销毁,很显然,如果状态对象还没有被创建或已经被销毁,你再 访问这个状态对象可能失败,而状态的生命周期控制是可能散落在运行程序的各个地方,如果不象状态模式那样进行统一控制,有可能整个系统是危机四伏的。

  状态的生命周期其实就是对象生命周期,更加细化地说:是Domain Model这个对象的生命周期。这在一个以领域模型为驱动的设计概念中不可回避的课题,而领域模型实战的复杂性就复杂在此。

  状态的生命周期在J2EE中目前有三种:Request/Session和 Application,Request是每个客户端发出的一次请求,这是J2EE系统中最基本的事件激活单元, 当服务器端推出一个页面到客户端时,意味着这个Request的结束。那么如果我们的状态保存在Request中,意味着在request结束之前,这个 请求经历的任何一个环节都可以对这个状态(对象)进行操作。(掌握这个原理,对于你学习Struts和JSF很有帮助)

  如果是Session,则一直和该客户端有关,只要是该客户端发出的每次request的任何环节都可以对这个状态(对象)进行操作。

  如果是Application,则意味着这个状态是当前Web项目的全局状态。

  这三种状态形式都是以将状态保存在内存中形式存在的,是和持久化状态相对的。是一种内存活动状态。

  生命周期的选取当然是越短越好,这样,这个状态对象就可以被自动销毁,从而避免了
大访问量下的内存泄漏,但是在大访问量下,对象频繁创建和销毁是耗费性能的。

  那么,我们可能经常使用HttpSession来保存状态,这时你极有可能造成内存泄漏,我经常在 Jdon论坛上看到将很多数据库数据暂时保存在HttpSession中想法,这是相当危险的,因为一旦并发用户很多,相当多的HttpSession包 含了状态,而状态中有可能有更多其他引用,因此内存很快会爆满,或者垃圾回收机制频繁启动,造成应用系统运行暂停或缓慢。

  当你将状态放入HttpSession时,难道没有考虑将其手工消除吗?你要知道所有Web容器 (Tomcat/Weblogic等)都不会自动替你清除那些你可能不用的状态对象啊。如果每个人只管新增元素,不管重整或管理,这个系统能不变得混乱 吗?代码上这种现象我们是通过Refactoring等结构/行为模式来解决,那么在运行时的状态管理呢?

  状态管理模式或者说对象管理模式正是解决这种问题的。

   按照该模式,你必须手工自己管理放在HttpSession的状态,比如你为每个HttpSession
设立一个状态容器最大尺寸,当超过这个尺寸时,你需要将不用的状态从容器去除, 但是如果这个客户端在Session失效期内又来访问这个状态怎么办?那么你可能需要先临时将状态序列化保存到硬盘上,等Session失效期到达后再真正删除。

  是不是觉得很麻烦?
  捷径是有:
  1. 尽量少使用HttpSession保存状态,这对集群环境也是有利的,见该贴讨论:
http://www.jdon.com/jive/article.jsp?forum=121&thread=22282
那么这些状态放在哪里?使用Application的缓存中,

  2. 使用状态管理中间件,目前有几个选择:EJB的有态Bean;NanoContainer之类状态相关的微容器。那么Spring可以吗?目前没有发现有 该功能,甚至在Spring容器内无法直接使用Session性质的状态,只能通过线程级别的ThreadLocal来实现(对不起,你又要开始回到远古 的汇编线程时代了);而Jdon框架则可以。

  下面我们谈谈Application的状态,在这个范围内,一个对象状态可以被多个用户反复访问,在这个级别,状态类似数据库中数据,因为可以使用数据库来替代这个级别的状态,所以将状态放入缓存这个深层次技术被大多数初学者忽视了,甚至产生了对数据库依赖心理。

缓存中的状态

  虽然我们将状态保存在Application中,但是我们不可避免还是遇到Session同样的状态管理问题,这个问题所幸的是有专门缓存中间件解决 了,当然,在一个多服务器集群系统,如果一个客户端在一个服务器中存放了状态,那么能否在另外一个服务器的内存中访问到呢?回答是肯定的,前提是你必须使 用分布式缓存系统。

  目前分布式缓存系统是靠EJB服务器完成,当JBoss 5在2006变成完全解耦、可肢解时,
我们就可以使用原本只支持EJB的JBoss分布式缓存系统来支持我们的普通JavaBeans了(POJO)。这其中目前可能会花费一些力气,因为还没有一个统一的POJO构件接口标准,我相信以后
可能会有。

  如果你不想花费力气,而且可能就只是一台服务器,可以通过双核芯片提升性能,那么单态缓存如果实现?很简单,使用一个缓存产品如OsCache等,将其设定保存在 Application中,或者在web.xml中进行一下简单的配置即可。

  但是,这时你可能碰到另外一个问题:状态的唯一标识,如何通过唯一标识从缓存中那么
多对象状态中取出你要的那一个呢?比较琐碎。

  有没有一个框架帮助你省却这些麻烦,当然推荐Jdon Framework,只要将包含状态的类(主要是Domain Model)继承特定的类或接口(接口在1.4版本实现)即可,这个类的对象运行时就会被缓存或从缓存中读取,再也无需你照料缓存了,就这么简单。

  当然,Jdon Framework的底层缓存器是可以被替代,使用你喜欢的缓存产品,因为jdon
Framework是基于Ioc设计,构件之间是完全解耦、可彻底肢解,能够通过配置替代和更换的。
如果你不明白这个道理,需要好好研究一下Ioc模式带给我们革命性的新变化。

  从以上也可以看出:java复杂性还在于我们需要在编码时,却要想象其运行时的情形。而这种翻译联想没有深厚的实践功底,是很难顺利完成的。

状态管理中间件

  自从J2EE开辟中间件时代以来,就有相当多的高级中间件提供与具体应用无关的通用功能,状态管理中间件很早就有之,EJB的有态Session Bean是一个代表。

  一个中间件不但要有良好的松耦合设计,我们暂时称为静态设计;更要有优秀的动态设计,例如状态管理就属于一种动态设计。

  当然,如果你比较谦虚,不但要选择一些静态设计很好的框架或中间件;而且还要依赖一些拥有良好的动态运行管理的中间件。

  EJB无论是EJB1.X/EJB2.X/EJB3.X.在状态管理上要更加优秀,当然EJB3.X又吸收了优秀的静态设计概念,但是因为需要有一个具体服务器实现过程,这个过程中存在一些陷阱,如In-Box问题等。

  Spring无疑是一个静态设计非常优秀框架,它一直在AOP上孜孜不倦,力图探索一条从AOP角度进行动态运行管理干预捷径,相信会有惊人结果,当然,这种细粒度的AOP需要实践检验,当然如果整入JDK 6.0就更好。

  而Jdon Framework则试图在目前两者之间寻求了一个平衡,既有Ioc/AOP优秀的静态设计,虽然在AOP上不及Spring前卫;但提供了切实Session和Cache状态管理;

  如果你不需要EJB的分布式多服务器集群功能;又不是AOP的超级粉丝,无疑使用Jdon Framework之类的框架无疑是简化方便的。

状态设计的难点

  最后,我不得不重申,并不是有了良好的状态管理框架就可以高枕无忧了,状态的设计其实是我们每个项目必须面临的可变课题,如果状态复杂了可以使用状态模式对付,可惜往往状态不够复杂。

  一个对象本身属性和状态是应该耦合在一起,还是进行分离,属性和状态没有明显的泾渭分明的界限,我们举一个例子:

  论坛Forum这个对象,它有一些字段属性,如论坛名称、论坛描述,还有其他一些相关属性:如该论坛 的最新发帖;该论坛的发贴量,后两者好像也是论坛字段,但是他们可能经常变化的,应该属于状态,那么状态和Forum这个主体对象是什么关系?是将该论坛 的最新发帖和该论坛的发贴量两个字段并入Forum这个Domain Model中,还是应该单独建立一个状态对象?如果进行分离,分离的依据是什么?

  当然,这里分离的依据是因为对象的生存周期不同。对于我们熟悉的课题,我们能够马上分辨出其中的生存周期,如果是不熟悉领域的建模呢?

  所以,大家已经明白:状态设计的难点是:如何粒度细化地创建模型对象;然后分辨出其中动态的状态性质。这是域建模实战中一个难点。

  很多人问我:你提倡的域建模、设计模式和框架是什么意思?为什么说他们是Java开发设计的三件宝呢?或者说三个典型知识点呢?我想通过本篇我已经通过状态这个概念稍微解释了域建模的一些特点。

  当前,MDA中的四色原型模式Archetype将帮助我们更好地分辨出类的属性、状态和行为,这是一场带来以后十年的软件革命,
posted @ 2011-08-25 15:38 redcoatjk 阅读(177) | 评论 (0)编辑 收藏
 

我对浏览器请求流程的理解:

(1) 访问流程:

(1.1) 系统运行在某web容器,Tomcat(其运行和weblogic不同,Tomcat只有一个进程).

      其预设有初始的线程数.

(1.2) 浏览器打开某网站,网站及给其分配一个sessionID(页面隐式的发起request, Tomcat

      某个特定的监听线程给予response一个sessionid). sessionid用以识别本次访问.

(1.3) 用户点击登录/注册, 浏览器发起一个新的request, Tomcat线程池中空闲的线程进行

       处理. 反馈结果于前台展现.如线程池中线程不足,Tomcat每次按照一定规则创建出更多的空闲线程(其初始值,增加值,及最大值依据配置文件/JDK/硬件).

posted @ 2011-08-25 11:37 redcoatjk 阅读(222) | 评论 (0)编辑 收藏
 
来源:
http://www.iteye.com/topic/960652
http://godsend-jin.iteye.com/blog/1004386
--------------------------------------------------------------------

最近在做登录和权限控制模块,用到了session,发现session的好多方法都不熟悉,而且以前也听说过JsessionId 之类session窃取的事,

对这些一直都是一知半解。今天索性google了很多资料,先上sun的官网去看session的文档了解一些方法,又找了别人关于session的看法。

总结如下:

      1,session是什么?  what

          session经常译为会话,以打电话为例,从开始拨号到挂断电话就是你会话的生存周期。

      2,session 做什么用的  why?

          首先举个例子:

                咖啡店举行 消费满5杯咖啡赠送一杯的活动,可每个人一次消费5杯的时候非常少。这时候有3种办法:

                1,店员看到每个顾客时都能记住其消费了多少杯,从而给其优惠,这是协议本身具有状态

                2,给每个顾客一个卡片,上面记录顾客的每次消费,这是客户端保存状态

                3,给每个顾客一个卡片,卡片上只有一个编号,顾客每次的消费记录在店里,这就是 服务端有状态

          而http本身是无状态的,所以我们只能使用2,3中方法,来保存一些信息。

          实际采用的是第3种方法,服务器段保存一次会话所有的信息,并生成一个唯一的id,这个id没有规律而且不会重复,将这个id传回到客户段,

保存到cookie中。每次访问服务器时,客户端都会偷偷将这个id传到服务器,服务器根据id查到这次会话保存的内容。就能实现会话中共享一些数据。

     3,session怎样创建和销毁 ? how

         session是保存在内存中的,所以会有一些性能上的影响。因此本着这个原则,session是只有在使用到的时候才会被创建,如果始终没有用到

session,这个session是永远不会被创建的。

        比如: 访问servlet ,只要你代码中没有 request.getSession()或request.getSession(true);这两行是等价的,那session是不会创建。

又 当你访问静态页面时,根本不会生成servlet,所以也不会创建session。

       下面解释一些疑惑: session是第一次请求时创建的?

  大家都知道 jsp是被编译成servlet才执行的,问题就在jsp编译的过程。

 jsp中有个<%@ page session="true/false"%> 这个开关表示是否创建session,当你不写这行时,它会默认给你加上这句。所以会造成上面的疑惑。

当然还有一些标签中可能有getSession()操作,会产生一些不必要的session。

       session只能在服务端销毁,有三种途径: 1,到达session的最大请求间隔时间时,2,session。invalidate()

 3,服务器进程当掉。

       这里也有一些疑惑: 浏览器关闭时,session就会注销。

       首先浏览器关闭时,浏览器并没有给服务器发送任何消息,所以服务器不会知道浏览器何时关闭了。

 上面我们知道取得session 是因为浏览器cookie中有sessionid,而普通cookie通常会是会话cookie,也就是说浏览器关闭时,这个cookie会被注销,

所以当你再访问服务器时就没有sessionid了,所以造成session关闭了的假象,如果昵称通过特殊方法将sessionid传递给服务器,你会发现session还在。

如果想让cookie保存时间长一些,就需要手动指定cookie的过期时间

 

4,实际项目中的难点:

     1,浏览器禁用cookie

      这就没办法保存sessionid了,可以采用url重写,转发,加隐藏字段等方法来将sessionid传给服务器。

     如:  baidu.com:jsessionid=adfasdfasdfasdfasdfafdadf?asdfasdf

             baidu.com?jsessionid=asdfasdfasdfadsfad&&adfdf

 这根据服务器的不同实现,第一种可以将普通参数区分开。

 

     2,多人共用session的问题

        例: a 访问 baidu.com ,但他没有帐号,于是他将连接 baidu.com/login.jsp?jsessionid=adsfasdfad(这个a的sessionid) 发给B, B登录

后,a就相当于用b的帐号登录了。你们可以在在本地试试。

        解决方法: 当发现通过sessionid从url指定时, 创建一个新的session,将旧session的信息复制到 新sessoin中,然后将新session注销。

就能防止上面那种情况了。

    3,一个帐号多地方登录

       比如: 你用abc帐号登录了baidu.com,有打开了一个浏览器,又用abc帐号登录了一次。当不设计敏感操作时,这无所谓,而当你做一些敏感操

作时就必须禁止这样情况,防止同时操作,造成重复操作,或者数据损坏。

     解决方法: 监听session,将username和sessionid对应起来,当username再次登录时,注销掉以前的session,保存现在的session,这也是

一种比较不错的方案。

 

这是 sghcel 画的图,挺不错的:

 



其他:
 1session在何时被创建 
    一个常见的误解是以为session在有客户端访问时就被创建,然而事实是直到某server端程序调用 HttpServletRequest.getSession(true)这样的语句时
才被创建,注意如果
JSP没有显示的使用 <%@page session="false"%> 关闭session,则JSP文件在编译成Servlet时将会自动加上这样一条语句
HttpSession session = HttpServletRequest.getSession(true);这也是JSP中隐含的session对象的来历。 

   
由于session会消耗内存资源,因此,如果不打算使用session,应该在所有的JSP中关闭它。


    2
session何时被删除
  综合前面的讨论,session在下列情况下被删除a.程序调用HttpSession.invalidate();b.距离上一次收到客户端发送的session id时间间隔超过了session
超时设置
;c.服务器进程被停止(非持久session


    3
、如何做到在浏览器关闭时删除session
Title
  严格的讲,做不到这一点。可以做一点努力的办法是在所有的客户端页面里使用javascript代码window.oncolose来监视浏览器的关闭动作,然后向服务器发送
一个请求来删除
session。但是对于浏览器崩溃或者强行杀死进程这些非常规手段仍然无能为力。


    4
、有个HttpSessionListener是怎么回事 

   
你可以创建这样的listener去监控session的创建和销毁事件,使得在发生这样的事件时你可以做一些相应的工作。注意是session的创建和销毁动作触发listener
而不是相反。类似的与
HttpSession有关的listener还有 HttpSessionBindingListenerHttpSessionActivationListener HttpSessionAttributeListener 

    5
、存放在session中的对象必须是可序列化的吗 


 
不是必需的。要求对象可序列化只是为了session能够在集群中被复制或者能够持久保存或者在必要时server能够暂时把session交换出内存。
Weblogic Serversession中放置一个不可序列化的对象在控制台上会收到一个警告。我所用过的某个iPlanet版本如果session中有不可序列化的对象,
session销毁时会有一个Exception,很奇怪。


    6
、如何才能正确的应付客户端禁止cookie的可能性
 
    对所有的URL使用URL重写,包括超链接,formaction,和重定向的URL,具体做法参见[6]
http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770


    7
、开两个浏览器窗口访问应用程序会使用同一个session还是不同的session 

   
参见第三小节对cookie的讨论,对session来说是只认id不认人,因此不同的浏览器,不同的窗口打开方式以及不同的cookie存储方式都会对这个问题
的答案有影响。
 

    8
、如何防止用户打开两个浏览器窗口操作导致的session混乱 
这个问题与防止表单多次提交是类似的,可以通过设置客户端的令牌来解决。就是在服务器每次生成一个不同的id返回给客户端,同时保存在session里,
客户端提交表单时必须把这个
id也返回服务器,程序首先比较返回的id与保存在session里的值是否一致,如果不一致则说明本次操作已经被提交过了。
可以参看《
J2EE核心模式》关于表示层模式的部分。需要注意的是对于使用javascript window.open打开的窗口,一般不设置这个id,或者使用单独的id
以防主窗口无法操作,建议不要再
window.open打开的窗口里做修改操作,这样就可以不用设置。


    9
、为什么在Weblogic Server中改变session的值后要重新调用一次session.setValue 


做这个动作主要是为了在集群环境中提示Weblogic Server session中的值发生了改变,需要向其他服务器进程复制新的session值。


   10HttpSession 和 hibernate session 有什么区别?
httpSession :

它的产生:J2EE的Web程序在运行的时候,会给每一个新的访问者建立一个HttpSession,这个Session是用户身份的唯一表示。注意,是容器

(Tomcat,Resin)自动创建的。

用途:存放这个用户的一些经常被用到的信息,例如:用户名,权限。例如在购物车程序里,存放用户买的商品。

销毁:一定时间(跟容器有关)内,用户无任何动作,session自动销毁。

得到的方法:
HttpSession session = request.getSession();
常用方法setAttribute
session.setAttribute(key,value);
这样在另一个jsp或者Servlet里,可以用
session.getAttribute(key);得到value
类似一个Map


hibernate session

它是hibernate操作数据库的一个句柄对象。它跟上面那个Session唯一的相似处就是名字有点像,其他没任何一样的地方。
它是hibernate表示操作数据库的一个会话

 

posted @ 2011-08-25 11:22 redcoatjk 阅读(1242) | 评论 (0)编辑 收藏
 

AOP术语介绍

1. 正常的编程为从上到下的调用,执行



2. 加入了安全性检查,日志这样的代码. 这是一个横切的问题,其于正常的业务毫无关系.

横切的问题会散布在代码的各个角落
.


3.这个横切就是横切性的关注点: Cross cutting concern





4.
将横切的关注点都放在一个类中(如动态代理项目中的SecurityHandler.java).这个类就叫做切面.

   对横切关注点进行模块化,这个模块化的类就叫做切面类(Aspect对应的类) ,


 

 

5. 在切面类中对某个问题如日志或安全性检查的具体实现方法,叫做横切关注点的具体实现(称为Advice).






 

 

6. 这个Advice可以进行分类. :在业务方法执行之前,之后.异常时候……


 

7. Advice应用的目标方法范围(那些方法之前,之后,异常….)这个过滤范围叫做切入点Pointcut()


 

8 .植入

Advice应用的目标方法的过程叫做植入(Weave)

Spring只支持针对业务方法执行前,执行后进行植入. 即只支持方法级别的植入

植入的地方就叫做连接点.

SpringAop是使用代理模式.

 

横切问题的处理思路:

发现横切性的问题,将其模块化(切片).然后形成切片类,在其中实现这些横切性的功能.

posted @ 2011-06-26 21:58 redcoatjk 阅读(195) | 评论 (0)编辑 收藏
 
摘自:
http://www.iteye.com/topic/257191

-----------------
今天下午研究了半天hashcode()和equals()方法,终于有了一点点的明白,写下来与大家分享(zhaoxudong 2008.10.23晚21.36)。
1. 首先equals()和hashcode()这两个方法都是从object类中继承过来的。
equals()方法在object类中定义如下:
  public boolean equals(Object obj) {
return (this == obj);
}
很明显是对两个对象的地址值进行的比较(即比较引用是否相同)。但是我们必需清楚,当String 、Math、还有Integer、Double。。。。等这些封装类在使用equals()方法时,已经覆盖了object类的equals()方法。比 如在String类中如下:
  public boolean equals(Object anObject) {
if (this == anObject) {
    return true;
}
if (anObject instanceof String) {
    String anotherString = (String)anObject;
    int n = count;
    if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
    if (v1[i++] != v2[j++])
return false;
}
return true;
    }
}
return false;
}
很明显,这是进行的内容比较,而已经不再是地址的比较。依次类推Double、Integer、Math。。。。等等这些类都是重写了equals()方法的,从而进行的是内容的比较。当然了基本类型是进行值的比较,这个没有什么好说的。
我们还应该注意,Java语言对equals()的要求如下,这些要求是必须遵循的:
• 对称性:如果x.equals(y)返回是“true”,那么y.equals(x)也应该返回是“true”。
• 反射性:x.equals(x)必须返回是“true”。
• 类推性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那么z.equals(x)也应该返回是“true”。
• 还有一致性:如果x.equals(y)返回是“true”,只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是“true”。
• 任何情况下,x.equals(null),永远返回是“false”;x.equals(和x不同类型的对象)永远返回是“false”。
以上这五点是重写equals()方法时,必须遵守的准则,如果违反会出现意想不到的结果,请大家一定要遵守。
2. 其次是hashcode() 方法,在object类中定义如下:
  public native int hashCode();
说明是一个本地方法,它的实现是根据本地机器相关的。当然我们可以在自己写的类中覆盖hashcode()方法,比如String、 Integer、Double。。。。等等这些类都是覆盖了hashcode()方法的。例如在String类中定义的hashcode()方法如下:
    public int hashCode() {
int h = hash;
if (h == 0) {
    int off = offset;
    char val[] = value;
    int len = count;

            for (int i = 0; i < len; i++) {
                h = 31*h + val[off++];
            }
            hash = h;
        }
        return h;
}
解释一下这个程序(String的API中写到):
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
使用 int 算法,这里 s[i] 是字符串的第 i 个字符,n 是字符串的长度,^ 表示求幂。(空字符串的哈希码为 0。)

3.这里我们首先要明白一个问题:
equals()相等的两个对象,hashcode()一定相等;
equals()不相等的两个对象,却并不能证明他们的hashcode()不相等。换句话说,equals()方法不相等的两个对象,hashcode()有可能相等。(我的理解是由于哈希码在生成的时候产生冲突造成的)。
反过来:hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()可能相等,也可能不等。解释 下第3点的使用范围,我的理解是在object、String等类中都能使用。在object类中,hashcode()方法是本地方法,返回的是对象的 地址值,而object类中的equals()方法比较的也是两个对象的地址值,如果equals()相等,说明两个对象地址值也相等,当然 hashcode()也就相等了;在String类中,equals()返回的是两个对象内容的比较,当两个对象内容相等时,
Hashcode()方法根据String类的重写(第2点里面已经分析了)代码的分析,也可知道hashcode()返回结果也会相等。以此类 推,可以知道Integer、Double等封装类中经过重写的equals()和hashcode()方法也同样适合于这个原则。当然没有经过重写的 类,在继承了object类的equals()和hashcode()方法后,也会遵守这个原则。

4.谈到hashcode()和equals()就不能不说到hashset,hashmap,hashtable中的使用,具体是怎样呢,请看如下分析:
Hashset是继承Set接口,Set接口又实现Collection接口,这是层次关系。那么hashset是根据什么原理来存取对象的呢?
在hashset中不允许出现重复对象,元素的位置也是不确定的。在hashset中又是怎样判定元素是否重复的呢?这就是问题的关键所在,经过一下午的查询求证终于获得了一点启示,和大家分享一下,在java的集合中,判断两个对象是否相等的规则是:
1),判断两个对象的hashCode是否相等
      如果不相等,认为两个对象也不相等,完毕
      如果相等,转入2)
(这一点只是为了提高存储效率而要求的,其实理论上没有也可以,但如果没有,实际使用时效率会大大降低,所以我们这里将其做为必需的。后面会重点讲到这个问题。)
2),判断两个对象用equals运算是否相等
      如果不相等,认为两个对象也不相等
      如果相等,认为两个对象相等(equals()是判断两个对象是否相等的关键)
为什么是两条准则,难道用第一条不行吗?不行,因为前面已经说了,hashcode()相等时,equals()方法也可能不等,所以必须用第2条准则进行限制,才能保证加入的为非重复元素。
比如下面的代码:

public static void main(String args[]){
String s1=new String("zhaoxudong");
String s2=new String("zhaoxudong");
System.out.println(s1==s2);//false
System.out.println(s1.equals(s2));//true
System.out.println(s1.hashCode());//s1.hashcode()等于s2.hashcode()
System.out.println(s2.hashCode());
Set hashset=new HashSet();
hashset.add(s1);
hashset.add(s2);
/*实质上在添加s1,s2时,运用上面说到的两点准则,可以知道hashset认为s1和s2是相等的,是在添加重复元素,所以让s2覆盖了s1;*/
Iterator it=hashset.iterator();
            while(it.hasNext())
            {
             System.out.println(it.next());
            }
最后在while循环的时候只打印出了一个”zhaoxudong”。
输出结果为:false
            true
            -967303459
            -967303459
这是因为String类已经重写了equals()方法和hashcode()方法,所以在根据上面的第1.2条原则判定时,hashset认为它们是相等的对象,进行了重复添加。
但是看下面的程序:
import java.util.*;
public class HashSetTest
{
   public static void main(String[] args)
    {
                 HashSet hs=new HashSet();
                 hs.add(new Student(1,"zhangsan"));
                 hs.add(new Student(2,"lisi"));
                 hs.add(new Student(3,"wangwu"));
                 hs.add(new Student(1,"zhangsan"));
 
                 Iterator it=hs.iterator();
                 while(it.hasNext())
                 {
                        System.out.println(it.next());
                 }
     }
}
class Student
   {
     int num;
     String name;
     Student(int num,String name)
                {
                this.num=num;
                 this.name=name;
                 }
              public String toString()
                {
                    return num+":"+name;
                 }
           }     
输出结果为:
                      1:zhangsan
                   1:zhangsan
                   3:wangwu
                   2:lisi
问题出现了,为什么hashset添加了相等的元素呢,这是不是和hashset的原则违背了呢?回答是:没有
因为在根据hashcode()对两次建立的new Student(1,"zhangsan")对象进行比较时,生成的是不同的哈希码值,所以hashset把他当作不同的对象对待了,当然此时的 equals()方法返回的值也不等(这个不用解释了吧)。那么为什么会生成不同的哈希码值呢?上面我们在比较s1和s2的时候不是生成了同样的哈希码 吗?原因就在于我们自己写的Student类并没有重新自己的hashcode()和equals()方法,所以在比较时,是继承的object类中的 hashcode()方法,呵呵,各位还记得object类中的hashcode()方法比较的是什么吧!!
它是一个本地方法,比较的是对象的地址(引用地址),使用new方法创建对象,两次生成的当然是不同的对象了(这个大家都能理解吧。。。),造成 的结果就是两个对象的hashcode()返回的值不一样。所以根据第一个准则,hashset会把它们当作不同的对象对待,自然也用不着第二个准则进行 判定了。那么怎么解决这个问题呢??
答案是:在Student类中重新hashcode()和equals()方法。
例如:
  class Student
{
int num;
String name;
Student(int num,String name)
{
            this.num=num;
            this.name=name;
}
public int hashCode()
{
            return num*name.hashCode();
}
public boolean equals(Object o)
{
            Student s=(Student)o;
            return num==s.num && name.equals(s.name);
}
public String toString()
{
            return num+":"+name;
}
}
根据重写的方法,即便两次调用了new Student(1,"zhangsan"),我们在获得对象的哈希码时,根据重写的方法hashcode(),获得的哈希码肯定是一样的(这一点应该没有疑问吧)。
当然根据equals()方法我们也可判断是相同的。所以在向hashset集合中添加时把它们当作重复元素看待了。所以运行修改后的程序时,我们会发现运行结果是:
                      1:zhangsan
                   3:wangwu
                   2:lisi
可以看到重复元素的问题已经消除。
关于在hibernate的pojo类中,重新equals()和hashcode()的问题:
1),重点是equals,重写hashCode只是技术要求(为了提高效率)
2),为什么要重写equals呢,因为在java的集合框架中,是通过equals来判断两个对象是否相等的
3),在hibernate中,经常使用set集合来保存相关对象,而set集合是不允许重复的。我们再来谈谈前面提到在向hashset集合中添加元素时,怎样判断对象是否相同的准则,前面说了两条,其实只要重写equals()这一条也可以。
但当hashset中元素比较多时,或者是重写的equals()方法比较复杂时,我们只用equals()方法进行比较判断,效率也会非常低, 所以引入了hashcode()这个方法,只是为了提高效率,但是我觉得这是非常有必要的(所以我们在前面以两条准则来进行hashset的元素是否重复 的判断)。
比如可以这样写:
public int hashCode(){
   return  1;}//等价于hashcode无效
这样做的效果就是在比较哈希码的时候不能进行判断,因为每个对象返回的哈希码都是1,每次都必须要经过比较equals()方法后才能进行判断是否重复,这当然会引起效率的大大降低。
我有一个问题,如果像前面提到的在hashset中判断元素是否重复的必要方法是equals()方法(根据网上找到的观点),但是这里并没有涉及到关于哈希表的问题,可是这个集合却叫hashset,这是为什么??
我想,在hashmap,hashtable中的存储操作,依然遵守上面的准则。所以这里不再多说。这些是今天看书,网上查询资料,自己总结出来 的,部分代码和语言是引述,但是千真万确是自己总结出来的。有错误之处和不详细不清楚的地方还请大家指出,我也是初学者,所以难免会有错误的地方,希望大 家共同讨论。
posted @ 2011-05-27 18:15 redcoatjk 阅读(360) | 评论 (0)编辑 收藏
仅列出标题
共8页: 上一页 1 2 3 4 5 6 7 8 下一页 
CALENDER
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

常用链接

留言簿(3)

随笔分类(22)

随笔档案(76)

文章分类(12)

文章档案(17)

搜索

  •  

积分与排名

  • 积分 - 249961
  • 排名 - 227

最新评论

评论排行榜


Powered By: 博客园
模板提供沪江博客