Tomcat und JNDI installieren #
JNDI ist eine Art "Objektverzeichnis". Damit kann man zentral für einen Tomcat-Server bestimmte Objekte oder Werte definieren, die dann allen Applikationen zur Verfügung stehen. Dies hat zwei praktische Anwendungen, die mir spontan einfallen: Zum einen kann man Konfigurationseinstellungen zentral angeben, über die dann alle Applikationen verfügen können. So kann man ihnen mitteilen, in welcher Umgebung sie laufen ohne jede Applikation einzeln konfigurieren zu müssen. Zum anderen kann man Datenbankverbindungen zentral verwalten.
JDBC-Verbindungen zentral verwalten #
Eine Datenbankverbindung ist relativ teuer, d.h. man benötigt relativ viel Zeit und Ressourcen, um eine Verbindung mit einem MySQL-Server aufzubauen und zu authentifizieren. Ist diese Verbindung einmal aufgebaut, benötigt eine normale Webanwendung jedoch oftmals nur die Daten eines einzigen Querys und schließt die Verbindung dann wieder (oder schlimmer noch: schliesst sie nicht). Um eine solche Applikation nun zu beschleunigen, benutzt man sogenannte "Connection Pools". Ein solcher Pool enthält Verbindungen zu einer Datenbank, die dann bei Bedarf einer Applikation zugeordnet werden. In einer normalen, praktischen Applikation, die im Intranet läuft, hat unser Tomcat sowieso meistens nicht mehr als einen oder vielleicht mal zwei Threads gleichzeitig zu bearbeiten. Das bedeutet dann, daß der Tomcat beim ersten Starten eine einzige Verbindung öffnet und diese dann immer wieder benutzt wird.
Schnell-Anleitung #
Die offizielle Doku zum Thema findet sich auf der Tomcat Webseite. Die Doku dort ist sehr gut und ausführlich, allerdings vielleicht ein wenig zu ausführlich. Deshalb habe ich hier direkt und kurz die nötigsten Schritte unter Debian Linux (siehe auch JavaUnterDebian) notiert, um loszulegen:
Pool- und JDBC-Treiber in den Tomcat installieren
aptitude install libmysql-java libcommons-dbcp-java cd /usr/share/tomcat4/common/lib/ ln -s ../../../java/mysql.jar . ln -s ../../../java/commons-dbcp.jar . ln -s ../../../java/commons-pool.jar .
JDBC-Ressourcen meiner Applikation definieren
In der WEB-INF/web.xml muss man folgendes eintragen. Man deklariert damit, welche Ressourcen das Programm benutzen will, welchen Typ diese Ressource hat und unter welchem Namen sie gesucht werden wird. Der Name fängt normalerweise mit jdbc/ an. In folgendem Beispiel geht es also um die banking-Datenbank.
<resource-ref> <description> Ressource-Reference zu einer Factory, die java.sql.Connection Instanzen erzeugen kann. Diese können (müssen) in der server.xml eingerichtet werden. </description> <res-ref-name> jdbc/banking </res-ref-name> <res-type> javax.sql.DataSource </res-type> <res-auth> Container </res-auth> </resource-ref>
Java-Quelltext
Ein genaues Beispiel eines Servlets anzugeben, ist hier zu stark von der jeweiligen Applikation abhängig. Es ist jedoch definitiv so, daß jede datenbankgestützte Applikation irgendwo ein Connection-Objekt benötigt. Dieses zu bekommen ist nun etwas anders als bei einfachem JDBC-Aufruf. Sehr wichtig ist übrigens, daß die Connection auch wieder mit close() geschlossen wird (und zwar auch nur genau einmal), sonst funktioniert das Ganze natürlich nicht richtig...
Context initCtx = new InitialContext(); Context envCtx = (Context) initCtx.lookup("java:comp/env"); DataSource ds = (DataSource) envCtx.lookup("jdbc/banking"); Connection conn = ds.getConnection(); ... conn.close();
Konfiguration der Datasource
In der Datei ../conf/server.xml des Tomcat trägt man nun die Daten ein, mit denen der Tomcat das Datasource-Objekt einrichten kann. Diesen Teil kann man z.B. im <GlobalNamingResources>-Bereich einfügen. Dann kann diese JNDI-Ressource global von allen Applikationen benutzt werden. Man kann den Teil jedoch auch innerhalb des Host- oder des Context-Tags benutzen, um die Ressource auf bestimmte Applikationen zu beschränken.
<Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000" username="javauser" password="javadude" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/javatest?autoReconnect=true"/>
Bei Tomcat 4.x und 5.0 war die Syntax wie folgt:
<Resource name="jdbc/banking" auth="Container" type="javax.sql.DataSource"/> <ResourceParams name="jdbc/banking"> <parameter> <name>factory</name> <value>org.apache.commons.dbcp.BasicDataSourceFactory</value> </parameter> <parameter> <name>username</name> <value>freibierweb</value> </parameter> <parameter> <name>password</name> <value>freibierwebpasswort</value> </parameter> <parameter> <name>driverClassName</name> <value>org.gjt.mm.mysql.Driver</value> </parameter> <parameter> <name>url</name> <value>jdbc:mysql://localhost:3306/banking16?autoReconnect=true</value> </parameter> <parameter> <name>maxActive</name> <value>8</value> </parameter> <parameter> <name>maxIdle</name> <value>4</value> </parameter> </ResourceParams>
Ergebnis #
Obwohl ich jetzt diese wunderbare, überlegene Technologie benutze :-), konnte ich beim Seitenaufruf übrigens keinen echten Geschwindigkeitsvorteil feststellen. Falls man jedoch einen Server hat, der viele parallele Anfragen beantworten muss, dürfte der Unterschied bemerkbar werden. -- ThomasBayen