Tomcat容器下 jdni 数据库连接也的配置 (oracle,mysql)

Tomcat5.5容器下

JNDI(Java Naming and Directory Interface,Java命名和目录接口)是一组在Java应用中访问命名和目录服务的API。命名服务将名称和对象联系起来,使得我们可以用名称访问对象。目录服务是一种命名服务,在这种服务里,对象不但有名称,还有属性。

配置数据库的服务。

文章的主要内容:

·          简介

·          数据库连接池的配置

1.  安装

2.  防止数据库连接池的泄漏

3.  MySQL 数据库连接池例子。

4.  Oracle 8i, 9i & 10g数据库连接池

5.  PostgreSQL

·          Non-DBCP 解决方案

·          Oracle 8i 使用oracle调用接口客户端

1.  简介

2.  把它们放在一起

·          共同的问题

1.  间歇性数据库连接失败

2.  随机性数据库连接关闭异常

3.  上下文与全局命名资源相对应

4.  JNDI 的资源命名与作用域的相互作用

 

简介

JNDI 的数据库配置这样的的说法相对于JNDI 资源来说是比较广泛的。对于tomcat的用户来说这样的配置是相对复杂的。下面会有几个例子来介绍流行的数据库jndi的配置,与一些数据库使用建议。请注意在 Tomcat 5.0.x and Tomcat 5.5.x之间JNDI资源的配置是有些变化的。. 要尽可能的修改其中的语法这样才能使下面的例子在Tomcat 5.5.x下运行。

在配置JNDI 数据库的时候,要确保我们对 Context Host的配置的了解。在这个环节中我还要知道应用的自动布署。

 

数据库连接池配置

DBCP支持 JDBC 2.0. 。在系统中使用 1.4 java虚拟机 DBCP 将可以支持到 JDBC 3.0. 查看 DBCP文档这里有完整的参数配置解释。.

安装

DBCP是使用 Jakarta-Commons来配置数据库连接池.    下面列出了 Jakarta-Commons 的组件:

·            Jakarta-Commons DBCP

·            Jakarta-Commons Collections

·            Jakarta-Commons Pool

这些类库是放在一个单独的jar文件中,这个jar文件是$CATALINA_HOME/common/lib/naming-factory-dbcp.jar.    只有数据库连接池需要的才会被引用。在应用中我们有可能要对包进行重命名避免冲突。

 

防止连接池内存泄漏

一个数据库连接池的创建与管理对应一个数据库。回收再利用一个已经存在的数据库连接比重新创建一个新的数据库连接更有效率。

数据库连接池存在一个问题. 一个web应用要显式的关闭了ResultSet, Statement, 和 Connection.如果没有关闭及时的回收数据库资源,数据库连接池就回收到相应的数据库资源就会导致数据库连接池的内存泄漏。    ".这样会导数数据库连接池的失效,使数据库连接池再也无法使用。

这个问题有个解决方案. Jakarta-Commons DBCP 可以配置跟踪和恢复被遗弃的数据库连接.这样不仅可以恢复数据库连接的使用,而且可以生成一个栈打开数据库资源不用关闭这些资源。

配置数据连接池的数据资源设置下面的这个属性。可以保证数据连接可以删除被遗弃的数据连接和回收数据库连接。

   
 

                 removeAbandoned="true"

 
     

当数据库连接运行在最低配置下所有被遗弃的数据库连接都会被回收并重新利用。这里的默认配置是false.

使用 removeAbandonedTimeout 属性设置一个秒数。在被连接前我们可以认为这个数据库连接是闲着的。

     
 

                 removeAbandonedTimeout="60"

 
     

这个属性的置信配置是 300秒.

logAbandoned这个属性设置为true,就会用日志记录数据库连接池栈闲着的数据库连接。

     
 

            logAbandoned="true"

 
     

它的默认配置是 false.

 

MySQL数据库连接池的例子

0. 简介

我们当前使用的MySQL and JDBC 驱动版本如下:

·            MySQL 3.23.47, MySQL 3.23.47 using InnoDB,, MySQL 3.23.58, MySQL    4.0.1alpha

·            Connector/J 3.0.11-stable (the official JDBC Driver)

·            mm.mysql 2.0.14 (an old 3rd party JDBC Driver)

在开始之前我们不要忘了把这些jar文件放到tomcat的$CATALINA_HOME/common/lib目录下面。

1. MySQL 配置

 创建一个新的用户test,一个新的用户和一张test表. MySQL 用户必须要有密码的分配。 否则会提示你:“The driver will fail if you try to connect with an empty    password”.

   
 

mysql> GRANT ALL PRIVILEGES ON      *.* TO javauser@localhost

         ->   IDENTIFIED BY      'javadude' WITH GRANT OPTION;

mysql> create database javatest;

mysql> use javatest;

