JNDI & Pooling gleichzeitig mit Java nutzen

Hi leutz,

ich will seit geraumer Zeit mit PostgreSQL 8.3 und dem JDBC-Treiber in V3 auf meine Datenbank verbinden. Aber nicht irgend wie! Dies soll über JNDI & Pooling der Connections funktionieren. Alles andere hab ich soweit geschafft, nur daran bin ich gescheitert. Nach meiner Quellcode-Analyse liegt das Problem beim Binden(rebind) der PoolingSource mit dem Namen “jdbc/dataSource”.

Compiler: JBuilder 2008
JDBC-Treiber(dieser wurde im Build-Path als JAR hinterlegt)**:**http://jdbc.postgresql.org/download/postgresql-8.3-604.jdbc3.jar


package test.jdbc;

import java.sql.Connection;
import java.sql.SQLException;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.postgresql.ds.PGPoolingDataSource;
import sun.jdbc.odbc.ee.DataSource;

public class ConnectionManagerByJDNC {

    public static void main(String[] args) {
        PGPoolingDataSource poolSource = new PGPoolingDataSource();
        poolSource.setDataSourceName("A Data Source");
        poolSource.setServerName("localhost");
        poolSource.setDatabaseName("NES2");
        poolSource.setUser("NES_User");
        poolSource.setPassword("DenkDirEinesAus");
        poolSource.setMaxConnections(10);
        
        SqlErrorHandler innerErrorHandyler= new SqlErrorHandler();
        
        Connection conn = null;
        try {
            new InitialContext().rebind("jdbc/dataSource", poolSource);
//            DataSource source = (DataSource)new InitialContext().lookup("DataSource");
//            conn = source.getConnection();
//        } catch (SQLException e) {
//            innerErrorHandyler.PrintSQLError(e);
        } catch (NamingException e) {
            System.err.println("Error: Es ist ein unbekannter Fehler aufgetreten.");
            System.err.println("===========================");
            e.printStackTrace();
        } finally {
            if (conn != null) {
                try { conn.close(); } catch (SQLException e) {}
            }
        }

    }
}

Fehlermeldung:

Error: Es ist ein unbekannter Fehler aufgetreten.
===========================
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file:  java.naming.factory.initial
    at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:645)
    at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:247)
    at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:284)
    at javax.naming.InitialContext.rebind(InitialContext.java:367)
    at test.jdbc.ConnectionManagerByJDNC.main(ConnectionManagerByJDNC.java:40)

Was ich schon zu rate gezogen habe:

Die Quellen haben mir in dem Fall leider nicht weiter geholfen oder ich haben einfach was wichtiges überlesen was druchaus sein kann.
Ich hoffe ihr wisst Rat, schon mal Danke im Vorraus.
Ist sicher peinlich einfach … . :rolleyes:

Also wenn Du eine Webapplication mit Tomcat machen willst dann kannst Du den eingebauten Connectionpooler von Tomcat (DBCP) einfach benutzen (aus meiner Sicht sowieso der beste für Tomcat den es gibt).

In deine Context.xml Datei trägst Du folgendes ein

<?xml version="1.0" encoding="UTF-8"?>

<Resource name=“jdbc/postgres” auth=“Container”
type=“javax.sql.DataSource” driverClassName=“org.postgresql.Driver”
url=“jdbc > :p > ostgresql://127.0.0.1:5432/meineDB”
username=“benutzer” password=“geheim” maxActive=“20” maxIdle=“10”
maxWait="-1" removeAbandoned="true"removeAbandonedTimeout=“60” />

Damit hat deine WebApp von jeder JSP oder jedem Bean aus direkt Zugriff auf das DB Connectionobjekt und so kann Du es für SQL-Abfragen verwenden.

// loads User Accountdata
public info getUserInfo(int aic) throws Exception {
javax.naming.InitialContext context = new InitialContext();
javax.sql.DataSource dataSource =
(javax.sql.DataSource) context.lookup(“java:comp/env/jdbc/postgres”);
java.sql.Connection conn = dataSource.getConnection();

String select =
"SELECT " +
" aic, nickname " +
"FROM " +
" webapp.account_main "+
“WHERE “+
" aic =’”+aic+”’ ";

info ui = new info();

PreparedStatement ps = conn.prepareStatement(select);
ResultSet result = ps.executeQuery();

if (result.next()) {
ui.uid = result.getInt(“aic”);
ui.nickname = result.getString(“nickname”);
} else {
ui.uid = 0;
}
return ui;
}

