WEB-INF/lib
de notre application, soit dans le répertoire
lib
de Tomcat.
doGet()
, ce qui va consister à établir une connexion à chaque requête. Cette façon de faire peut être utilisée à titre de test, mais en aucun cas ne doit être utilisée dans une application en production ! L'établissement d'une connexion est un processus coûteux, totalement incompatible avec les exigences de performance d'une application web. Cette façon de faire est absolument à proscrire.
init()
d'une servlet. Cette approche utilise le même code, et est un peu meilleure : au moins la connexion est établie une fois pour toutes, et peut être réutilisée à chaque requête.
init()
.
Exemple 25. Établissement d'une connexion : méthode
init()
public void init(ServletConfig config) { String url = config.getInitParameter("db-url") ; String login = config.getInitParameter("db-login") ; String passwd = config.getInitParameter("db-passwd") ; Connection con = DriverManager.getConnection(url, login, passwd) ; config.getServletContext().setAttribute("db-connection", con) ; }
db-url
,
db-login
et
db-passwd
sont écrits dans le fichier
web.xml
, ce qui permet de pouvoir les modifier sans avoir à recompiler notre application.
Exemple 26. Établissement d'une connexion : paramétrage dans
web.xml
<context-param> <param-name>db-url</param-name> <param-value>jdbc:mysql::3306/db_test</param-value> </context-param> <context-param> <param-name>db-login</param-name> <param-value>scott</param-value> </context-param> <context-param> <param-name>db-passwd</param-name> <param-value>tiger</param-value> </context-param>
web.xml
, il suffit de mettre la servlet qui sait se connecter en premier pour garantir que toutes les servlets pourront lire cette connexion. On peut même, ultime raffinement, ne pas associer cette servlet à une URL. Cette servlet est donc "borgne", on ne peut pas faire de requête dessus, son seul rôle consiste à établir cette connexion.
En fait, cette méthode n'est guère meilleure que la première, même si elle peut paraître plus séduisante.
Effectivement, écrite de cette façon, elle ne crée qu'une unique connexion, que vont devoir utiliser toutes nos requêtes. Dans certains contextes, il serait plus sûr de créer une réserve de connexions, de façon à mieux gérer les montées en charge.
Mettre un
pool
de connexions plutôt qu'une connexion unique serait donc meilleur, d'autant qu'un
pool
permettrait de gérer aussi le cycle de vie de ces connexions : notamment retirer les connexions mortes, et les remplacer par d'autres.
Mais il reste tout de même un problème, dans le cas d'un serveur en cluster. Dans ce cas les contextes doivent être transmis de nœud en nœud, et les objets attachés à ces contextes doivent être sérialisés. Les objets de connexion ne sont pas sérializables, cette solution ne supportera donc pas le clustering.
D'une façon générale, cette méthode convient aux anciennes installations, ou code
legacy
, mais ne doit plus être utilisée.
META-INF/Context.xml
de l'application web, comme suit.
Exemple 27. Déclaration d'une source de données dans le fichier
Context.xml
<Context> <Resource name="jdbc/tp-servlet" auth="Container" type="javax.sql.DataSource" maxActive="20" maxIdle="10" maxWait="100000" username="scott" password="tiger" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql:/db_test" validationQuery="select 1" testOnBorrow="true"/> </Context>
jdbc/tp-servlet
. C'est par ce nom logique que l'on va pouvoir lire cette ressource de l'intérieur du code d'une servlet.
Enfin, on remarque quelques paramètres techniques, propres au gestionnaire de réserve de connexions utilisé par Tomcat : DBCP.
maxActive
,
maxIdle
et
maxWait
: ces paramètres règlent le fonctionnement du
pool
proprement dit : le nombre maximal de connexions actives à un moment donné, le nombre maximal de connexions inactives (le surplus sera fermé), et un
timeout
.
validationQuery
et
testOnBorrow
permettent de tester si une connexion est active avant qu'elle soit fournie au code appelant. Effectivement, certains serveurs de bases de données, MySQL entre autres, ont la fâcheuse tendance à fermer autoritairement une connexion qui n'a pas été utilisée pendant un certain temps. Le driver JDBC n'est pas informé de cette fermeture, ce n'est que lorsque l'on tente une requête SQL que l'on se rend compte que cette connexion est en fait fermée.
Exemple 28. Obtention d'une connexion du pool
try { // lecture du contexte JDNI de notre servlet Context initContext = new InitialContext() ; // initialisation de ce contexte Context envContext = (Context)initContext.lookup("java:/comp/env") ; // lecture de la datasource définie par requête JNDI DataSource ds = (DataSource)envContext.lookup("jdbc/tp-servlet") ; // demande d'une connexion à cette datasource Connection conn = ds.getConnection(); pw.print(" " + conn) ; } catch (NamingException e) { // gestion de l'exception } catch (SQLException e) { // gestion de l'exception }
doGet()
. La connexion qu'il obtient est beaucoup plus sûre que dans les exemples des paragraphes précédents :
Exemple 29. Utilisation d'une connexion dans une page JSP
<%@ taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <sql:query var="rs" dataSource="jdbc/tp-servlet"> select id, nom, prenom from Marin </sql:query>