mysql> create table testdata (

         ->   id int not null      auto_increment primary key,

         ->   foo varchar(25),

         ->   bar int);

 
     

注意:上面的用户在测试完成后要删除。

接下来向testdata表插入一些测试数据。

     
 

mysql> insert into testdata      values(null, 'hello', 12345);

Query OK, 1 row affected (0.00 sec)

 

mysql> select * from testdata;

+----+-------+-------+

| ID | FOO   | BAR        |

+----+-------+-------+

|       1 | hello | 12345 |

+----+-------+-------+

1 row in set (0.00 sec)

 

mysql>

 
     

2. Context 的配置

要在tomcat配置 JNDI 数据源,只要在context.xml声明一个Context.

例如:

     
 

<Context>

 

         <!-- maxActive: Maximum      number of dB connections in pool. Make sure you

         configure your mysqld      max_connections large enough to handle

         all of your db connections. Set      to -1 for no limit.

         -->

 

         <!-- maxIdle: Maximum number of idle dB connections to retain      in pool.

         Set to -1 for no limit.  See also the DBCP documentation on this

         and the      minEvictableIdleTimeMillis configuration parameter.

         -->

 

         <!-- maxWait: Maximum time to wait for a dB connection to become      available

         in ms, in this example 10      seconds. An Exception is thrown if

         this timeout is exceeded.  Set to -1 to wait indefinitely.

         -->

 

         <!-- username and password: MySQL dB username and password for      dB connections  -->

 

         <!-- driverClassName: Class name for the old mm.mysql JDBC      driver is

         org.gjt.mm.mysql.Driver - we      recommend using Connector/J though.

         Class name for the official      MySQL Connector/J driver is com.mysql.jdbc.Driver.

         -->

        

         <!-- url: The JDBC      connection url for connecting to your MySQL dB.

         -->

 

       <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"/>

 

</Context>

 
     

3. web.xml 的配置

在测试的应用 WEB-INF/web.xml文件里的配置如下。

     
 

<web-app xmlns="http://java.sun.com/xml/ns/j2ee"

         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee

http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"

         version="2.4">

       <description>MySQL Test App</description>

       <resource-ref>

           <description>DB Connection</description>

           <res-ref-name>jdbc/TestDB</res-ref-name>

           <res-type>javax.sql.DataSource</res-type>

           <res-auth>Container</res-auth>

       </resource-ref>

</web-app>

 
     

4. 测试代码

创建一个简单的页面test.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/TestDB">

select id, foo, bar from testdata

</sql:query>

 

<html>

       <head>

         <title>DB Test</title>

       </head>

       <body>

 

       <h2>Results</h2>

      

<c:forEach var="row"      items="${rs.rows}">

         Foo ${row.foo}<br/>

         Bar ${row.bar}<br/>

</c:forEach>

 

       </body>

</html>

 
     

That JSP page makes use of这个jsp页面使用了 JSTL的SQL和核心标签库 and Core taglibs. 我们可以可以从Java Web Services Developer Pack或者 Jakarta Taglib Standard 1.1项目中获取相应的jar包,要保证获取的版本是1.1.x    release. 你有了JSTL, 只需要把    jstl.jar 和 standard.jar 拷贝到web应用的 WEB-INF/lib目录下面。

最后,我们要把web应用布署在tomcat的$CATALINA_HOME/webapps 目录下面。或者以一个war文件DBTest.war的形式放到放到目录下面或者下叫DBTest的目录下面。

布署完成后,在浏览器入http://localhost:8080/DBTest/test.jsp 查看我辛苦劳作的结果。

 

Oracle 8i, 9i & 10g数据库连接池

0. 简介

Oracle 配置数据库连接池相对于MySQL 只要稍微做一点修改。

旧版本的Oracle连接驱动是*.zip文件形式发布的。Tomcat 只能使用will only use *.jar 文件安装到 installed in $CATALINA_HOME/common/lib目录下面. 因此我们要把 classes111.zip 或 classes12.zip重新命名为a .jar r的形式.由于jar文件也是压缩文件我们不需要解压只要简单的重命名。

Oracle 9i建议使用oracle.jdbc.OracleDriver 比oracle.jdbc.driver.OracleDriver 好。因为    Oracle 曾经说过oracle.jdbc.driver.OracleDriver 在下一版本中将会停止使用。

1. Context 配置

和上面 mysql的配置相似,我们只要在Context标签中定义我的数据资源.这里我们定义我们的数据源叫做myoracle 使用精简的驱动用 scott用户, 密码是tiger数据库的唯一标识(sid)叫做 mysid. (注意:使用thin的驱动这里sid是不可能使用相同的监听名字(tnsname)). 这种结构是scott用户的默认结构.

使用 OCI 驱动只需要把oci添加到URL上.

   
 

