Servlets + DBVerbindung

Ellosum

Grünschnabel
Hey Leute,

ich bin grad dabei eine Web-Anwendung mit Servlets zu realisieren. Dabei habe ich ein ServletController, der bei jedem Request angesprochen wird, schaut in der URL u.a. welche Funktion angegeben wurde und instanziert dementsprechend eine normale Java-Klasse, die dann Methoden enthält. In diesen Klassen baue ich die Verbindung zur Datenbank auf und schließe sie nach Gebrauch wieder. In die init-Methode des Servlets kann ich dies nicht auslagern, da die Verbindung bei jedem Request eine andere sein kann. Also es gibt verschiedene Instanzen, die ihre eigene Datenbank haben und diese Information ist in der URL enthalten und kann sich bei jedem Request ändern.

Das Problem dabei ist nun, dass anscheinend DB-Verbindungen offen sind, da Oracle mir folgende Folgende Fehlermeldung mitteilt: Cannot open database.
java.sql.SQLException: ORA-00020: maximum number of processes (%s) exceeded


Ich hoffe, ich habe mich verständlich genug ausgedrückt. Falls nicht, fragt mich einfach!

Ich bin für jeden Hinweis dankbar..Habe das Problem bereits seit einigen Tagen :(
 
Zuletzt bearbeitet:

genodeftest

Erfahrenes Mitglied
Gibt es eine Möglichkeit, herauszufinden, wie viele DB-Verbindungen offen sind? Oder wie viele Prozesse/Threads auf dem System bereits laufen?

BTW: und überprüf mal deinen Code, ob du nicht irgendwo bei jedem DB-Zugriff eine neue Verbindung aufbaust / einen neuen Thread/Prozess erzeugst. An sonsten bräuchten wir wohl etwas Code, vermute ich mal.
 

Ellosum

Grünschnabel
Also, wenn ich mit ps -ef | grep pmon die offenen Prozesse mir anzeigen lasse bekomme ich folgende:

Code:
  oracle 15872     1  0 13:37:19 ?        0:00 ora_pmon_atvrsim
  oracle 15991     1  0 13:37:48 ?        0:00 ora_pmon_edr
  oracle 16136     1  0 13:38:16 ?        0:00 ora_pmon_sae
  oracle 15962     1  0 13:37:42 ?        0:00 ora_pmon_echit
  oracle 15814     1  0 13:37:04 ?        0:00 ora_pmon_atvest
  oracle 15930     1  0 13:37:33 ?        0:00 ora_pmon_dpp
  oracle 16078     1  0 13:38:04 ?        0:00 ora_pmon_iotars
  oracle 16020     1  0 13:37:53 ?        0:00 ora_pmon_emis
  oracle 15901     1  0 13:37:27 ?        0:00 ora_pmon_dmsr
  oracle 15785     1  0 13:36:59 ?        0:00 ora_pmon_tools
  oracle 15843     1  0 13:37:13 ?        0:00 ora_pmon_atvgsstf
cscadmin 18284 18206  0 11:06:18 pts/5    0:00 grep pmon
  oracle 16049     1  0 13:37:59 ?        0:00 ora_pmon_iot
  oracle 16205     1  0 13:38:43 ?        0:00 ora_pmon_vmk2
  oracle 16176     1  0 13:38:35 ?        0:00 ora_pmon_splc
  oracle 16107     1  0 13:38:10 ?        0:00 ora_pmon_iotts
Die Ausgabe verstehe ich nicht wirklich, außer das der cscadmin (ich) viel größere Zahlen als die anderen Instanzen aufweist. Das seltsame ist auch, wenn ich das Kommando öfter eingebe, ist cscadmin mal da und mal nicht.

Hier der Code:
SerlvetController
Java:
....
if (functionName.equals("saveDoc")) {
             SaveDocument save = new SaveDocument(instanceName);
             save.doRequest(request, response);

          }
.....

SaveDocument:
Java:
public class SaveDocument {
    ...
    	public SaveDocument(String instance) {
		this.instance = instance;

		config = new Configuration(instance);
		db = new Database(config);
	}

       public void doRequest(HttpServletRequest request, HttpServletResponse response)
	throws ServletException, IOException {
                 ...
                saveFile(request, response, out, instance);
                ....
       }
      
        private void saveFile(HttpServletRequest request,
			HttpServletResponse response, PrintWriter out, String instanceName)
			throws Exception {
           ....
          checkInsert = insertMetaData(contentType, size,
									fileName, userId, author, title, company,
									documentNo, descr);
           ........
        }

        private int insertMetaData(String format, long size, String fileName,
			String userId, String author, String title, String company,
			String documentNo, String descr) {

		java.util.Date date = new java.util.Date();
		Date sqlDate = new java.sql.Date(date.getTime());

		String revision = "non existent";
		int statusNo = 0;

		try {
			db.execute("LOCK TABLE documents IN EXCLUSIVE MODE");
			int documentId = getNextDocID();

			String insertData = "INSERT INTO documents ("
				+ "ID, TITLE, AUTHOR, USER_NAME, COMPANY, "
				+ "FILE_NAME, TYPE, FILE_SIZE, CREATED, REVISION, DOCUMENT_NUMBER, DESCRIPTION)"
					+ " VALUES (" + documentId + ", '"
									  + title + "', '"
								     + author + "', '"
							        + userId + "', '"
								     + company + "', '"
								     + fileName + "', '"
								     + format + "', "
								     + size + ", to_date('"
								     + sqlDate + "', 'yyyy/mm/dd'), '"
								     + revision + "', '"
								     + documentNo + "', '"
								     + descr + "')";

			statusNo = db.executeUpdate(insertData);
			db.commit();

		} catch (SQLException e) {
			e.printStackTrace();
			System.err.println("Error! Reason: " + e.toString());

		} finally {
			try {
				if (db != null) {
					db.closeDb();
					db = null;
					System.err.println("DB closed!");
				}
				System.err.println("DB closed 2!");
			} catch (SQLException e) {
				e.printStackTrace();
				System.err.println("Could not close data base! Reason: " + e.toString());
			}
		}
		return statusNo;

	}
}

Und die Database:
Java:
public class Database {
    public Database(Configuration configuration) {
      // Configuration parameters:
      this.configuration = configuration;

      String jdbcDsn    = configuration.value("SPR_JDBC_DSN");
      String dbName     = configuration.value("SPR_DB_NAME");
      String jdbcDbName = jdbcDsn + "@" + dbName;
      String dbUser     = configuration.value("SPR_DB_USER");
      String dbPassword = configuration.value("SPR_DB_PW");

      statement = null;
      connection = null;

      try {
      	System.err.println("Data base open!");
         Class.forName(configuration.value("SPR_JDBC_DRIVER"));
         if (connection == null) {
            connection      = DriverManager.getConnection(jdbcDbName, dbUser, dbPassword);
            statement       = connection.createStatement();
            updateStatement = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY,
                                                         ResultSet.CONCUR_UPDATABLE);
         }
      }
      catch (ClassNotFoundException classnotfoundexception) {
         System.err.println("JDBC-ODBC-Driver not found.");
      }
      catch (SQLException sqlexception) {
         System.err.println("Cannot open database.");
         sqlexception.printStackTrace();
      }
   }
   ......
     public Integer executeUpdate(String s)
          throws SQLException {
      return statement.executeUpdate(s);
   }
   ......
      public void closeDb()
          throws SQLException {
      statement.close();
      connection.close();
   	System.err.println("Data base close!");
   }
   .....
}

