פורסם 2011 ביוני 914 שנים שלום רבאנחנו צריכים לכתוב אתר אינטרנט(אפליקצית מייל פשוטה) יש כמובן שימוש בהתחברות למסד נתוניםלשם הנוחות יצרתי מחלקה (שהיא סינגלטון כי ממה שהבנתי היא צריכה להיות מוגדרת רק פעם אחת) שתפקידה הוא ליצור קשר למסד הנתונים ולאחר מכן אני יכול לשלוח לאובייקט הנ"ל שאילתות והוא יחזיר לי את הרשימות המבוקשות(SELECT...) או יוסיף דברים חדשים(INSERT) הבעיה הכי גדולה שיש בעיה בהתנתקות של חלק מהשדות של האובייקטולכן נוצרות לי מלא חריגותתיאור החריגות:SEVERE: Servlet.service() for servlet Inbox threw exceptioncom.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 Internet.DbManager.getResultSet(DbManager.java:76) at Internet.Inbox.showIndox(Inbox.java:116) at Internet.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);
פורסם 2011 ביוני 914 שנים אתה יוצר את stmt רק פעם אחת (בקונסטרקטור של DbManager) אבל עושה לו close כל פעם שהקוד של הסרבלט רץ.... אין בזה הרבה הגיון. חוץ מזה, ברגע שאתה שומר את stmt כאיבר של DbManager אתה לחלוטין מונע מהרצת שתי שאילתות ל-DB במקביל (כי ל-Statement אחד מותר לשייך רק ResultSet אחד בכל רגע נתון).המימוש שלך של סינגלטון לא נכון (לא מערבבים בין static וסינגלטון - בשביל לבנות סינגלטון עושים קלאס רגיל לחלוטין, שהקונסטרקטורים שלו הם פרטיים ורק הפונקציה getInstance והאיבר MyDbManagerInstance הם static).
פורסם 2011 ביוני 914 שנים מחבר אני רוצה שרק האובייקט הזה יקשר למסד הנתונים(פעם אחת) ורק הוא שיפנה למסד לקבלת רשומות או להוספת/שינויים של הטבלאות(ע"י שליחה של משפטי SQL) איך אני מתקן את האובייקט כך שיוכל להריץ שתי שאילתות במקביל?בגלל שרציתי שconnection יוגדר רק פעם אחת ממשתי אותו כסינגלטון, בכל מקרה אתה חושב שעדיין צריך להשתמש בסינגלטון? ואיפה אני אמור לשמור את הSTATEMENT, ממה שקראתי אחרי שעושים לו סגירה אי אפשר כבר להשתמש בותודה על העזרה
פורסם 2011 ביוני 914 שנים סינגלטון זה רעיון טוב, רק אמרתי שאין צורך לערבב סינגלטון ו-static.מי שמחזיק את ה-ResultSet צריך להחזיק גם את ה-Statement. בשביל זה יש כמה אפשרויות:- אתה יכול להחזיר מ-DbManager.getResultSet אובייקט שיחזיק גם את ה-Statment וגם את ה-ResultSet. לאובייקט הזה תהיה פונקצית סגירה שתסגור את שניהם יחד (במקום שהפונקציה הזו תהיה ב-DbManager).- אתה יכול ש-DbManager.getResultSet יחזיר רק את ה-Statement ולא את ה-ResultSet עצמו, ואז תוכל לקבל את ה-ResultSet ממנו (באמצעות executeQuery כמו שעשית, או שה-DbManager יפעיל את execute ואז תקבל את ה-ResultSet מה-Statement באמצעות המתודה שלו שנקראת getResultSet).
פורסם 2011 ביוני 914 שנים מחבר אתה מתכוון לשדות connection, statement? שהם לא יהיו סטטים?אם אני הולך על הפתרון השני, אני יוכל לייצר יותר מstatement אחד? אחרי הסגירה אני יוכל לעשות שוב stmt = con.createStatement();?ומה בעניין סגירת הResultSet, אני אצטרך לסגור אותו פר שאילתה שאני מפעיל, אני יכול אולי להוסיף פונקציה בDbManager שתסגור אותו?תודה על העזרה
פורסם 2011 ביוני 914 שנים אתה מתכוון לשדות connection, statement? שהם לא יהיו סטטים?בדיוק. חוץ מזה, כיוון ש-Statement הוא תקף רק לשאילתא אחת, אתה בכלל לא צריך לשמור אותו כשדה של ה-DbManager.אם אני הולך על הפתרון השני, אני יוכל לייצר יותר מstatement אחד? אחרי הסגירה אני יוכל לעשות שוב stmt = con.createStatement();?כמובן, למה שלא תוכל? זה ייצור לך פשוט Statement חדש לחלוטין.ומה בעניין סגירת הResultSet, אני אצטרך לסגור אותו פר שאילתה שאני מפעיל, אני יכול אולי להוסיף פונקציה בDbManager שתסגור אותו?את ה-ResultSet לא צריך לסגור - סגירת ה-Statement תדאג לסגור אותו אוטומטית.
פורסם 2011 ביוני 914 שנים מחבר הבנתי אותך, עוד שאלה קטנה אני רוצה לעשות פונקציה שתסגור את הstatement ותדאג שהיא תיהיה מכונה לקראת השאילתה הבאה:public void closingStatement(){ try{ if(stmt != null) { stmt.close(); stmt = null; }}catch (SQLException e) {} stmt = con.createStatement();}
פורסם 2011 ביוני 914 שנים א. למה שתרצה לעשות דבר כזה? תיצור Statement רק כשאתה צריך אותו.ב. אתה עדיין מחזיק את stmt כאיבר של ה-DbManager, מה שמונע משתי שאילתות לרוץ במקביל.
פורסם 2011 ביוני 1114 שנים מחבר יש לי שוב בעיה עם עניין החריגות, זה הקוד של הDbmanagerstatic 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 Internet.Inbox.showInboxCount(Inbox.java:100) at Internet.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)
פורסם 2011 ביוני 1114 שנים פשוט התעלמת מההצעות שלי לפתרון...למה stmt הוא איבר של DbManager? למה אתה לא מחזיר את stmt ב-getResultSet?
פורסם 2011 ביוני 1114 שנים מחבר כנראה שלא הבנתי את הפתרון(ות) שהצעת, STMT הוא איבר של DbManager בגלל שאני מפעיל שאילתה (הוספה/ עדכון וכ"ו), כעקרון מה שאני רוצה לעשות כשאני עובד מול המסד, זה לקרוא לפונקציה instance (יוצר לי פעם אחת את ההתקשרות) ולאחר מכן להפעיל אזשהי שאילתה אחרי שאני מקבל את הResult set (בהנחה שאני מבצע שאילתת SELECT) ומעבד את כל הנתונים שקבלתי אני רוצה לסגור את הStatement ואז בפעם הבאה שאני יעבוד מול המסד לקרוא שוב getResultSet ושהיא תדאג ליצירת Statement חדש.אני מחזיר את stmt בשביל לבצע ממנו את השאילתה מבחוץ ואז אני סוגר אותו בשביל להיות מוכן לבצע את השאילתה הבאה
פורסם 2011 ביוני 1114 שנים הבעיה היא שאתה מאפשר שבכל רגע נתון יהיה רק Statement אחד (כי יש רק DbManager אחד). ה-DbManager לא צריך להחזיק אצלו את ה-Statement, אלא להחזיר אותו למי שקרא לפונקציה getResultSet (ואם אתה עושה את זה, אז לשנות את השם של הפונקציה למשהו יותר מדויק).
פורסם 2011 ביוני 1114 שנים מחבר תקן אותי אם אני טועה, הפתרון שלך הוא להוסיף עוד פונקציה 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 בשביל ליפות קצת את הקוד, בכל מקרה לזה התכוונת?
פורסם 2011 ביוני 1114 שנים כן, זה מה שהתכוונתי אליו.רק שים לב שב-closeStatement, אין שום משמעות לשורה st = null...
ארכיון
דיון זה הועבר לארכיון ולא ניתן להוסיף בו תגובות חדשות.