בעיה בסגירת הstatement ,resultset בJAVA - תכנות - HWzone פורומים
עבור לתוכן
  • צור חשבון

בעיה בסגירת הstatement ,resultset בJAVA


jeet87

Recommended Posts

שלום רב

אנחנו צריכים לכתוב אתר אינטרנט(אפליקצית מייל פשוטה) יש כמובן שימוש בהתחברות למסד נתונים

לשם הנוחות יצרתי מחלקה (שהיא סינגלטון כי ממה שהבנתי היא צריכה להיות מוגדרת רק פעם אחת) שתפקידה הוא ליצור קשר למסד הנתונים ולאחר מכן אני יכול לשלוח לאובייקט הנ"ל שאילתות והוא יחזיר לי את הרשימות המבוקשות(SELECT...) או יוסיף דברים חדשים(INSERT) הבעיה הכי גדולה שיש בעיה בהתנתקות של חלק מהשדות של האובייקט

ולכן נוצרות לי מלא חריגות

תיאור החריגות:

SEVERE: Servlet.service() for servlet Inbox threw exception

com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransient ConnectionException: No operations allowed after statement closed.

at sun.reflect.NativeConstructorAccessorImpl.newInst ance0(Native Method)

at sun.reflect.NativeConstructorAccessorImpl.newInst ance(NativeConstructorAccessorImpl.java:39)

at sun.reflect.DelegatingConstructorAccessorImpl.new Instance(DelegatingConstructorAccessorImpl.java:27)

at java.lang.reflect.Constructor.newInstance(Constructor.java:513)

at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)

at com.mysql.jdbc.Util.getInstance(Util.java:386)

at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1013)

at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:987)

at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:982)

at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:927)

at com.mysql.jdbc.StatementImpl.checkClosed(StatementImpl.java:436)

at com.mysql.jdbc.StatementImpl.executeQuery(StatementImpl.java:1375)

at .DbManager.getResultSet(DbManager.java:76)

at .Inbox.showIndox(Inbox.java:116)

at .Inbox.doPost(Inbox.java:46)

at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)

at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)

at org.apache.catalina.core.ApplicationFilterChain.i nternalDoFilter(ApplicationFilterChain.java:269)

at org.apache.catalina.core.ApplicationFilterChain.d oFilter(ApplicationFilterChain.java:188)

at org.apache.catalina.core.StandardWrapperValve.inv oke(StandardWrapperValve.java:213)

at org.apache.catalina.core.StandardContextValve.inv oke(StandardContextValve.java:172)

at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)

at org.apache.catalina.valves.ErrorReportValve.invok e(ErrorReportValve.java:117)

at org.apache.catalina.core.StandardEngineValve.invo ke(StandardEngineValve.java:108)

at org.apache.catalina.connector.CoyoteAdapter.servi ce(CoyoteAdapter.java:174)

at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:879)

at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:665)

at org.apache.tomcat.util.net.PoolTcpEndpoint.proces sSocket(PoolTcpEndpoint.java:528)

at org.apache.tomcat.util.net.LeaderFollowerWorkerTh read.runIt(LeaderFollowerWorkerThread.java:81)

at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:689)

at java.lang.Thread.run(Thread.java:662)


להלן הקוד של האובייקט:


[code]

