Navigace

Hlavnφ menu

 

Java Servlets - JDBC, JNDI a dßtovΘ zdroje II

V ostatnej Φasti naÜej sΘrie som predstavil mo₧nosti vyu₧itia technol≤gie JDBC v spojenφ so servletmi. Ukßzali sme si ako nastavi¥ potrebnΘ parametre, ako sa pripoji¥ k DB a ako polo₧i¥ dotaz. V zßvere Φlßnku som naznaΦil, ₧e pri pou₧itφ JDBC m⌠₧u vznikn·¥ urΦitΘ v²konnostnΘ problΘmy a ₧e existuje rieÜenie. Tak sa po∩me na to pozrie¥.

DßtovΘ zdroje a Tomcat = DBCP

Implementßcia connection poolingu m⌠₧e silne zßvisie¥ na konkrΘtnom aplikaΦnom prostredφ. Ke∩₧e pri pφsanφ tohto serißlu vyu₧φvame Tomcat, chcem vßm predostrie¥ rieÜenie problΘmu s JDBC na tejto platforme. Pri prßci s databßzami a Tomcatom sa odpor·Φa pou₧φva¥ nßstroj Database Connection Pool (DBCP), Φo je tzv. connection broker. Ide o Φas¥ projektu Apache Jakarta, ktor² nßjdete na adrese http://jakarta.apache.org/commons/dbcp/. Momentßlne je vo verzii 1.0 a mal by by¥ s·Φas¥ou vaÜej k≤pie Tomcata. Nachßdza sa v /common/lib/commons-dbcp.jar. Prφpadne si ho m⌠₧ete z horeuvedenej adresy stiahnu¥. V tom istom adresßry sa musφ nachßdza¥ aj s·bor commons-pool.jar. Ak nie treba ho stiahnu¥ tie₧.

AkΘ s· vlastne v²hody DBCP? Prvß a najd⌠le₧itejÜia je, ₧e zabezpeΦuje samotnΘ zdie╛anie a mana₧ovanie databßzov²ch pripojenφ. O to nßm samozrejme iÜlo. ╧alej DBCP je schopnΘ spolupracova¥ s ak²mko╛vek JDBC driverom a plne vyu₧φva¥ jeho mo₧nosti. DBCP spσ≥a nariadenia normy J2EE a v neposlednom rade je integrovanou s·Φas¥ou Tomcata. Samozrejme ho m⌠₧ete vyu₧i¥ aj v in²ch prostrediach.

UrΦitou Φrtou DBCP je, ₧e vyu₧φva Java Naming and Directory Interface (JNDI) technol≤giu a preto je nutnΘ najprv vytvori¥ JNDI zdroj. Aby ste teda mohli vyu₧φva¥ connection pooling a Tomcat musφte urobi¥ tieto tri kroky:

  1. Definova¥ JNDI zdroj v deskriptore webovej aplikßcie - wwb.xml.
  2. Namapova¥ tento zdroj na skutoΦn² dßtov² zdroj, resp. databßzovΘ spojenie.
  3. V aplikßcii vyh╛ada¥ referenciu na JNDI zdroj a zaΦa¥ vyu₧φva¥ zdie╛anΘ pripojenie.

Definovanie JNDI zdroja

V prvom rade potrebujete referenΦnΘ meno a malo by zaΦφna¥ na jdbc/. Nßsledne treba do web.xml vlo₧i¥ znaΦku <resource-ref>. Postupujte pod╛a uvedenΘho prφkladu:

<resource-ref>
    <res-ref-name>jdbc/CustomersDB</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
</resource-ref>

ZnaΦka <res-ref-name> obsahuje referenΦnΘ meno zdroja, <res-type> definuje ₧e ide o JDBC dßtov² zdroj a <res-auth> Üpecifikuje, ₧e autentifikßcia je zabezpeΦovanß servlet kontajnerom.

Definovanie dßtovΘho zdroja

Teraz je nutnΘ editova¥ s·bor server.xml z d⌠vodu vlo₧enia informßciφ t²kaj·cich sa databßzovΘho pripojenia, ktor² sa nachßdza v adresßry conf/. Tieto informßcie je mo₧nΘ vlo₧i¥ bu∩ do Φasti <DefaultContext> alebo pod vlastn² <Context>. V prvom prφpade bud· informßcie dostupnΘ pre vÜetky web aplikßcie na vaÜom servery a v druhom prφpade len pre vami urΦen· aplikßciu. Ukß₧eme si na prφklade pou₧itie druhej mo₧nosti:

<Context path="/dbapplication" docBase="dbapplication"
        debug="0" reloadable="true">
  <ResourceParams name="jdbc/CustomersDB">
    <parameter>
      <name>user</name>
      <value>sa</value>
    </parameter>
    <parameter>
      <name>password</name>
      <value>passwd</value>
    </parameter>
    <parameter>
      <name>driverClassName</name>
      <value>com.informix.jdbc.IfxDriver</value>
    </parameter>
    <parameter>
      <name>url</name>
      <value>jdbc:informix-sqli://IP:port/database:INFORMIXSERVER=ol1</value>
    </parameter>
  </ResourceParams>
</Context>

Nadefinovali sme teda Ütyri parametre: user, password, driver a url. Zßrove≥ sme prostrednφctvom atrib·tu name namapovali JNDI zdroj na skutoΦn² databßzov² zdroj uveden² v parametry url. Myslφm ₧e je samozrejmΘ, ₧e referenΦn² nßzov JNDI zdroja <res-ref-name> musφ presne odpoveda¥ hodnote atrib·tu name uvedenΘho v elemente <ResourceParams>.

Zφskanie a vyu₧φvanie zdie╛anΘho pripojenia na dßtov² zdroj

Po vytvorenφ JNDI zdroja a jeho namapovanφ na skutoΦn² zdroj nßm u₧ niΦ nebrßni zaΦa¥ vyu₧φva¥ v²hody connection poolingu. Ke∩₧e vyu₧φvame JNDI na vyh╛adanie zdroja a prφstup k dßtam, musφme importova¥ balφΦek javax.naming. ReferenΦn² nßzov zdroja, ktor² ste uviedli v <res-ref-name> musφte uvies¥ vo vaÜom k≤de. Aby ste mohli zaΦa¥ vyu₧φva¥ dßtov² zdroj asociovan² s referenΦn²m nßzvom, musφte najprv zφska¥ tzv. JNDI kontext pre web aplikßciu. Postupujte pod╛a nasledovnΘho prφkladu:

Context init_con = new InitialContext();
Context cntx = (Context) init_con.lookup("java:comp/env");
DataSource ds = (DataSource) cntx.lookup("jdbc/CustomersDB");
Connection con = ds.getConnection();

Ak u₧ mßte objekt Connection m⌠₧ete ho zaΦa¥ vyu₧φva¥ presne t²m ist²m sp⌠sobom ako ste boli zvyknut². Nasledovn² prφklad je upraven²m prφkladom z predchßdzaj·cej Φasti serißlu.

package interval;

import javax.servlet.*;
import javax.servlet.http.*;
import java.sql.*;
import javax.sql.*;
import javax.naming.*;

public class DBServlet extends HttpServlet {

  private Connection con;
  private DataSource ds;

  public void init(ServletConfig conf)
        throws ServletException {
    try {
      Context init_con = new InitialContext();
      Context cntx = (Context) init_con.lookup("java:comp/env");
      ds = (DataSource) cntx.lookup("jdbc/CustomersDB");
    }
    catch (NamingException ex) {
      throw new ServletException ("java:comp/env/jdbc/CustomersDB", ex);
    }
  }

  public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    try {
      synchronized(ds) {
        con = ds.getConnection();
      }
      Statement stm = con.createStatement();
      String sql = "SELECT * FROM TABLE";
      ResultSet rs = stm.executeQuery(sql);
      stm.close();
    }
    catch (SQLException e) {}
    finally {
      try { con.close(); } catch (Exception e) {}
    }
  }
}

Rovnako ako v predoÜlej Φasti aj tento prφklad ilustruje len pou₧itie nieko╛k²ch zßkladn²ch objektov a ich met≤d. Prφklad konΦφ v okamihu naplnenie objektu ResultSet v²sledkami dotazu.

╚asovo nßroΦnΘ operßcie vyh╛adania databßzovΘho pripojenia prostrednφctvom JNDI s· umiestnenΘ v Φasti init(), tak₧e bud· vykonanΘ len raz. Ke∩₧e premennß ds m⌠₧e by¥ potencißlne zdie╛anß medzi jednotliv²mi vlßknami, prφstup k nej je synchronizovan².

T²m by som dneÜn· Φas¥ uzavrel. D·fam, ₧e u₧ nebude pre vßs problΘm vyu₧φva¥ vo vaÜich aplikßcißch connection pooling a t²m zdvihn·¥ ich v²kon.

Branick², Marek (15.10. 2003)