<Resource name="jdbc/myoracle"      auth="Container"

                   type="javax.sql.DataSource"      driverClassName="oracle.jdbc.OracleDriver"

                   url="jdbc:oracle:thin:@127.0.0.1:1521:mysid"

              username="scott"      password="tiger" maxActive="20"      maxIdle="10"

                   maxWait="-1"/>

 
     

2. web.xml 配置

创建 web.xml 文件要保证标签元素的顺序准确。

     
 

<resource-ref>

 <description>Oracle Datasource      example</description>

 <res-ref-name>jdbc/myoracle</res-ref-name>

 <res-type>javax.sql.DataSource</res-type>

 <res-auth>Container</res-auth>

</resource-ref>

 
     

3. 代码示例

我们可以使用上面同样的测试例子 (假定我们已经创建了数据库实例、表等.) 替换数据源代码。

     
 

Context initContext = new      InitialContext();

Context envContext  =      (Context)initContext.lookup("java:/comp/env");

DataSource ds =      (DataSource)envContext.lookup("jdbc/myoracle");

Connection conn =      ds.getConnection();

//etc.

 
     

 

PostgreSQL数据库连接池

0. 简介

PostgreSQL 的配置与 Oracle相似.

1. 需要的文件

拷贝 Postgres JDBC jar文件到    $CATALINA_HOME/common/lib目录下面. 和 Oracle一样, 要保证这些    jar文件在 DBCP进行类加载的时候可以被加载。这一步做完之后,后面的配置我们每一步都要拿下。

2. 资源配置

在这里我们有两个选选择:一、定义一个数据源所有的tomcat项目共享;另外一个方法是:为一个应用定义一个数据源。

2a.共享数据源的配置方法。

   
 

<Resource      name="jdbc/postgres" auth="Container"

               type="javax.sql.DataSource"      driverClassName="org.postgresql.Driver"

          url="jdbc:postgresql://127.0.0.1:5432/mydb"

          username="myuser"      password="mypasswd" maxActive="20"      maxIdle="10" maxWait="-1"/>

 
     

2b.一个应用配置一个数据源

     
 

<Context>

 

<Resource      name="jdbc/postgres" auth="Container"

               type="javax.sql.DataSource"      driverClassName="org.postgresql.Driver"

               url="jdbc:postgresql://127.0.0.1:5432/mydb"

               username="myuser"      password="mypasswd" maxActive="20"      maxIdle="10"

maxWait="-1"/>

</Context>

 
     

3. web.xml 配置

     
 

<resource-ref>

 <description>postgreSQL Datasource      example</description>

 <res-ref-name>jdbc/postgres</res-ref-name>

 <res-type>javax.sql.DataSource</res-type>

 <res-auth>Container</res-auth>

</resource-ref>

 
     

4. 连接数据源

当我们使用程序去连接数据时,记得要使用java的压缩机制java:/comp/env    到相应的JNDI目录查找,下面是一些代码片段。我们注意到这里的"jdbc/postgres"可以替换成任意值。只要我们在上面的配置文件做相应的修改。

     
 

InitialContext cxt = new      InitialContext();

if ( cxt == null ) {

        throw new Exception("Uh oh -- no context!");

}

 

DataSource ds = (DataSource)      cxt.lookup( "java:/comp/env/jdbc/postgres" );

 

if ( ds == null ) {

        throw new Exception("Data source not found!");

}

 
     

 

Non-DBCP解决方案

这些解决方案是使用一个单一的数据库连接(不推荐以外的任何测试!)或其他一些池技术。

 

Oracle 8i 使用 OCI 客户端

简介

虽然没有解决使用OCI 客户端创建 JNDI 数据源,但是这些笔记可以解决Oracle 和 DBCP 的问题.

为了使用 OCI驱动,应该安装Oracle客户端. 可以从cd安装Oracle8i(8.1.7) 客户端, 从 otn.oracle.com下载合适的JDBC/OCI 驱动(Oracle8i 8.1.7.1 JDBC/OCI驱动)。

重命名classes12.zip 成classes12.jar    拷贝到$CATALINA_HOME/common/lib目录下面.我们要从我们所使用的tomcat和jdk上删除所依赖的javax.sql.* 类文件。

 

把所有的放在一起

确保有ocijdbc8.dll或者在 $PATH 或 LD_LIBRARY_PATH (possibly in $ORAHOME\bin)中 并一个简单的程序确认是使用系统的类库加载的。    ("ocijdbc8");

You should next create a simple test    servlet or jsp that has these critical lines:

   
 

DriverManager.registerDriver(new

oracle.jdbc.driver.OracleDriver());

conn =

DriverManager.getConnection("jdbc:oracle:oci8:@database","username","password");

 
     