public class DbManager {
static private Connection con = null;
static private Statement stmt = null;
static private DbManager MyDbManagerInstance = null;






static public DbManager instance() {
if (MyDbManagerInstance == null) {
try {
MyDbManagerInstance = new DbManager();
} catch (ServletException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return MyDbManagerInstance;
}


static void closeResultSet(ResultSet rs)
{
try {
if(stmt != null) {
stmt.close();
stmt = null;
}


if(rs != null) {
rs.close();
rs = null;
}
} catch (SQLException e) {}
}





private DbManager() throws ServletException, IOException {

try {
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection(
"-------", "----", "----");
stmt = con.createStatement();
} catch (SQLException e) {
throw new ServletException("Servlet Could not display records.", e);
} catch (ClassNotFoundException e) {
throw new ServletException("JDBC Driver not found.", e);
}
finally{
//closeConnection();
}
}


public ResultSet getResultSet(String query) throws ServletException,
IOException
{

ResultSet rs=null;

try {
rs = stmt.executeQuery(query);
} catch (SQLException e) {
throw new ServletException("Servlet Could not display records.", e);
}


return (rs);
}


public void updateTable(String query) throws ServletException,
IOException {

try {
stmt = con.createStatement();
stmt.execute(query);
}
catch (SQLException e) {
throw new ServletException("Servlet Could not update records.", e);
}


}


public void closeConnection()
{
try {

if(stmt != null) {
stmt.close();
stmt = null;
}
if(con != null) {
con.close();
con = null;
}
} catch (SQLException e) {}
}


}


והקוד בJSP



DbManager db = DbManager.instance();
ResultSet rsCount = db.getResultSet("Select count(Pid) from mails ,mails_to_users mtu where mtu.mailId=mails.mailId and mtu.reciverLabel='Inbox' and mtu.userName='"+user+"'");
rsCount.next();
....
DbManager.closeResultSet(rsCount);

קישור לתוכן
שתף באתרים אחרים

אתה יוצר את stmt רק פעם אחת (בקונסטרקטור של DbManager) אבל עושה לו close כל פעם שהקוד של הסרבלט רץ.... אין בזה הרבה הגיון. חוץ מזה, ברגע שאתה שומר את stmt כאיבר של DbManager אתה לחלוטין מונע מהרצת שתי שאילתות ל-DB במקביל (כי ל-Statement אחד מותר לשייך רק ResultSet אחד בכל רגע נתון).

המימוש שלך של סינגלטון לא נכון (לא מערבבים בין static וסינגלטון - בשביל לבנות סינגלטון עושים קלאס רגיל לחלוטין, שהקונסטרקטורים שלו הם פרטיים ורק הפונקציה getInstance והאיבר MyDbManagerInstance הם static).

קישור לתוכן
שתף באתרים אחרים

אני רוצה שרק האובייקט הזה יקשר למסד הנתונים(פעם אחת) ורק הוא שיפנה למסד לקבלת רשומות או להוספת/שינויים של הטבלאות(ע"י שליחה של משפטי SQL) איך אני מתקן את האובייקט כך שיוכל להריץ שתי שאילתות במקביל?

בגלל שרציתי שconnection יוגדר רק פעם אחת ממשתי אותו כסינגלטון, בכל מקרה אתה חושב שעדיין צריך להשתמש בסינגלטון? ואיפה אני אמור לשמור את הSTATEMENT, ממה שקראתי אחרי שעושים לו סגירה אי אפשר כבר להשתמש בו

תודה על העזרה

קישור לתוכן
שתף באתרים אחרים

סינגלטון זה רעיון טוב, רק אמרתי שאין צורך לערבב סינגלטון ו-static.

מי שמחזיק את ה-ResultSet צריך להחזיק גם את ה-Statement. בשביל זה יש כמה אפשרויות:

- אתה יכול להחזיר מ-DbManager.getResultSet אובייקט שיחזיק גם את ה-Statment וגם את ה-ResultSet. לאובייקט הזה תהיה פונקצית סגירה שתסגור את שניהם יחד (במקום שהפונקציה הזו תהיה ב-DbManager).

- אתה יכול ש-DbManager.getResultSet יחזיר רק את ה-Statement ולא את ה-ResultSet עצמו, ואז תוכל לקבל את ה-ResultSet ממנו (באמצעות executeQuery כמו שעשית, או שה-DbManager יפעיל את execute ואז תקבל את ה-ResultSet מה-Statement באמצעות המתודה שלו שנקראת getResultSet).

קישור לתוכן
שתף באתרים אחרים

אתה מתכוון לשדות connection, statement? שהם לא יהיו סטטים?

אם אני הולך על הפתרון השני, אני יוכל לייצר יותר מstatement אחד? אחרי הסגירה אני יוכל לעשות שוב




stmt = con.createStatement();

?ומה בעניין סגירת הResultSet, אני אצטרך לסגור אותו פר שאילתה שאני מפעיל, אני יכול אולי להוסיף פונקציה בDbManager שתסגור אותו?

תודה על העזרה

קישור לתוכן
שתף באתרים אחרים

אתה מתכוון לשדות connection, statement? שהם לא יהיו סטטים?

בדיוק. חוץ מזה, כיוון ש-Statement הוא תקף רק לשאילתא אחת, אתה בכלל לא צריך לשמור אותו כשדה של ה-DbManager.

אם אני הולך על הפתרון השני, אני יוכל לייצר יותר מstatement אחד? אחרי הסגירה אני יוכל לעשות שוב




stmt = con.createStatement();

?

כמובן, למה שלא תוכל? זה ייצור לך פשוט Statement חדש לחלוטין.

ומה בעניין סגירת הResultSet, אני אצטרך לסגור אותו פר שאילתה שאני מפעיל, אני יכול אולי להוסיף פונקציה בDbManager שתסגור אותו?

את ה-ResultSet לא צריך לסגור - סגירת ה-Statement תדאג לסגור אותו אוטומטית.

קישור לתוכן
שתף באתרים אחרים

הבנתי אותך, עוד שאלה קטנה אני רוצה לעשות פונקציה שתסגור את הstatement ותדאג שהיא תיהיה מכונה לקראת השאילתה הבאה:


public void closingStatement(){
try{
if(stmt != null) {
stmt.close();
stmt = null;
}
}catch (SQLException e) {}


stmt = con.createStatement();
}

קישור לתוכן
שתף באתרים אחרים

יש לי שוב בעיה עם עניין החריגות, זה הקוד של הDbmanager




static public DbManager instance() {
if (MyDbManagerInstance == null) {
try {
MyDbManagerInstance = new DbManager();
} catch (ServletException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return MyDbManagerInstance;
}

void closeStatement()
{
try {
if(stmt != null) {
stmt.close();
stmt = null;
}
} catch (SQLException e) {}
}







private DbManager() throws ServletException, IOException {

try {
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection(
"-----", "----", "-----");
} catch (SQLException e) {
throw new ServletException("Servlet Could not display records.", e);
} catch (ClassNotFoundException e) {
throw new ServletException("JDBC Driver not found.", e);
}
finally{
//closeConnection();
}
}




public ResultSet getResultSet(String query) throws ServletException,IOException, SQLException
{
stmt = con.createStatement();
ResultSet rs=null;

try {
rs = stmt.executeQuery(query);
} catch (SQLException e) {
throw new ServletException("Servlet Could not display records.", e);
}




return (rs);
}





public void updateTable(String query) throws ServletException,IOException, SQLException
{
stmt = con.createStatement();
try {
stmt = con.createStatement();
stmt.execute(query);
}
catch (SQLException e) {
throw new ServletException("Servlet Could not update records.", e);
}




}




עכשיו יש לי סרבלט אחר ששם יש את הקוד הבא:








DbManager db = DbManager.instance();
ResultSet rsMail = db.getResultSet("Select * from mails ,mails_to_users mtu where mtu.mailId=mails.mailId and mtu.reciverLabel='Inbox' and mtu.userName='"+user+"' Limit "+(numPage-1)*numMails+","+numMails);
while(rsMail.next())
{
//פה אני מעבד את הנתונים שקבלתי
}
db.closeStatement();

תיאור החריגה:




java.sql.SQLException: Operation not allowed after ResultSet closed
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1073)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:987)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:982)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:927)
at com.mysql.jdbc.ResultSetImpl.checkClosed(ResultSetImpl.java:794)
at com.mysql.jdbc.ResultSetImpl.next(ResultSetImpl.java:7139)
at .Inbox.showInboxCount(Inbox.java:100)
at .Inbox.doPost(Inbox.java:75)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.i nternalDoFilter(ApplicationFilterChain.java:269)
at org.apache.catalina.core.ApplicationFilterChain.d oFilter(ApplicationFilterChain.java:188)
at org.apache.catalina.core.StandardWrapperValve.inv oke(StandardWrapperValve.java:213)
at org.apache.catalina.core.StandardContextValve.inv oke(StandardContextValve.java:172)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invok e(ErrorReportValve.java:117)
at org.apache.catalina.core.StandardEngineValve.invo ke(StandardEngineValve.java:108)
at org.apache.catalina.connector.CoyoteAdapter.servi ce(CoyoteAdapter.java:174)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:879)
at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:665)
at org.apache.tomcat.util.net.PoolTcpEndpoint.proces sSocket(PoolTcpEndpoint.java:528)
at org.apache.tomcat.util.net.LeaderFollowerWorkerTh read.runIt(LeaderFollowerWorkerThread.java:81)

