一个困扰了我一个多月的问题,关于空指针的。。。请教各位老大。。。

一个困扰了我一个多月的问题,关于空指针的。。。请教各位老大。。。

问题描述:

Stacktrace:
org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:505)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:416)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)

root cause

java.lang.NullPointerException
servlet.CountIPShw.doPost(CountIPShw.java:110)
servlet.CountIPShw.doGet(CountIPShw.java:50)
javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.apache.jasper.runtime.JspRuntimeLibrary.include(JspRuntimeLibrary.java:968)
org.apache.jsp.mng.ipcount_jsp._jspService(ipcount_jsp.java:90)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:374)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)

[size=medium]servlet.CountIPShw.doPost(CountIPShw.java:110)[/size]代码如下:
ExecuteDB exedb = new ExecuteDB();
ResultSet rs1 = exedb.exeQuery("select count(*) from ip where date != \""+date+"\";");
ResultSet rs2 = exedb.exeQuery("select * from visit;");
ResultSet rs3 = exedb.exeQuery("select count(*) from ip where date = \""+date+"\";");
try {
[size=medium]if(rs1.next()&&rs2.next()){[/size]//这是第110行
if(rs1.getString(1)!=null&&!rs1.getString(1).equals("")){
amount = rs1.getInt(1)+rs2.getInt(1);
exedb.exeSql("update visit set amount = "+amount);
exedb.exeSql("delete from ip where date != \""+date+"\";");
}
}
rs1.close();
rs2.close();
if(rs3.next()){
if(rs3.getString(1)!=null&&!rs3.getString(1).equals(""))today = rs3.getInt(1);
}
rs3.close();
} catch (SQLException e) {
}
exedb.close();
这里的ExecuteDB 类代码如下:
package newshop;

import java.sql.*;

public class ExecuteDB
{
private String userName="****";
private String userPassword="****";
private String url="jdbc:mysql://127.0.0.1:3306/****";
private Connection dbConn;
private Statement stmt;
private ResultSet rs;

private String errMes;

public ExecuteDB()
{
    dbConn = this.getConn();
    stmt = null;
    rs = null;  
    this.errMes = this.getErrMes(); 
}

public Connection getConn()
{       
    try
    { 
        Class.forName("org.gjt.mm.mysql.Driver").newInstance();
        dbConn= DriverManager.getConnection(url,userName,userPassword);
    }
    catch(Exception e)
    {           
        dbConn = null;
        errMes=e.toString();            
    }finally{

    }
    return dbConn;
}

public boolean exeSql(String strSql)
{
    boolean isSuc = false;      
    try
    {
        stmt=dbConn.createStatement();
        stmt.executeUpdate(strSql); 
        isSuc = true;    
    }
    catch(Exception e)
    {
        this.errMes = this.errMes + "<br>" +e.toString();           
    }finally{
    }
    return isSuc;
}

public ResultSet exeQuery(String strSql)
{       
    try
    {
        stmt=dbConn.createStatement();
        rs =stmt.executeQuery(strSql);  
    }
    catch(Exception e)
    {   
        this.errMes = this.errMes + "<br>" +e.toString();   
        rs = null;
    }finally{
    }
    return rs;
}

public void close()
{   
    try {
        stmt.close();   
        dbConn.close();
    } catch (SQLException e) {
        this.errMes = this.errMes + "<br>" +e.toString();   
    }
}

public String getErrMes()
{
    return errMes;
}       

}

你是在程序中对于每个请求自己创建连接,当请求比较多的时候,连接就不够用了。

而且,你在doPost()里面,当有异常的时候,也没有关闭数据库连接,只有正常结束的情况下才关闭。

一般数据库连接都是有限制的,你这样自己创建连接肯定不行,当并发请求比较多的时候,数据库就会连接不上,那你执行sql的时候就肯定会出错了。