Ich erzeuge bei jeder Instanzierung der Database eine Verbindung (wenn ich das richtig verstehe), die ich am Ende auch wieder schließe. Kann das zum Problem führen?
 

Ellosum

Grünschnabel
Vielen Dank für den Tipp!
Mein Programm/Anwendung wird ja mit dem ServletController gestartet. Dabei instanziert der Container (Tomcat) zu Anfang ein Objekt der Klasse und danach bei jedem Request einen neuen Thread. Wenn ich nun mit Hilfe des Singleton meine Verbindung in dem ServletController aufbaue, ist mir die Anzahl der Threads ja unbekannt.
Die Frage stellt sich mir dann, wann schließe ich die Verbindung? Ich weiß grad auch nicht wann der Container bzw. JVM die ganzen Threads aufräumt.
Was mir gerade eingefallen ist: Das Servlet hat eine Destroy-Methode die am Ende des Lebenszyklus ausgeführt wird. Theoretisch könnte ich doch dann dort meine Verbindung schließen, oder **** Das würde dazu führen, dass all meine Klassen die gleiche Verbindung nutzen.
 
Zuletzt bearbeitet:

Ellosum

Grünschnabel
Ne, das geht auch nicht was ich grade von mir gegeben habe. Beim Servlet wird zu Anfang die config-Methode aufegrufen, wo man theoretisch den Verbindungsaufbau erstellen könnte. Das Problem bei meiner Anwendung ist, dass die DB-Instanz bei jedem Request ändern kann. Somit kommt config nicht in Frage. Also nützt mir das Singelton auch nichts.
Ich muss also die Verbindung in der service-Methode (doGet, doPost) erstellen, was aber dazu führt das mehrere Verbindungen existieren..Zum verrückt werden :(
 

Ellosum

Grünschnabel
Gibt es sonst keine Vorschläge****
Bin echt am verzweifeln :(

Übrigens kann ich mir nun die aktuelle Prozesse in Oracle ausgeben lassen mit select count(*) from V$PROCESS;
und da sehe ich deutlich, dass bei jeder Aktion eine neue DB-Verbindung erzeugt wird. Nur weiß ich nicht, wie ich das Problem lösen kann..
 

wakoz

Erfahrenes Mitglied
Datenbanken sind nicht Meins aber soweit ich das sehe und verstehe ist dein Problem nicht Java und Db, sondern alleine die DB Konfiguration Versuch mal den Prozess Counter hoch zu schrauben. Google sollte helfen ;)
 

Ellosum

Grünschnabel
Danke, aber die Anzahl der Prozesse zu erhöhen löst nicht das Problem.Lediglich verzögert es, denn die Verbindungen werden nicht geschlossen.
Ich schließe nun meine Verbindungen früher, und siehe da die Verbindungen werden auch richtig geschlossen;) Ich weiß allerdings nicht, warum es nicht im finally-block funktioniert hat.