一个困扰了我一个多月的问题,关于空指针的。。。请教各位老大。。。
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())
这样才有效果。