你的代码还有一个很大的问题,java里面处理异常,你不能吞了它,而应该把它重新扔出来,最后在doPost之类的方法里面统一处理。在你的代码里,getConn() 方法,已经exeQuery()方法里面的异常你都只是记录,但是没有抛出来,这样,程序出错的时候是空指针,但是实际上错误是在一开始创建连接的时候。就会误导你debug。

建议使用一些DAO框架,像iBatis、Hibernate之类的,可以提供数据库连接池。

servlet.CountIPShw.doPost(CountIPShw.java:110)代码如下:

这里提示的110行是哪一行

代码 初始化的时候 不能这样写吧

dbConn = this.getConn();

你试一下把

[code="java"]public ExecuteDB()
{
dbConn = this.getConn();
stmt = null;
rs = null;

this.errMes = this.getErrMes();
}
[/code]
改成
[code="java"]
public ExecuteDB()
{
try
{
Class.forName("org.gjt.mm.mysql.Driver").newInstance();
dbConn= DriverManager.getConnection(url,userName,userPassword);
}
catch(Exception e)
{

dbConn = null;
errMes=e.toString();

}finally{

}
stmt = null;
rs = null
}

[/code]

但是这样也不合适,将来数据库链接会不及时释放

你先试一下看看结果

这个就得对JAVA对像初始化的执行顺序 要有一定的了解了

你能断点调试看看是改后的哪一行出错吗?

你把刚才 改的代码再替回来吧,可能我记错了,那样初始化也不可以(不过你这样取数据库连接还是会造成混乱,链接也有可能没法及时释放 等 问题)

[code="java"]ExecuteDB exedb = new ExecuteDB();
ResultSet rs1 = exedb.exeQuery("select count(*) from ip where date != \""+date+"\";");
ResultSet rs2 = exedb.exeQuery("select * from visit;");
ResultSet rs3 = exedb.exeQuery("select count(*) from ip where date = \""+date+"\";");

[/code]

这段代码三个RS感觉是同一个,因为你只声明了一个exedb

你把这个
[code="java"]public ResultSet exeQuery(String strSql)
{

try
{
stmt=dbConn.createStatement();
rs =stmt.executeQuery(strSql);

}
catch(Exception e)
{

this.errMes = this.errMes + "
" +e.toString();

rs = null;
}finally{
}
return rs;
} [/code]

改成
[code="java"]
public ResultSet exeQuery(String strSql)
{

try
{
stmt=dbConn.createStatement();
return stmt.executeQuery(strSql);

}
catch(Exception e)
{

this.errMes = this.errMes + "
" +e.toString();

}finally{
}
}

[/code]

不要把查询结果赋给RS再返回了,这样的话你的三个RS就变成同一个了,直接把结果 返回

而且你这代码里在RS.NEXT偱环里还有

exedb.exeSql("update visit set amount = "+amount); 这些操作

在这些操作里STMT又重新赋值产生了变化 ,也就有可能导致RS变空

感觉这代码有点乱..... :(

睡觉 了,明天 有时间 再看了

[quote]if(rs1.next()&&rs2.next()){//这是第110行 [/quote]

简单的看了一下代码,显然rs1或者rs2当中有一个为null.
再看实现:
public ResultSet exeQuery(String strSql)
{
try
{
stmt=dbConn.createStatement();
rs =stmt.executeQuery(strSql);
}
catch(Exception e)
{
this.errMes = this.errMes + "
" +e.toString();
[b]rs = null;[/b]
}finally
{
}
return rs;
}

这里rs不能是共享成员变量
应该改为:
public ResultSet exeQuery(String strSql)
{
ResultSet rset = null;
try
{
stmt=dbConn.createStatement();
rset =stmt.executeQuery(strSql);
}
catch(Exception e)
{
this.errMes = this.errMes + "
" +e.toString();
}finally
{
}
return rset;
}

再把if(rs1.next()&&rs2.next())判断条件多加两个

if (rs1!=null && rs1.next() && rs2!=null && rs2.next())
这样才有效果。