日期:2014-05-16  浏览次数:20720 次

Weblogic92中,不少系统为了降低系统的内存开销,抑或防止session丢失,管理人员会是用JDBC store来存放session信息。不过在使用这种
 Weblogic92中,不少系统为了降低系统的内存开销,抑或防止session丢失,管理人员会是用JDBC store来存放session信息。不过在使用这种配置的时候,不少客户反映会碰到约束冲突的异常信息,如下,
  <Jan 23, 2009 10:07:33 AM CST> <Error> <HTTP Session> <BEA-100087> <The jdbc session data for session id: DcwFJ5mH1HbFrVR2L6z5xpyGXcWLbJFxHrxP2ZF6jQ1hVJ32Gmfl ctx:testWeb dblat:1232676391562 triggerLAT:0 has been modified by another server in the cluster.
  java.sql.SQLException: ORA-00001: unique constraint (SYSTEM.SYS_C003007) violated
  at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:112)
  at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:331)
  at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:288)
  at oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:743)
  at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:216)
  Truncated. see log file for complete stacktrace
   本文就对这个问题作一下分析,看看什么样的原因会引起上述问题。
   首先,我们想一下,为什么会出现诸如ORA-00001,这样的错误。下面是ORA-00001的问题官方描述,
   This error means that an attempt has been made to insert a record with a duplicate (unique) key. This error will also be generated if an existing record is updated to generate a duplicate (unique) key. Typically this is a duplicate primary key, but it need not be the primary key.
   如上所述,这类问题多是由于我 create table wl_servlet_sessions
( wl_id VARCHAR2(100) NOT NULL,
    wl_context_path VARCHAR2(100) NOT NULL,
    wl_is_new CHAR(1),
    wl_create_time NUMBER(20),
    wl_is_valid CHAR(1),
    wl_session_values LONG RAW,
    wl_access_time NUMBER(20),
    wl_max_inactive_interval INTEGER,
   PRIMARY KEY (wl_id, wl_context_path) );们插入或更新纪录时,出现duplicate (unique) key导致的。Weblogic92中,使用JDBC store来存储session的时候,所有的session会被放入一张叫做wl_servlet_sessions的表中,我们现在看看wl_servlet_sessions,哪些列可能导致duplicate key呢?wl_servlet_sessions的结构如下:对于不同的database,具体表结构请参考 http://e-docs.bea.com/wls/docs92/webapp/sessions.html。从表结构中我们可以看到,weblogic使用wl_id,wl_context_path作为联合主键,由于对于一个session application而言,他的wl_context_path是固定,所以引发ORA-00001的只有wl_id。那么到底是insert,还是update引起这个问题的呢?Weblogic中,更新sessio的时候,只更新session data,不会更新其primary key,也就是说session update不会引起ORA-00001,原因只能是insert,即尝试插入相同wl_id数据的时候,会引发该问题。即使同样是插入操作,其直接原因也可能分为如下几种情况,
  1: weblogic的bug
  2: 应用场景问题(比如load balancer不能保证session stick)
   下面我会分别介绍一下这两种情况,
   1:Weblogic的bug
   也许你会问,同一时刻,一个session id不是只能有一个与其对应的session object在内存中吗?而且这应该由weblogic来保证。是的,正常情况下,客户端请求进到Weblogic的时候,weblogic会检查cache中是否存在与其session id对应的session object,有的话,从cache中取出,没有的话,它会通过getFromDB()从database中load,如果还是没有,这时候才会通过dbCreate去插入一条记录。 如果中间某一处weblogic没有控制好的话,问题就来了。我将以如下的一个test作为案例,分析一下具体过程,
   这里将不考虑应用场景问题,即session stick可以被保证。假如一个客户在访问应用系统时,顺序访问了三个应用页面(page 1/2/3),而这三个页面中, page 1/3会涉及session更新(set attribute),而page 2只读取session(get attribute). 由于这个问题和session的dbLAT、triggerLAT相关,所以我们主要这里主要关注 dbLAT、triggerLAT的变化及问题点。
   1.1: client访问page1, 假如page1中第一次访问session对象,由于cache和db中均没有该对象,那么我们会创建一个session, 并以wl_id和wl_context_path作为主键,插入纪录。page1中作写setAttribute的动作,请求结束后,这个对象会被同步到数据库,同时session数据被放入内存的cache中.注意:cache用于限制内存中当前active的session数,当cache满了的时候,最早进入cache的session将被从cache中挪走。默认的cache size为1024,这个至可以通过session-descriptor的cache-size配置。这里可以看到,syncSession的时候,首先检查对象是否作过修改,如果没有,通过jdbcCtx.updateLAT()去更新triggerLAT,如果做过修改,我们到数据库中检查对象是否存在,存在的话,更新dbLAT,如果不存在,通过dbCreate()插入纪录。我们这一步中,因为是第一个请求,所以db中没有记录,要通过dbCreate()插入纪录,假如同步进数据库的dbLAT为1,由于这是没有timerTrigger被触发,它的triggerLAT为0。
   1.2: client访问完page1后,继续访问page2,由于cache中能够找到session-id对应的对象,我们直接利用cache中的对象,该对象属性如下:
   Session_A.dbLAT = 1(这里1标示某个时间点)
   Session_A.triggerLAT = 0
   请求结束时,由于我们没有修改这个session对象(只做了read attribute), 在syncSession的时候,我们会把这个update操作交给trigger去做,即jdbcCtx.updateLAT()。这个trigger就是LastAccessTimeTrigger,它用于批量更新类似未作修改的session的triggerLAT修改,每10秒被触发一次。我们把这个Session_A交给trigger,这时候triggerLAT被赋一个值(这个值在trigger被触发的时候被写入数据库