at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:689)

at java.lang.Thread.run(Thread.java:662)

קישור לתוכן
שתף באתרים אחרים

כנראה שלא הבנתי את הפתרון(ות) שהצעת, STMT הוא איבר של DbManager בגלל שאני מפעיל שאילתה (הוספה/ עדכון וכ"ו),

כעקרון מה שאני רוצה לעשות כשאני עובד מול המסד, זה לקרוא לפונקציה instance (יוצר לי פעם אחת את ההתקשרות) ולאחר מכן להפעיל אזשהי שאילתה אחרי שאני מקבל את הResult set (בהנחה שאני שאילתת SELECT) ומעבד את כל הנתונים שקבלתי אני רוצה לסגור את הStatement ואז בפעם הבאה שאני יעבוד מול המסד לקרוא שוב getResultSet ושהיא תדאג ליצירת Statement חדש.

אני מחזיר את stmt בשביל לבצע ממנו את השאילתה מבחוץ ואז אני סוגר אותו בשביל להיות מוכן לבצע את השאילתה הבאה

קישור לתוכן
שתף באתרים אחרים

הבעיה היא שאתה מאפשר שבכל רגע נתון יהיה רק Statement אחד (כי יש רק DbManager אחד). ה-DbManager לא צריך להחזיק אצלו את ה-Statement, אלא להחזיר אותו למי שקרא לפונקציה getResultSet (ואם אתה עושה את זה, אז לשנות את השם של הפונקציה למשהו יותר מדויק).

קישור לתוכן
שתף באתרים אחרים

תקן אותי אם אני טועה, הפתרון שלך הוא להוסיף עוד פונקציה getStat


public Statement getStat()
{
return(con.createStatement());
}


//for closing statement
void closeStatement(Statement st)
{
try {
if(st!= null) {
st.close();
st= null;
}
} catch (SQLException e) {}
}


ואיפה שאני צריך להפעיל שאילתה אז אני את הקוד הבא:


DbManager db = DbManager.instance();
Statement smt = db.getStat();

ResultSet rs=null;
try {
rs = smt.executeQuery(query);
} catch (SQLException e) {
throw new ServletException("Servlet Could not display records.", e);
}
db.closeStatement(smt);

אני בכוונה רוצה לכתוב פונקציה שתסגור את הStatement בשביל ליפות קצת את הקוד, בכל מקרה לזה התכוונת?

קישור לתוכן
שתף באתרים אחרים

ארכיון

דיון זה הועבר לארכיון ולא ניתן להוסיף בו תגובות חדשות.

×
  • צור חדש...