访问数据库连接url的形式如: host:port:SID    ,现在我们可以使用test servlet/jsp测试URL是否正确,当我们得到下面这个异常: ServletException with a    root cause of java.lang.UnsatisfiedLinkError:get_env_handle.

一, 表明 UnsatisfiedLinkErro

 JDBC 类文件和Oracle 客户端的版本不匹配。 需要的类文件无法被找到. 例如,使用classes12.zip    文件Oracle版本是从 8.1.6 到 8.1.5的客户端. 这里classeXXXs.zip    文件种Oracle客户端软件必须匹配。

·            $PATH, LD_LIBRARY_PATH 的问题.

·            忽略从 otn下载的驱动,使用  $ORAHOME\jdbc\lib 下的classes12.zip文件。

你可能遇到错:ORA-06401 NETCMN: invalid driver designator

Oracle 文档说明: "Cause: The login (connect) string    contains an invalid driver designator. Action: Correct the string and    re-submit." Change the database connect string (of the form    host:port:SID) with this one:    (description=(address=(host=myhost)(protocol=tcp)(port=1521))(connect_data=(sid=orcl)))   

Ed. Hmm, I don't think this is really    needed if you sort out your TNSNames - but I'm not an Oracle DBA :-)

 

共同的问题

这里有我们在web应用遇到的一些问题和一些方法解决这些问题。

Ps:下面是tomcat里面列出来的问题和解决方法。觉得翻译会失去味道就留着和大家一起学习。

Intermittent    dB Connection Failures

Tomcat runs within a JVM. The JVM    periodically performs garbage collection (GC) to remove java objects which    are no longer being used. When the JVM performs GC execution of code within    Tomcat freezes. If the maximum time configured for establishment of a dB    connection is less than the amount of time garbage collection took you can    get a db conneciton failure.

To collect data on how long garbage    collection is taking add the -verbose:gc argument to your CATALINA_OPTS    environment variable when starting Tomcat. When verbose gc is enabled your    $CATALINA_BASE/logs/catalina.out log file will include data for every    garbage collection including how long it took.

When your JVM is tuned correctly 99% of    the time a GC will take less than one second. The remainder will only take    a few seconds. Rarely, if ever should a GC take more than 10 seconds.

Make sure that the db connection timeout    is set to 10-15 seconds. For the DBCP you set this using the parameter    maxWait.

 

Random    Connection Closed Exceptions

These can occur when one request gets a    db connection from the connection pool and closes it twice. When using a    connection pool, closing the connection just returns it to the pool for    reuse by another request, it doesn't close the connection. And Tomcat uses    multiple threads to handle concurrent requests. Here is an example of the    sequence of events which could cause this error in Tomcat:

     Request 1 running in Thread 1 gets a db connection.

 

     Request 1 closes the db connection.

 

     The JVM switches the running thread to Thread 2

 

     Request 2 running in Thread 2 gets a db connection

     (the same db connection just closed by Request 1).

 

     The JVM switches the running thread back to Thread 1

 

     Request 1 closes the db connection a second time in a finally block.

 

     The JVM switches the running thread back to Thread 2

 

     Request 2 Thread 2 tries to use the db connection but fails

     because Request 1 closed it.

Here is an example of properly written    code to use a db connection obtained from a connection pool:

     Connection conn = null;

     Statement stmt = null;  // Or    PreparedStatement if needed

     ResultSet rs = null;

     try {

       conn = ... get connection from connection pool ...

       stmt = conn.createStatement("select ...");

       rs = stmt.executeQuery();

       ... iterate through the result set ...

       rs.close();

       rs = null;

       stmt.close();

       stmt = null;

       conn.close(); // Return to connection pool

       conn = null;  // Make sure we    don't close it twice

     } catch (SQLException e) {

       ... deal with errors ...

     } finally {

       // Always make sure result sets and statements are closed,

       // and the connection is returned to the pool

       if (rs != null) {

         try { rs.close(); } catch (SQLException e) { ; }

         rs = null;

       }

       if (stmt != null) {

         try { stmt.close(); } catch (SQLException e) { ; }

         stmt = null;

       }

       if (conn != null) {

         try { conn.close(); } catch (SQLException e) { ; }

         conn = null;

       }

     }

 

Context versus    GlobalNamingResources

Please note that although the above    instructions place the JNDI declarations in a Context element, it is    possible and sometimes desirable to place these declarations in the GlobalNamingResources section of the server configuration    file. A resource placed in the GlobalNamingResources section will be shared    among the Contexts of the server.

 

JNDI Resource    Naming and Realm Interaction

In order to get Realms to work, the realm    must refer to the datasource as defined in the    <GlobalNamingResources> or <Context> section, not a datasource    as renamed using <ResourceLink>.

 

你可能感兴趣的:(Tomcat容器下 jdni 数据库连接也的配置 (oracle,mysql))