Tip: Wenn Performance wichtig für Dich ist und Dich das Thema DB
SoftwareRaids intressiert (Hochverfügbarkeit, Statementbased
Replication in Java) dann empfehle ich Dir mal Sequoia genauer
anzuschauen Sequoia: Check Out Our New Community Site!

Hi marc9022,

danke für deine antwort. Ich habe mich daraufhin nach SimpleJNDI umgesehen das funktioniert auch so wie im Buch “Java ist auch ein Insel” beschieben wurde und ist von der funktionalität sehr änhlich zu deiner Lösung.

Mich würde aber dennoch interessieren warum es nicht klappt.
Soweit ich heraus gefunden habe muss ich an der stelle ein SystemProperty namens “java.naming.factory.initial” setzen, welches als Wert eine Klassennamen bekommt. Leider weiß ich nicht welchen er bekommen muss, er sollte entweder ein Context und/oder Factory enthalten. Bin alle in Frage kommenden Klassennamen in des PostgreSQL-Treibers druchgegangen und habe diesen dort eingestetzt was aber leider nicht geklappt hat.

Soweit ich mitbekommen habe geht es auch anderen so JNDI & Others, ich will mich nicht nur von fremden JARs abhängig machen wenn es nicht umbedingt sein muss und laut der PostgreSQL-Dokumentation soll es ja auch so gehen!

Quelle: Verbindungspools und Data Sources

mfg shark1985

Hmm, also vielleicht solltest Du erstmal sagen ob Du nun einen
WebApplication oder ein Standalone (Swing/Commandline) Programm
schreibst. Für eine WebApplication macht es zu 99% Sinn einen
Connectionpooler zu verwenden, bei Clients die lange und persistente
Verbindungen zum Server aufbauen kann das auch schon mal
Kontraproduktiv sein.

@WebApp
Wenn Du mit Tomcat arbeitest (für Java WebApps der Standardfall)
dann ist der Weg so wie ich ihn skizziert habe der vorgesehen Weg
und Du benötigst keine separaten JARs, die bringt Tomcat schon
alle mit.

  1. Im Contextfile unter META-INF den JNDI Context einrichten
  2. Mit deinen Methoden wie oben beschrieben drauf zugreifen.

Ist eigentlich nicht so schwer. Wenn Du Dich aber mit exotischen,
nicht Standard konstrukten versuchen willst, wirds mit Sicherheit
auch nicht einfacher. Naja, musst Du wissen.

Hi,

es soll eine Swing-Anwendung werden, keine Web-Applikation.
Ich würde ja gern einen Standard verwenden aber Tomcat schein mit ehr was für Web-Anwendungen zu sein. Nur so neben bei, ich bin davon ausgegangen das ich das was in der PostgreSQL-Dokumentation lese als Standard werten kann und das es auch so funktioniert wie es dort steht. Ich bin gerne offen für Vorschläge, ich gehe mal davon aus das es noch weitere Standards gibt als den JNDI + ConnectionPooler von Tomcat.

Ist sowas vielleicht schon direkt im PostgreSQL-Treiber enthalten, nur das es mir noch nit aufgefallen ist!?

Ist eigentlich nicht so schwer. Wenn Du Dich aber mit exotischen,
nicht Standard konstrukten versuchen willst, wirds mit Sicherheit
auch nicht einfacher. Naja, musst Du wissen.

@marc9022
Welches von meinen beiden versuchen siehst du nicht als Standard an!?

  1. Den mit dem Problem beim rebind aus meinem ersten post, den ich aus der PostgreSQL-Dokumentation genommen habe?
  2. Simple JNDI der im Buch “Java ist auch eine Insel” aufgeführt wird?

mfg shark1985

Hallo!

