Domino 9 und frühere Versionen > ND6: Entwicklung
Java OutOfMemoryError
Marinero Atlántico:
--- Zitat von: qojote am 22.04.05 - 11:00:39 ---Hi,
ich hatte daselbe Problem wenn ich den die Sachen in den Agent als Attachement gepackt habe.
--- Ende Zitat ---
Guter Punkt :D
In deinem Programmverzeichnis müsste sich ein VErzeichnis java\lib\ext (oder so ähnlihc) befinden.
Tu da den DB2Treiber rein und starte den Notes Client neu.
Lösche dann den DB2Treiber aus dem Attachment und kompiliere neu.
birdy:
Yep, die Fehlermeldung ist immer noch die gleiche.
Die Vorgehensweise im Detail:
1. Der User gibt über eine Dialogbox eine Auftragsnr. ein.
2. Die Nr. wird in einem Profildokument gespeichert.
3. Der Java-Agent wird aufgerufen.
- bis hierher alles über LotusScript -
4. Der Agent liest die Nr. aus dem Profildokument aus.
5. Es wird über JDBC eine Verbindung zur DB2 aufgebaut.
6. SQL-Abfrage
7. Im RecordSet wird nach der Nr. gesucht.
8. Anhand der Auftragsnr. werden mehrere Daten aus der DB2 gefischt und in Variablen gespeichert.
9. Ein neues Notes-Document wird erstellt.
10. Die Daten werden an Felder im Notes-Doc übergeben.
11. Das Notes-Doc wird gespeichert.
12. Die JDBC-Verbindung wird gekappt.
13. Objekte werden recycelt und alles auf null gesetzt.
Hier nochmal der Code:
--- Code: ---import lotus.domino.*;
import java.sql.*;
import java.io.*;
import java.util.*;
public class JavaAgent extends AgentBase {
public void NotesMain() {
Database db = null;
Connection con = null;
try {
Session session = getSession();
AgentContext agentContext = session.getAgentContext();
db = agentContext.getCurrentDatabase();
Document doc = agentContext.getDocumentContext();
Document profildok = db.getProfileDocument("Profildok", "");
// Variablen deklarieren
String l_nr;
String l_artikel;
String l_stueck;
String l_text;
String l_termin;
boolean rc;
// Nr. aus Profildokument auslesen
l_nr = profildok.getItemValueString("Nr");
System.out.println("lfd.Nr. " + l_lfdnr);
PrintWriter pw = getAgentOutput();
// Connection con=null;
Statement stmt=null;
ResultSet rs=null;
String JDBCDriverName="com.ibm.as400.access.AS400JDBCDriver";
String system="Serverpfad/; libraries=libname";
String user = "username";
String pwd = "password";
DriverManager.registerDriver((Driver) Class.forName(JDBCDriverName).newInstance());
con = DriverManager.getConnection(system,user,pwd);
stmt = con.createStatement();
System.out.println("Connection hergestellt.");
// SQL-Abfrage
String sql = "SELECT feld1, feld2, feld3, feld4 FROM libname.tablename;
rs = stmt.executeQuery(sql);
// prüfen ob rs leer ist
rc = rs.next();
if (rc) {
// Felder auslesen
System.out.println("RS gefüllt");
l_nr = rs.getString(1);
l_artikel = rs.getString(2);
l_stueck = rs.getString(3);
l_termin = rs.getString(4);
l_text = rs.getString(5);
}
else {
// Leerstring
System.out.println("RS leer");
l_nr = "";
l_artikel = "";
l_stueck = "";
l_termin = "";
l_text = "";
};
// Anzahl der Zeichen zählen, wenn < 0 ist Leerstring
int l_zeichen = l_artikel.length();
System.out.println("Zeichen " + l_zeichen);
boolean z = (l_zeichen > 0);
if (z) {
// neues Dokument anlegen
doc = db.createDocument();
doc.appendItemValue("Form", "maskenname");
System.out.println("Dok. angelegt.");
// Felder im Dokument füllen
doc.appendItemValue("Nr", l_nr);
doc.appendItemValue("Artikel", l_artikel);
doc.appendItemValue("Stueck", l_stueck);
doc.appendItemValue("Termin", l_termin);
doc.appendItemValue("Text", l_text);
// Dokument speichern
doc.save(true, true);
}
else {
System.out.println("Kein Dokument angelegt.");
}
// Close statement and connection
rs.close();
stmt.close();
con.close();
// alles bereinigen
profildok.recycle();
doc.recycle();
rs = null;
stmt = null;
con = null;
System.gc();
} //end try
catch (Exception e) {
e.printStackTrace();
if (con != null)
try{
con.close();
} catch (SQLException sqle) {
}
}
}
}
--- Ende Code ---
birdy:
@marinero atlantico
das Verzeichnis hab ich.
nur, was meinst du mit Attachment?
und, müsste dann jeder user der die db nutzt diesen treiber im verzeichnis stehen haben? fürchte da spielt mein admin nicht mit.
Marinero Atlántico:
Das die fEhlermeldung kommt verstehe ich nicht, aber es fehlte die Klammerung nach dem if in der catch clause. Mit // NEU gekennzeichnet.
--- Code: ---import lotus.domino.*;
import java.sql.*;
import java.io.*;
import java.util.*;
public class JavaAgent extends AgentBase {
public void NotesMain() {
Database db = null;
Connection con = null;
try {
Session session = getSession();
AgentContext agentContext = session.getAgentContext();
db = agentContext.getCurrentDatabase();
Document doc = agentContext.getDocumentContext();
Document profildok = db.getProfileDocument("Profildok", "");
// Variablen deklarieren
String l_nr;
String l_artikel;
String l_stueck;
String l_text;
String l_termin;
boolean rc;
// Nr. aus Profildokument auslesen
l_nr = profildok.getItemValueString("Nr");
System.out.println("lfd.Nr. " + l_lfdnr);
PrintWriter pw = getAgentOutput();
// Connection con=null;
Statement stmt=null;
ResultSet rs=null;
String JDBCDriverName="com.ibm.as400.access.AS400JDBCDriver";
String system="Serverpfad/; libraries=libname";
String user = "username";
String pwd = "password";
DriverManager.registerDriver((Driver) Class.forName(JDBCDriverName).newInstance());
con = DriverManager.getConnection(system,user,pwd);
stmt = con.createStatement();
System.out.println("Connection hergestellt.");
// SQL-Abfrage
String sql = "SELECT feld1, feld2, feld3, feld4 FROM libname.tablename;
rs = stmt.executeQuery(sql);
// prüfen ob rs leer ist
rc = rs.next();
if (rc) {
// Felder auslesen
System.out.println("RS gefüllt");
l_nr = rs.getString(1);
l_artikel = rs.getString(2);
l_stueck = rs.getString(3);
l_termin = rs.getString(4);
l_text = rs.getString(5);
}
else {
// Leerstring
System.out.println("RS leer");
l_nr = "";
l_artikel = "";
l_stueck = "";
l_termin = "";
l_text = "";
};
// Anzahl der Zeichen zählen, wenn < 0 ist Leerstring
int l_zeichen = l_artikel.length();
System.out.println("Zeichen " + l_zeichen);
boolean z = (l_zeichen > 0);
if (z) {
// neues Dokument anlegen
doc = db.createDocument();
doc.appendItemValue("Form", "maskenname");
System.out.println("Dok. angelegt.");
// Felder im Dokument füllen
doc.appendItemValue("Nr", l_nr);
doc.appendItemValue("Artikel", l_artikel);
doc.appendItemValue("Stueck", l_stueck);
doc.appendItemValue("Termin", l_termin);
doc.appendItemValue("Text", l_text);
// Dokument speichern
doc.save(true, true);
}
else {
System.out.println("Kein Dokument angelegt.");
}
// Close statement and connection
rs.close();
stmt.close();
con.close();
// alles bereinigen
profildok.recycle();
doc.recycle();
rs = null;
stmt = null;
con = null;
System.gc();
} //end try
catch (Exception e) {
e.printStackTrace();
if (con != null) { //NEU NEU NEU (die Klammer)
try{
con.close();
} catch (SQLException sqle) {
}
}
}
}
--- Ende Code ---
Kanns z.Zt. nicht ausprobieren.
Ja. Der Treiber müsste dann auf jeden Desktop deployed werden.
3-Tier Umgebungen sind mit Notes ein bischen nicht so gut.
Marinero Atlántico:
Hier zu später Stunde noch das versprochene verbesserte ExceptionHandling:
Über
--- Code: ---catch (Exception e)
--- Ende Code ---
das hier:
--- Code: ---catch(SQLException sqlEx)
{
while(sqlEx != null) {
System.err.println("SQLException information");
System.err.println("Error msg: " + sqlEx.getMessage());
System.err.println("SQLSTATE: " + sqlEx.getSQLState());
System.err.println("Error code: " + sqlEx.getErrorCode());
sqlEx.printStackTrace();
sqlEx=sqlEx.getNextException();
}
}
--- Ende Code ---
Falls es Probleme mit dem SQL gibt, erhält man so alle wichtigen Fehlerinformationen. Über SQLState und ErrorCode bekommt man aus der DB2 Doku direkt raus, woran es hakt. Meistens ist bei mir das SQL-Statement doch nicht so richtig (bei mir zumindest)
Btw. bringt System.gc() fast nie etwas.
Ausserdem solltest du PreparedStatement statt Statement verwenden. Das macht den Code oft sicherer und vielleicht können so auch die Ausführungspfade von SQL-Statements auf DB2 gecached werden (die Regeln habe ich immer noch nicht so richtig verstanden). JDBC läuft immer über sogenanntes "dynamisches SQL" und da wird auf DB2 immer zuerst der "Ausführungsplan" errechnet und das nimmt Zeit in Anspruch. Bei einfachen SQL aber im Milisekundenbereich.
Warum diese komische Konstruktion mit connection noch mal in catch schliessen?
Oben öffnest du eine Datenbank-Connection. Das ist eine knappe Ressource. Wenn nun in dem Code des try-Blocks an irgend einer Stelle eine Exception auftritt, wechselt das Programm direkt in den catch-Block und kommt nie wieder in den try zurück. Die Connection muß aber geschlossen werden. So muß man das eben im catch auch noch machen. Und dieses Statement muß wiederum mit try-catch umgeben werden, da connection.close() eine SQLException wirft.
Das sind all diese kleinen JDBC-Basics.
In der realen Java-Welt ist JDBC Programmierung mittlerweile ziemlich selten. Die Leute benutzen irgendwelche Frameworks und Objekt-Relationalen-Mapper wie Hibernate.
Ich hab hier z.B. ein Framework namens IBAtis SQLMaps und da stehen die ganzen SQL-Queries gar nicht mehr im Source-Code sondern werden per xml definiert:
Sieht ungefähr so aus:
Als Beispiel steht ein solcher sql-query in einer xml-Datei (mit den entsprechenden Datentypen die übergeben und zurückgegeben werden:
--- Code: ---<select id="getIdByIdUserAndIdStockDescr"
parameterClass="java.util.HashMap" resultClass="java.lang.Long">
Select ID from STockUser where IDUSER=#idUser# AND IDStockDescr=#idStockDescr#
</select>
--- Ende Code ---
Wird dann einfach so in einem sogenannten DataAcces Object aufgerufen und ich spar mir den ganzen restlichen Quatsch. Den Rest macht das Framework. Hier lass ich mir nur eine ID als Long zurückgeben. Ganze Objekte geht aber auch. Auch als Collection.
--- Code: ---public StockUser getStockUserByIdUserAndIdStockDescr(long idUser, int idStockDescr) throws IllegalArgumentException {
if (idUser < 0) throw new IllegalArgumentException("Parameter idUser cannot be lower than 0");
if (idStockDescr < 0) throw new IllegalArgumentException("Parameter idStockDescr cannot be lower than 0");
Map params = new HashMap();
params.put("idUser", new Long(idUser));
params.put("idStockDescr", new Long(idStockDescr));
return (StockUser)getSqlMapClientTemplate().queryForObject("getStockUserByIdUserAndIdStockDescr", params);
}
--- Ende Code ---
Leider kann man mit Notes solche schönen Sachen nur unter ziemlichen Verrenkungen schwer verwenden.
Navigation
[0] Themen-Index
[#] Nächste Seite
[*] Vorherige Sete
Zur normalen Ansicht wechseln