Ich weiss nicht ob Du Dein Problem inzwischen gelöst hast.
Ich habe im Grunde ein ähnliches Problem wie Du. Bei mir geht es derzeit ebenfalls darum bei einer Standalone Anwendung (keine Webanwendung) ein Connection Pooling einzusetzen.
Auch bei Standalone Anwendungen ist es sinnvoll ein Connection Pool zu verwenden, da die Anfragen schneller abgearbeitet werden und man ja vielleicht auch mehrere DB-Abfragen parallel absenden möchte (mehrere Suchfenster in einer GUI-Anwendung um z.B. nach verschiedenen Filmen/Serien zu suchen --> JMDB).

Dabei gibt es wohl drei Möglichkeiten:

  1. JNDI & Pooling wie von Dir gestartet (aber eben mit einem integrierten JNDI --> Simple-JNDI wie in der Java Insel beschrieben). Galileo Computing :: Java ist auch eine Insel (8. Auflage) – 23.5 Mit Java an eine Datenbank andocken und Simple-JNDI - simple-jndi
  2. Die PostgreSQL Treiber Variante (Verbindungspools und Data Sources), die scheinbar nichts mit JNDI zu tun hat.
  3. den DbConnectionBroker als ConnectionPool Klasse von javaexchange (JavaExchange.com)

Letzteres ist schon recht alt und verwendet einfach ein Array mit mehreren Connection Objekten. Da wird auch kein JNDI verwendet, sondern wirklich direkt der DriverManager, der mehrere Connections rausrücken muss, die dann in diesem Connection Array landen. Min/Max Verbindungen und auch Timeouts können definiert werden.
Die Variante hatte ich selber schon im Einsatz und sie funktioniert.

Dennoch wollte ich mir nun auch mal ansehen ob ich nicht im aktuellen Projekt mal einen Versuch mit JNDI bzw. allgemein DataSource wagen sollte.
Das Problem ist, wie Du auch schon festgestellt hast, das es quasi nur noch Webanwendungen zu geben scheint und somit so gut wie alle Bespiele in diese Kategorie fallen.

Ich würde sagen die Variante 2 ohne InitialContext wäre das.

und bau es selbst … dann bekommst du etwas gescheites

man man … so trivialitaeten …

aufwand: ein launiger nachmittag … + paar einheiten bis es zuverlaessig ist (je nach erfahrung dauert das halt kuerzer)

p.s. oft findet man pooling-snipets da, wo es um nebenlaeufigkeit geht - threads und so zeug … weils halt ein sehr praxisnahes und oft benoetiges feature ist. wenn du es sowieso noch nie gemacht hast, lohnt es sich sowieso - ist eine schoene aufgabe

Also das möchte ich doch gern bewiesen sehen!
Wenn die Anwendung die Datenbankverbindung offen hält, kann das durch den Connection Pool nicht schneller werden.


und man ja vielleicht auch mehrere DB-Abfragen parallel absenden möchte (mehrere Suchfenster in einer GUI-Anwendung um z.B. nach verschiedenen Filmen/Serien zu suchen --> JMDB).

Auch dann muss man mehrere Anfragen offen haben - und ob die nun zum Pool oder direkt zur DB geöffnet sind, spielt bei dauerhaft offenen Verbindungen keine Rolle.


Connection Pools haben ihre Daseinsberechtigung, aber ich denke, du verwechselst hier etwas.

ebent - ein pool spart ausschließlich das rel. teure erzeugen von connections. es macht sinn, so einen pool zu verwenden, wenn man nicht so recht weiss, wohin die architektonische reise geht. vielleicht ist ein connection-pool fuer eine rich-client anwendung reichlich luxus - aber falsch auf keinen fall.

mehrere connections machen auch dort duraus sinn - z.B. fuer MDI anwendungen, wenn jedes “haupt-fenster” seine eigene verbindung kriegen soll. das macht auch die gesamte anwendung stabiler (fehler passieren) - weil der verlust einer corrupten connection nicht unbedingt die anderen fenster beeinflusst. ausserdem kann man dann auch innerhalb des clients schoene sachen mit transaktionen bauen (undo funktionen und so zeug).

wie ich aber schon sagte - der performance-aspect spielt bei so einem fall aber kaum bis garkeine rolle - weil der user die paar millisek. beim fenster oeffnen eh nicht merkt.

ne schoene disziplin zum implementieren ists aber allemal :slight_smile: