JavaWeb开发与代码的编写(二十四)

JNDI数据源的配置

数据源的由来

  在Java开发中,使用JDBC操作数据库的四个步骤如下:

    ①加载数据库驱动程序(Class.forName("数据库驱动类");)
      ②连接数据库(Connection con  = DriverManager.getConnection();)
      ③操作数据库(PreparedStatement stat = con.prepareStatement(sql);stat.executeQuery();)
      ④关闭数据库,释放连接(con.close();)
  也就是说,所有的用户都需要经过此四步进行操作,但是这四步之中有三步(①加载数据库驱动程序、②连接数据库、④关闭数据库,释放连接)对所有人都是一样的,而所有人只有在操作数据库上是不一样,那么这就造成了性能的损耗。
  那么最好的做法是,准备出一个空间,此空间里专门保存着全部的数据库连接,以后用户用数据库操作的时候不用再重新加载驱动、连接数据库之类的,而直接从此空间中取走连接,关闭的时候直接把连接放回到此空间之中。
  那么此空间就可以称为连接池(保存所有的数据库连接),但是如果要想实现此空间的话,则必须有一个问题要考虑?
      1、 如果没有任何一个用户使用连接,那么那么应该维持一定数量的连接,等待用户使用。
      2、 如果连接已经满了,则必须打开新的连接,供更多用户使用。
      3、 如果一个服务器就只能有100个连接,那么如果有第101个人过来呢?应该等待其他用户释放连接
      4、 如果一个用户等待时间太长了,则应该告诉用户,操作是失败的。
   如果直接用程序实现以上功能,则会比较麻烦,所以在Tomcat 4.1.27之后,在服务器上就直接增加了数据源的配置选项,直接在服务器上配置好数据源连接池即可。在J2EE服务器上保存着一个数据库的多个连接。每一个连接通过DataSource可以找到。DataSource被绑定在了JNDI树上(为每一个DataSource提供一个名字)客户端通过名称找到在JNDI树上绑定的DataSource,再由DataSource找到一个连接。如下图所示:

  

  那么在以后的操作中,除了数据库的连接方式不一样之外,其他的所有操作都一样,只是关闭的时候不是彻底地关闭数据库,而是把数据库的连接放回到连接池中去。

  如果要想使用数据源的配置,则必须配置虚拟目录,因为此配置是在虚拟目录之上起作用的。需要注意的是,如果要想完成以上的功能,在Tomcat服务器上一定要有各个数据库的驱动程序。

JNDI+Tomcat配置数据源的两种方式

全局jndi配置

  此种配置需要在server.xml中配置数据源,具体的配置步骤如下:

  1、在tomcat服务器的lib目录下加入数据库连接的驱动jar包

  

  2、修改tomcat服务器的conf目录下server.xml配置文件

  

  打开server.xml配置文件,可以看到里面自带的一个全局JNDI配置,如下图所示:

  

  编辑server.xml文件,添加全局JNDI数据源配置,配置如下:

<!-- Global JNDI resourcesDocumentation at /docs/jndi-resources-howto.html--><GlobalNamingResources><!-- Editable user database that can also be used byUserDatabaseRealm to authenticate users--><Resource name="UserDatabase" auth="Container"type="org.apache.catalina.UserDatabase"description="User database that can be updated and saved"factory="org.apache.catalina.users.MemoryUserDatabaseFactory"pathname="conf/tomcat-users.xml" /><!--|- name:表示以后要查找的名称。通过此名称可以找到DataSource,此名称任意更换,但是程序中最终要查找的就是此名称,为了不与其他的名称混淆,所以使用jdbc/oracle,现在配置的是一个jdbc的关于oracle的命名服务。|- auth:由容器进行授权及管理,指的用户名和密码是否可以在容器上生效|- type:此名称所代表的类型,现在为javax.sql.DataSource|- maxActive:表示一个数据库在此服务器上所能打开的最大连接数|- maxIdle:表示一个数据库在此服务器上维持的最小连接数|- maxWait:最大等待时间。10000毫秒|- username:数据库连接的用户名|- password:数据库连接的密码|- driverClassName:数据库连接的驱动程序|- url:数据库连接的地址--><!--配置Oracle数据库的JNDI数据源--><Resource name="jdbc/oracle"auth="Container" type="javax.sql.DataSource"maxActive="100" maxIdle="30" maxWait="10000"username="lead_oams" password="p"driverClassName="oracle.jdbc.driver.OracleDriver"url="jdbc:oracle:thin:@192.168.1.229:1521:lead"/><!--配置MySQL数据库的JNDI数据源--><Resource name="jdbc/mysql"auth="Container" type="javax.sql.DataSource"maxActive="100" maxIdle="30" maxWait="10000"username="root" password="root"driverClassName="com.mysql.jdbc.Driver"url="jdbc:mysql://192.168.1.144:3306/leadtest?useUnicode=true&amp;characterEncoding=utf-8"/><!--配置SQLServer数据库的JNDI数据源--><Resource name="jdbc/sqlserver"auth="Container" type="javax.sql.DataSource"maxActive="100" maxIdle="30" maxWait="10000"username="sa" password="p@ssw0rd"driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"url="jdbc:sqlserver://192.168.1.51:1433;DatabaseName=demo"/></GlobalNamingResources>

经过以上的两个步骤,全局JNDI数据源就配置好了,在上述的server.xml文件中,分别配置了Oracle、MySQL、SQLServer这三种数据库的全局JNDI数据源。

全局jndi数据源测试

  1、创建一个JNDI测试项目JNDITest,在web.xml中添加JNDI配置的资源引用

 

  web.xml的配置如下:

 <?xml version="1.0" encoding="UTF-8"?><web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"><welcome-file-list><welcome-file>index.jsp</welcome-file></welcome-file-list><!-- JNDI配置的资源引用:• res-ref-name:表示引用资源的名称• res-type:此资源对应的类型为javax.sql.DataSource• res-auth:容器授权管理--><!--Oracle数据库JNDI数据源引用 --><resource-ref><description>Oracle DB Connection</description><res-ref-name>oracleDataSource</res-ref-name><res-type>javax.sql.DataSource</res-type><res-auth>Container</res-auth></resource-ref><!--MySQL数据库JNDI数据源引用 --><resource-ref><description>MySQL DB Connection</description><res-ref-name>mysqlDataSource</res-ref-name><res-type>javax.sql.DataSource</res-type><res-auth>Container</res-auth></resource-ref><!--SQLServer数据库JNDI数据源引用 --><resource-ref><description>SQLServer DB Connection</description><res-ref-name>sqlserverDataSource</res-ref-name><res-type>javax.sql.DataSource</res-type><res-auth>Container</res-auth></resource-ref></web-app>

  2、映射JNDITest项目的虚拟目录

  在tomcat的\conf\Catalina\localhost下(没有目录就新建)创建一个xml文件,文件名必须和项目名相同,测试JNDI数据源的web项目的项目名称是:JNDITest,所以xml文件的命名就叫JNDITest.xml,如下图所示:

  

  编辑JNDITest.xml,配置如下:

<?xml version="1.0" encoding="UTF-8"?><!--jndi配置方法(tomcat):将此文件放置在tomcat\conf\Catalina\localhost下(没有目录就新建)--><!--映射JNDITest项目的虚拟目录--><Context docBase="D:/MyEclipse8.5/workspace/JNDITest/WebRoot" debug="0" reloadable="false"><!--引用Oracle数据库的JNDI数据源--><ResourceLink name="oracleDataSource" global="jdbc/oracle" type="javax.sql.DataSource"/><!--引用mysql数据库的JNDI数据源--><ResourceLink name="mysqlDataSource" global="jdbc/mysql" type="javax.sql.DataSource"/><!--引用sqlserver数据库的JNDI数据源--><ResourceLink name="sqlserverDataSource" global="jdbc/sqlserver" type="javax.sql.DataSource"/></Context>

 3、测试从JNDI数据源获取数据库连接

  配置完数据源连接池之后,就可以按照以下的步骤进行访问:

   • 初始化名称查找上下文
    • 通过JNDI名称找到DataSource
    • 通过DataSource取得一个连接
    • 操作数据库
    • 关闭数据库,关闭的时候是将连接放回到连接池之中

  jsp测试页面代码如下:

 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%@ page import="java.sql.*,javax.sql.*,javax.naming.*" %><!DOCTYPE HTML><html><head><title>JNDI数据源测试</title></head><body><%Connection connOracle = null;try {//1、初始化名称查找上下文Context ctx = new InitialContext();//InitialContext ctx = new InitialContext();亦可 //2、通过JNDI名称找到DataSource,对名称进行定位java:comp/env是必须加的,后面跟的是DataSource名/*DataSource名在web.xml文件中的<res-ref-name>oracleDataSource</res-ref-name>进行了配置<!--Oracle数据库JNDI数据源引用 --><resource-ref><description>Oracle DB Connection</description><res-ref-name>oracleDataSource</res-ref-name><res-type>javax.sql.DataSource</res-type><res-auth>Container</res-auth></resource-ref>*/DataSource ds = (DataSource)ctx.lookup("java:comp/env/oracleDataSource");//3、通过DataSource取得一个连接connOracle = ds.getConnection();out.println("Oracle Connection pool connected !!");//4、操作数据库} catch (NamingException e) {System.out.println(e.getMessage());} catch (SQLException e) {e.printStackTrace();} finally {//5、关闭数据库,关闭的时候是将连接放回到连接池之中connOracle.close();}%><hr/><%Connection connMySQL = null;try {//1、初始化名称查找上下文Context ctx = new InitialContext();//InitialContext ctx = new InitialContext();亦可 //2、通过JNDI名称找到DataSource,对名称进行定位java:comp/env是必须加的,后面跟的是DataSource名/*DataSource名在web.xml文件中的<res-ref-name>mysqlDataSource</res-ref-name>进行了配置<!--MySQL数据库JNDI数据源引用 --><resource-ref><description>MySQL DB Connection</description><res-ref-name>mysqlDataSource</res-ref-name><res-type>javax.sql.DataSource</res-type><res-auth>Container</res-auth></resource-ref>*/DataSource ds = (DataSource)ctx.lookup("java:comp/env/mysqlDataSource");//3、通过DataSource取得一个连接connMySQL = ds.getConnection();out.println("MySQL Connection pool connected !!");//4、操作数据库} catch (NamingException e) {System.out.println(e.getMessage());} catch (SQLException e) {e.printStackTrace();} finally {//5、关闭数据库,关闭的时候是将连接放回到连接池之中connMySQL.close();}%><hr/><%Connection connSQLServer = null;try {//1、初始化名称查找上下文Context ctx = new InitialContext();//InitialContext ctx = new InitialContext();亦可 //2、通过JNDI名称找到DataSource,对名称进行定位java:comp/env是必须加的,后面的是DataSource名/*DataSource名在web.xml文件中的<res-ref-name>sqlserverDataSource</res-ref-name>进行了配置<!--SQLServer数据库JNDI数据源引用 --><resource-ref><description>SQLServer DB Connection</description><res-ref-name>sqlserverDataSource</res-ref-name><res-type>javax.sql.DataSource</res-type><res-auth>Container</res-auth></resource-ref>*/DataSource ds = (DataSource)ctx.lookup("java:comp/env/sqlserverDataSource");//3、通过DataSource取得一个连接connSQLServer = ds.getConnection();out.println("SQLServer Connection pool connected !!");//4、操作数据库} catch (NamingException e) {System.out.println(e.getMessage());} catch (SQLException e) {e.printStackTrace();} finally {//5、关闭数据库,关闭的时候是将连接放回到连接池之中connSQLServer.close();}%></body></html>

  运行结果如下:

  

  除了可以在Jsp页面中编写java代码测试JNDI数据源连接之外,还有一种比较简单的方式就是使用JSTL标签库提供的sql标签进行测试,测试代码如下:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%--引入JSTL标签库 --%><%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>4<%@ taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql"%><!DOCTYPE HTML><html><head><title>JNDI数据源连接测试</title></head><body><h3>Oracle JNDI数据源测试</h3><%--使用sql:query标签发送SQL语句去数据库查询数据,查询的结果集保存到rs变量当中,dataSource属性指明使用的数据源--%><sql:query var="rs" dataSource="oracleDataSource"><%--Oracle JNDI数据源测试 SQL--%>SELECT * FROM LEAD_OAMS_DBSOURCES</sql:query><%--使用c:forEach标签遍历查询结果集rs中的每一行--%><c:forEach var="row" items="${rs.rows}"><%--${row.字段名}获取字段的值--%>${row.RESOURCEID}---${row.DBSOURCE_NAME}---${row.DBSOURCE_TYPE}<br/></c:forEach><hr/><h3>MySQL JNDI数据源测试</h3><%--使用sql:query标签发送SQL语句去数据库查询数据,查询的结果集保存到rs变量当中,dataSource属性指明使用的数据源--%><sql:query var="rs" dataSource="mysqlDataSource"><%--MySQL JNDI数据源测试 SQL--%>select * from ld_user</sql:query><%--使用c:forEach标签遍历查询结果集rs中的每一行--%><c:forEach var="row" items="${rs.rows}"><%--${row.字段名}获取字段的值--%>${row.id}---${row.username}---${row.password}<br/></c:forEach><hr/><h3>SQLServer JNDI数据源测试</h3><%--使用sql:query标签发送SQL语句去数据库查询数据,查询的结果集保存到rs变量当中,dataSource属性指明使用的数据源--%><sql:query var="rs" dataSource="sqlserverDataSource"><%--SQLServer JNDI数据源测试 SQL--%>select * from t_demo</sql:query><%--使用c:forEach标签遍历查询结果集rs中的每一行--%><c:forEach var="row" items="${rs.rows}"><%--${row.字段名}获取字段的值--%>${row.id}---${row.time}<br/></c:forEach></body></html>

 运行结果如下:

  

非全局jndi配置

  非全局JNDI数据源是针对某一个Web项目配置的数据源,具体的配置步骤如下:

  1、在tomcat服务器的lib目录下加入数据库连接的驱动jar包

   2、针对具体的web项目映射虚拟目录,然后在虚拟目录映射的配置文件中配置JNDI数据源

  还是以上面的JNDITest项目为例子进行说明

  在tomcat目录下的\conf\Catalina\localhost目录下创建一个JNDITest.xml文件,如下图所示:

  

  编辑JNDITest.xml文件,添加对JNDITest项目的虚拟目录的映射和JNDI数据源的配置

 <?xml version="1.0" encoding="UTF-8"?><!--jndi配置方法(tomcat):将此文件放置在tomcat\conf\Catalina\localhost下(没有目录就新建)--><Context docBase="D:/MyEclipse8.5/workspace/JNDITest/WebRoot" debug="0" reloadable="false"><!--|- name:表示以后要查找的名称。通过此名称可以找到DataSource,此名称任意更换,但是程序中最终要查找的就是此名称,为了不与其他的名称混淆,所以使用jdbc/oracle,现在配置的是一个jdbc的关于oracle的命名服务。|- auth:由容器进行授权及管理,指的用户名和密码是否可以在容器上生效|- type:此名称所代表的类型,现在为javax.sql.DataSource|- maxActive:表示一个数据库在此服务器上所能打开的最大连接数|- maxIdle:表示一个数据库在此服务器上维持的最小连接数|- maxWait:最大等待时间。10000毫秒|- username:数据库连接的用户名|- password:数据库连接的密码|- driverClassName:数据库连接的驱动程序|- url:数据库连接的地址--><!--配置Oracle数据库的JNDI数据源--><Resource name="oracleDataSource"auth="Container" type="javax.sql.DataSource"maxActive="100" maxIdle="30" maxWait="10000"username="lead_oams" password="p"driverClassName="oracle.jdbc.driver.OracleDriver"url="jdbc:oracle:thin:@192.168.1.229:1521:lead"/><!--配置MySQL数据库的JNDI数据源--><Resource name="mysqlDataSource"auth="Container" type="javax.sql.DataSource"maxActive="100" maxIdle="30" maxWait="10000"username="root" password="root"driverClassName="com.mysql.jdbc.Driver"url="jdbc:mysql://192.168.1.144:3306/leadtest?useUnicode=true&amp;characterEncoding=utf-8"/><!--配置SQLServer数据库的JNDI数据源--><Resource name="sqlserverDataSource"auth="Container" type="javax.sql.DataSource"maxActive="100" maxIdle="30" maxWait="10000"username="sa" password="p@ssw0rd"driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"url="jdbc:sqlserver://192.168.1.51:1433;DatabaseName=demo"/></Context>

  3、在web项目的web.xml文件中引用配置好的JNDI数据源

 <!-- JNDI配置的资源引用:• res-ref-name:表示引用资源的名称• res-type:此资源对应的类型为javax.sql.DataSource• res-auth:容器授权管理--><!--Oracle数据库JNDI数据源引用 --><resource-ref><description>Oracle DB Connection</description><res-ref-name>oracleDataSource</res-ref-name><res-type>javax.sql.DataSource</res-type><res-auth>Container</res-auth></resource-ref><!--MySQL数据库JNDI数据源引用 --><resource-ref><description>MySQL DB Connection</description><res-ref-name>mysqlDataSource</res-ref-name><res-type>javax.sql.DataSource</res-type><res-auth>Container</res-auth></resource-ref><!--SQLServer数据库JNDI数据源引用 --><resource-ref><description>SQLServer DB Connection</description><res-ref-name>sqlserverDataSource</res-ref-name><res-type>javax.sql.DataSource</res-type><res-auth>Container</res-auth></resource-ref>

  经过以上3个步骤,针对具体web项目配置的JNDI数据源就算是配置好了。具体的测试和上述测试全局JNDI数据源的方式是一样的!

Tomcat下使用C3P0配置JNDI数据源

C3P0下载

  C3P0下载地址:http://sourceforge.net/projects/c3p0/files/?source=navbar

  

  下载完成之后得到一个压缩包

使用C3P0配置JNDI数据源

  Tomcat6.x中配置JNDI数据源时默认使用的是Tomcat6.x自带的DBCP连接池,Tomcat6.x使用DBCP连接池配置JNDI数据源如下:

 <Resource name="oracleDataSource" auth="Container" type="javax.sql.DataSource" maxActive="50" maxIdle="10" maxWait="10000" username="lead_oams" password="p" driverClassName="oracle.jdbc.OracleDriver" url="jdbc:oracle:thin:@192.168.1.229:1521:lead"/>

  如果想让Tomcat6.x使用C3P0连接池配置JNDI数据源,在配置时,以下配置项需要修改

  1、 type和factory的值发生变化

  2、username=>user

  3、url=>jdbcUrl

  4、driverClassName=>driverClass

  创建一个Web测试项目C3P0_JNDI_Config,解压压缩包,找到c3p0-0.9.5-pre9\lib目录下的相关Jar包如下图所示:

  

  将C3P0的相关Jar包添加到项目中,在项目的META-INF目录下创建一个context.xml文件,目录结构如下图所示:

  

  在tomcat服务器的lib目录下添加Oracle、MySQL、SQLServer三种数据库的驱动jar包,如下图所示:

  

  1、在context.xml文件中加入如下配置信息

<Context><!-- 使用C3P0配置针对MySQL数据库的JNDI数据源 --><Resource name="jdbc/MysqlDataSource" auth="Container"factory="org.apache.naming.factory.BeanFactory" type="com.mchange.v2.c3p0.ComboPooledDataSource"driverClass="com.mysql.jdbc.Driver"idleConnectionTestPeriod="60"maxPoolSize="50" minPoolSize="2"acquireIncrement="2" user="root" password="root"jdbcUrl="jdbc:mysql://192.168.1.144:3306/leadtest"/><!-- 使用C3P0配置针对Oracle数据库的JNDI数据源 --><Resource name="jdbc/OracleDataSource" auth="Container"factory="org.apache.naming.factory.BeanFactory" type="com.mchange.v2.c3p0.ComboPooledDataSource"driverClass="oracle.jdbc.OracleDriver"idleConnectionTestPeriod="60"maxPoolSize="50" minPoolSize="2"acquireIncrement="2" jdbcUrl="jdbc:oracle:thin:@192.168.1.229:1521:lead"user="lead_oams"password="p"/><!--使用C3P0配置针对SQLServer数据库的JNDI数据源--><Resource name="jdbc/SqlServerDataSource"auth="Container"factory="org.apache.naming.factory.BeanFactory" type="com.mchange.v2.c3p0.ComboPooledDataSource"driverClass="com.microsoft.sqlserver.jdbc.SQLServerDriver"idleConnectionTestPeriod="60"maxPoolSize="50" minPoolSize="2"acquireIncrement="2" jdbcUrl="jdbc:sqlserver://192.168.1.51:1433;DatabaseName=demo"user="sa" password="p@ssw0rd"/></Context>

  2.在web.xml引用JDNI数据源:

<?xml version="1.0" encoding="UTF-8"?><web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"><welcome-file-list><welcome-file>index.jsp</welcome-file></welcome-file-list><!-- JNDI配置的资源引用:• res-ref-name:表示引用资源的名称• res-type:此资源对应的类型为javax.sql.DataSource• res-auth:容器授权管理--><!--Oracle数据库JNDI数据源引用 --><resource-ref><description>Oracle DB Connection</description><res-ref-name>jdbc/OracleDataSource</res-ref-name><res-type>javax.sql.DataSource</res-type><res-auth>Container</res-auth></resource-ref><!--MySQL数据库JNDI数据 --><resource-ref><description>MySQL DB Connection</description><res-ref-name>jdbc/MysqlDataSource</res-ref-name>  <res-type>javax.sql.DataSource</res-type><res-auth>Container</res-auth></resource-ref><!--SQLServer数据库JNDI数据源引用 --><resource-ref><description>SQLServer DB Connection</description><res-ref-name>jdbc/SqlServerDataSource</res-ref-name><res-type>javax.sql.DataSource</res-type><res-auth>Container</res-auth></resource-ref></web-app>

  3.部署C3P0_JNDI_Config Web应用到Tomcat服务器测试JNDI数据源

  

  部署到tomcat服务器的webapps目录之后,tomcat服务器就会自动在\conf\Catalina\localhost目录下生成一个C3P0_JNDI_Config.xml文件,如下图所示:

  

  C3P0_JNDI_Config.xml文件中的内容就是我们在META-INF目录的context.xml文件中配置的那些内容。

  jsp测试页面如下:

 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%--引入JSTL标签库 --%><%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%><%@ taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql"%><!DOCTYPE HTML><html><head><title>C3P0配置JNDI数据源连接测试</title></head><body><h3>针对MySQL数据库JNDI数据源测试</h3><%--使用sql:query标签发送SQL语句去数据库查询数据,查询的结果集保存到rs变量当中,dataSource属性指明使用的数据源--%><sql:query var="rs" dataSource="jdbc/MysqlDataSource"><%--MySQL JNDI数据源测试 SQL--%>select * from ld_user</sql:query><%--使用c:forEach标签遍历查询结果集rs中的每一行--%><c:forEach var="row" items="${rs.rows}"><%--${row.字段名}获取字段的值--%>${row.id}---${row.username}---${row.password}<br/></c:forEach><hr/><h3>针对Oracle数据库JNDI数据源测试</h3><%--使用sql:query标签发送SQL语句去数据库查询数据,查询的结果集保存到rs变量当中,dataSource属性指明使用的数据源--%><sql:query var="rs" dataSource="jdbc/OracleDataSource"><%--Oracle JNDI数据源测试 SQL--%>SELECT * FROM LEAD_OAMS_DBSOURCES</sql:query><%--使用c:forEach标签遍历查询结果集rs中的每一行--%><c:forEach var="row" items="${rs.rows}"><%--${row.字段名}获取字段的值--%>${row.RESOURCEID}---${row.DBSOURCE_NAME}---${row.DBSOURCE_TYPE}<br/></c:forEach><hr/></body>
</html>

C3P0 自动重连相关参数
     idleConnectionTestPeriod:C3P0会有一个Task检测pool内的连接是否正常,此参数就是Task运行的频率。默认值为0,表示不进行检测
    acquireRetryAttempts:pool请求取新连接失败后重试的次数
     C3P0目前存在问题:
     当数据库重启后,C3P0不会自动重新初始化数据库连接池,当新的请求需要访问数据库的时候,此时回报错误(因为数据库重启,连接失效),同时刷新数据库连接池,丢弃掉已经失效的连接,当第二个请求到来时恢复正常。
  C3P0目前没有提供当获取已建立连接失败后重试次数的参数,只有获取新连接失败后重试次数的参数(acquireRetryAttempts )。
要解决此问题,可以通过设置idleConnectionTestPeriod 参数折中解决,该参数的作用是设置系统自动检查连接池中连接是否正常的一个频率参数,时间单位是秒。

Tomcat下使用Druid配置JNDI数据源

com.alibaba.druid.pool.DruidDataSourceFactory实现了javax.naming.spi.ObjectFactory,可以作为JNDI数据源来配置。

下载Druid的jar包

  下载地址:http://mvnrepository.com/artifact/com.alibaba/druid/1.0.9,如下图所示:

 

  druid.jar依赖log4j的jar包,所以还需要下载log4j的jar包。

  log4j的下载地址如下:http://mvnrepository.com/artifact/log4j/log4j/1.2.17,如下图所示:

 

使用Druid配置JNDI数据源

前期准备工作

  创建一个Web测试项目Druid_JNDI_Config,将下载下来druid-1.0.9.jar和log4j-1.2.17.jar添加到项目中,在项目的META-INF目录下创建一个context.xml文件

  目录结构如下图所示:

  

  在tomcat服务器的lib目录下添加Oracle、MySQL、SQLServer三种数据库的驱动jar包,如下图所示:

  

在context.xml文件中加入JNDI的配置信息

  在context.xml文件中加入如下配置信息

 <Context><!-- 使用阿里巴巴的DruidDataSource配置针对Oracle数据库的JNDI数据源 --><Resource name="jdbc/OracleDataSource"factory="com.alibaba.druid.pool.DruidDataSourceFactory"auth="Container"type="javax.sql.DataSource"driverClassName="oracle.jdbc.OracleDriver"url="jdbc:oracle:thin:@192.168.1.229:1521:lead"username="lead_oams"password="p"maxActive="50"maxWait="10000"removeabandoned="true"removeabandonedtimeout="60"logabandoned="false"filters="stat"/><!-- 使用阿里巴巴的DruidDataSource配置针对MySQL数据库的JNDI数据源 --><Resource name="jdbc/MysqlDataSource"factory="com.alibaba.druid.pool.DruidDataSourceFactory"auth="Container"type="javax.sql.DataSource"driverClassName="com.mysql.jdbc.Driver"url="jdbc:mysql://192.168.1.233:3306/lead_oams?useUnicode=true&amp;characterEncoding=utf-8"username="lead_system"password="password"maxActive="50"maxWait="10000"removeabandoned="true"removeabandonedtimeout="60"logabandoned="false"filters="stat"/><!--使用阿里巴巴的DruidDataSource配置针对SQLServer数据库的JNDI数据源--><Resource name="jdbc/SqlServerDataSource"auth="Container"factory="com.alibaba.druid.pool.DruidDataSourceFactory" type="javax.sql.DataSource"driverClass="com.microsoft.sqlserver.jdbc.SQLServerDriver"url="jdbc:sqlserver://192.168.1.61:1433;DatabaseName=gaclTest"username="sa" password="p@ssw0rd"maxActive="50"maxWait="10000"removeabandoned="true"removeabandonedtimeout="60"logabandoned="false"filters="stat"/>
</Context>

  配置项中指定了各个参数后,在连接池内部是这么使用这些参数的。数据库连接池在初始化的时候会创建initialSize个连接,当有数据库操作时,会从池中取出一个连接。如果当前池中正在使用的连接数等于maxActive,则会等待一段时间,等待其他操作释放掉某一个连接,如果这个等待时间超过了maxWait,则会报错;如果当前正在使用的连接数没有达到maxActive,则判断当前是否空闲连接,如果有则直接使用空闲连接,如果没有则新建立一个连接。在连接使用完毕后,不是将其物理连接关闭,而是将其放入池中等待其他操作复用。同时连接池内部有机制判断,如果当前的总的连接数少于miniIdle,则会建立新的空闲连接,以保证连接数得到miniIdle。如果当前连接池中某个连接在空闲了timeBetweenEvictionRunsMillis时间后任然没有使用,则被物理性的关闭掉。有些数据库连接的时候有超时限制(mysql连接在8小时后断开),或者由于网络中断等原因,连接池的连接会出现失效的情况,这时候设置一个testWhileIdle参数为true,可以保证连接池内部定时检测连接的可用性,不可用的连接会被抛弃或者重建,最大情况的保证从连接池中得到的Connection对象是可用的。当然,为了保证绝对的可用性,你也可以使用testOnBorrow为true(即在获取Connection对象时检测其可用性),
不过这样会影响性能。

在web.xml引用JDNI数据源

  在web.xml文件中加入如下的配置引用JNDI数据源

<?xml version="1.0" encoding="UTF-8"?><web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"><welcome-file-list><welcome-file>index.jsp</welcome-file></welcome-file-list><!-- JNDI配置的资源引用:• res-ref-name:表示引用资源的名称• res-type:此资源对应的类型为javax.sql.DataSource• res-auth:容器授权管理--><!--Oracle数据库JNDI数据源引用 --><resource-ref><description>Oracle DB Connection</description>    <res-ref-name>jdbc/OracleDataSource</res-ref-name><res-type>javax.sql.DataSource</res-type><res-auth>Container</res-auth></resource-ref><!--MySQL数据库JNDI数据 --><resource-ref><description>MySQL DB Connection</description><res-ref-name>jdbc/MysqlDataSource</res-ref-name><res-type>javax.sql.DataSource</res-type><res-auth>Container</res-auth></resource-ref><!--SQLServer数据库JNDI数据源引用 --><resource-ref><description>SQLServer DB Connection</description><res-ref-name>jdbc/SqlServerDataSource</res-ref-name><res-type>javax.sql.DataSource</res-type><res-auth>Container</res-auth></resource-ref>
</web-app>

测试JNDI数据源

  部署Druid_JNDI_Config Web应用到Tomcat服务器测试JNDI数据源,如下图所示:

  

  部署到tomcat服务器的webapps目录之后,tomcat服务器就会自动在\conf\Catalina\localhost目录下生成一个Druid_JNDI_Config.xml文件,如下图所示:

  

  Druid_JNDI_Config.xml文件中的内容就是我们在META-INF目录的context.xml文件中配置的那些内容。

  jsp测试页面如下:

 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%--引入JSTL标签库 --%><%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%><%@ taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql"%><!DOCTYPE HTML><html><head><title>DRUID配置JNDI数据源连接测试</title></head><body><h3>针对MySQL数据库JNDI数据源测试</h3><%--使用sql:query标签发送SQL语句去数据库查询数据,查询的结果集保存到rs变量当中,dataSource属性指明使用的数据源--%><sql:query var="rs" dataSource="jdbc/MysqlDataSource"><%--MySQL JNDI数据源测试 SQL--%>select * from lead_oams_applications</sql:query><%--使用c:forEach标签遍历查询结果集rs中的每一行--%><c:forEach var="row" items="${rs.rows}"><%--${row.字段名}获取字段的值--%>${row.resourceid}---${row.app_name}<br/></c:forEach><hr/><h3>针对Oracle数据库JNDI数据源测试</h3><%--使用sql:query标签发送SQL语句去数据库查询数据,查询的结果集保存到rs变量当中,dataSource属性指明使用的数据源--%><sql:query var="rs" dataSource="jdbc/OracleDataSource"><%--Oracle JNDI数据源测试 SQL--%>             SELECT * FROM LEAD_OAMS_DBSOURCES</sql:query><%--使用c:forEach标签遍历查询结果集rs中的每一行--%><c:forEach var="row" items="${rs.rows}"><%--${row.字段名}获取字段的值--%>${row.RESOURCEID}---${row.DBSOURCE_NAME}---${row.DBSOURCE_TYPE}<br/></c:forEach><hr/><h3>SQLServer JNDI数据源测试</h3><%--使用sql:query标签发送SQL语句去数据库查询数据,查询的结果集保存到rs变量当中,dataSource属性指明使用的数据源--%><sql:query var="rs" dataSource="jdbc/SqlServerDataSource"><%--SQLServer JNDI数据源测试 SQL--%>select * from t_demo</sql:query><%--使用c:forEach标签遍历查询结果集rs中的每一行--%><c:forEach var="row" items="${rs.rows}"><%--${row.字段名}获取字段的值--%>${row.id}---${row.name}<br/></c:forEach></body></html>

 运行结果如下:

  

在Java代码中获取JNDI中的数据源

获取JNDI中的数据源

  编写一个JdbcUtil工具类,JdbcUtil工具类负责从JNDI容器中获取DataSource,再通过DataSource获取数据库连接。

代码如下:

  package me.gacl.util;/*** <p>ClassName: JdbcUtil<p>* <p>Description: 从JNDI容器中获取DataSource,再通过DataSource获取数据库连接<p>*/import java.sql.Connection;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import javax.naming.Context;import javax.naming.InitialContext;import javax.naming.NamingException;import com.alibaba.druid.pool.DruidDataSource;public class JdbcUtil {/*web.xml文件中的JNDI数据源引用配置<!--Oracle数据库JNDI数据源引用 --><resource-ref><description>Oracle DB Connection</description><res-ref-name>jdbc/OracleDataSource</res-ref-name><res-type>javax.sql.DataSource</res-type><res-auth>Container</res-auth></resource-ref><!--MySQL数据库JNDI数据 --><resource-ref><description>MySQL DB Connection</description><res-ref-name>jdbc/MysqlDataSource</res-ref-name><res-type>javax.sql.DataSource</res-type><res-auth>Container</res-auth></resource-ref><!--SQLServer数据库JNDI数据源引用 --><resource-ref><description>SQLServer DB Connection</description><res-ref-name>jdbc/SqlServerDataSource</res-ref-name><res-type>javax.sql.DataSource</res-type><res-auth>Container</res-auth></resource-ref>*///Oracle数据库配置的JNDI数据源连接名,后面跟的是DataSource名,DataSource名在web.xml文件中的<res-ref-name></res-ref-name>进行了配置private static final String ORACLE_DB_JNDINAME = "java:comp/env/jdbc/OracleDataSource";//MySQL数据库配置的JNDI数据源连接名,java:comp/env是必须加的,后面跟的是DataSource名private static final String MYSQL_DB_JNDINAME = "java:comp/env/jdbc/MysqlDataSource";//SQLServer数据库配置的JNDI数据源连接名,java:comp/env是必须加的,后面跟的是DataSource名private static final String SQLSERVER_DB_JNDINAME = "java:comp/env/jdbc/SqlServerDataSource";private static DruidDataSource dsOracle = null;private static DruidDataSource dsMySql = null;private static DruidDataSource dsSqlServer = null;static{try {//1、初始化名称查找上下文Context ctx = new InitialContext();//2、通过JNDI名称找到DataSourcedsOracle = (DruidDataSource) ctx.lookup(ORACLE_DB_JNDINAME);dsMySql = (DruidDataSource) ctx.lookup(MYSQL_DB_JNDINAME);dsSqlServer = (DruidDataSource) ctx.lookup(SQLSERVER_DB_JNDINAME);} catch (NamingException e) {e.printStackTrace();}}/*** MethodName: getOracleConnection* Description: 获取Oracle数据库连接* @return* @throws SQLException*/public static Connection getOracleConnection() throws SQLException {return dsOracle.getConnection();}/*** MethodName: getMySqlConnection* Description: 获取MySQL数据库连接* @return* @throws SQLException*/public static Connection getMySqlConnection() throws SQLException {return dsMySql.getConnection();}/*** MethodName: getSqlServerConnection* Description: 获取SQLServer数据库连接* @return* @throws SQLException*/public static Connection getSqlServerConnection() throws SQLException {return dsSqlServer.getConnection();}/*** @Method: release   * @Description: 释放资源,*     要释放的资源包括Connection数据库连接对象,负责执行SQL命令的Statement对象,存储查询结果的ResultSet对象** @param conn* @param st* @param rs*/ public static void release(Connection conn,Statement st,ResultSet rs){if(rs!=null){try{//关闭存储查询结果的ResultSet对象rs.close();}catch (Exception e) {e.printStackTrace();}rs = null;}if(st!=null){try{//关闭负责执行SQL命令的Statement对象st.close();}catch (Exception e) {e.printStackTrace();}}if(conn!=null){try{//关闭Connection数据库连接对象conn.close();}catch (Exception e) {e.printStackTrace();}}}}

测试JNDI数据源

  编写一个测试的Servlet,测试代码如下:

 package me.gacl.test;import java.io.IOException;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.ArrayList;import java.util.LinkedHashMap;import java.util.List;import java.util.Map;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import me.gacl.util.JdbcUtil;/*** <p>ClassName: JNDITestServlet<p>* <p>Description: <p>* <p>Company:广州利迪网络科技有限公司 <p>    * @author xudp* @version 1.0 V* @createTime 2014-10-23 上午09:32:52*/public class JNDITestServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {//Oracle数据库连接Connection oracleConnection = null;//MySql数据库连接Connection mySqlConnection = null;//SQLServer数据库连接Connection sqlServerConnection = null;//负责执行SQL的PreparedStatement对象PreparedStatement pstmtOracle = null;PreparedStatement pstmtMySQL = null;PreparedStatement pstmtSqlServer = null;//查询出来的结果集ResultSet rsOracle = null;ResultSet rsMySQL = null;ResultSet rsSqlServer = null;//存储查询出来的数据,每一行数据映射成一个Map,字段名作为key,字段的值作为valueList<Map<String, String>> oracleDataList = new ArrayList<Map<String, String>>();List<Map<String, String>> mySqlDataList = new ArrayList<Map<String, String>>();List<Map<String, String>> sqlServerDataList = new ArrayList<Map<String, String>>();try {//获取Oracle数据库连接oracleConnection = JdbcUtil.getOracleConnection();//获取MySql数据库连接mySqlConnection = JdbcUtil.getMySqlConnection();//获取SQLServer数据库连接sqlServerConnection =JdbcUtil.getSqlServerConnection();String oracleDb_Sql = "SELECT * FROM LEAD_OAMS_DBSOURCES";String mySqlDb_Sql = "SELECT * FROM LEAD_OAMS_APPLICATIONS";String sqlServerDb_Sql = "SELECT * FROM T_DEMO";pstmtOracle = oracleConnection.prepareStatement(oracleDb_Sql);pstmtMySQL = mySqlConnection.prepareStatement(mySqlDb_Sql);pstmtSqlServer = sqlServerConnection.prepareStatement(sqlServerDb_Sql);//执行查询,查询结果存储到ResultSet结果集中rsOracle = pstmtOracle.executeQuery();rsMySQL = pstmtMySQL.executeQuery();rsSqlServer = pstmtSqlServer.executeQuery();//循环结果集中的数据 while(rsOracle.next()){Map<String, String> oracleDataMap = new LinkedHashMap<String, String>();//取出结果集中的数据,每一行数据映射成一个map集合oracleDataMap.put("resourceid", rsOracle.getString("RESOURCEID"));oracleDataMap.put("dbsource_name", rsOracle.getString("DBSOURCE_NAME"));oracleDataMap.put("dbsource_type", rsOracle.getString("DBSOURCE_TYPE"));//将代表每一行数据的Map集合添加到List集合中oracleDataList.add(oracleDataMap);}while(rsMySQL.next()){Map<String, String> mySqlDataMap = new LinkedHashMap<String, String>();mySqlDataMap.put("resourceid", rsMySQL.getString("resourceid"));mySqlDataMap.put("app_name", rsMySQL.getString("app_name"));mySqlDataList.add(mySqlDataMap);}while(rsSqlServer.next()){Map<String, String> sqlServerDataMap = new LinkedHashMap<String, String>();sqlServerDataMap.put("id", rsSqlServer.getString("id"));sqlServerDataMap.put("name", rsSqlServer.getString("name"));sqlServerDataList.add(sqlServerDataMap);}//将数据集合存储到request对象发送到页面进行显示request.setAttribute("oracleDataList", oracleDataList);request.setAttribute("mySqlDataList", mySqlDataList);request.setAttribute("sqlServerDataList", sqlServerDataList);//跳转到JNDITest.jsp页面显示数据request.getRequestDispatcher("/JNDITest.jsp").forward(request, response);} catch (SQLException e) {e.printStackTrace();}finally{//释放资源JdbcUtil.release(oracleConnection, pstmtOracle, rsOracle);JdbcUtil.release(mySqlConnection, pstmtMySQL, rsMySQL);JdbcUtil.release(sqlServerConnection, pstmtSqlServer, rsSqlServer);}}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request,response);}}

 JNDITest.jsp页面代码如下:

 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%--引入JSTL标签库 --%><%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%><!DOCTYPE HTML><html><head><title>JNDI测试</title></head><body><h3>从Oracle数据库中取出来的数据</h3><%--使用c:forEach标签遍历List集合--%><c:forEach var="oracleDataMap" items="${oracleDataList}">${oracleDataMap.resourceid}---${oracleDataMap.dbsource_name}---${oracleDataMap.dbsource_type}<br/></c:forEach><hr/><h3>从mySql数据库中取出来的数据</h3><%--使用c:forEach标签遍历List集合--%><c:forEach var="mySqlDataMap" items="${mySqlDataList}">${mySqlDataMap.resourceid}---${mySqlDataMap.app_name}<br/></c:forEach><hr/><h3>从sqlServer数据库中取出来的数据</h3><%--使用c:forEach标签遍历List集合--%><c:forEach var="sqlServerDataMap" items="${sqlServerDataList}">${sqlServerDataMap.id}---${sqlServerDataMap.name}<br/></c:forEach></body></html>

  运行结果如下:

JavaWeb开发与代码的编写(二十四)相关推荐

  1. JavaWeb开发与代码的编写(一)

    JavaWeb开发与代码的编写(一) 绝对路径与相对路径 在JavaWeb开发中,常使用绝对路径的方式来引入JavaScript和CSS文件,这样可以避免因为目录变动导致引入文件找不到的情况,常用的做 ...

  2. 微信开发与代码的编写(二)

    微信开发与代码的编写(二) 普通消息的接收和回复 微信公众平台消息管理接口介绍 要实现微信公众号的普通消息的接收和回复,我们需要先熟悉微信公众平台API中消息接口部分,点此进入,点击后将进入到[消息管 ...

  3. 【软件开发底层知识修炼】二十四 ABI之函数调用约定

    上一篇文章学习了Linux环境下的函数栈帧的形成与摧毁.点击链接查看相关文章:软件开发底层知识修炼]二十三 ABI-应用程序二进制接口三之深入理解函数栈帧的形成与摧毁 本篇文章继续学习ABI接口相关的 ...

  4. 【软件开发底层知识修炼】二十五 ABI之函数调用约定二之函数返回值为结构体时的约定

    上一篇文章学习了几种函数调用约定的区别,点击链接查看上一篇文章:[软件开发底层知识修炼]二十四 ABI之函数调用约定 本篇文章继续学习函数调用约定中,关于函数返回值的问题.当函数返回值为结构体时,函数 ...

  5. 【软件开发底层知识修炼】二十六 ABI-应用程序二进制接口 学习总结文章目录

    前面学习了ABI的知识,感觉受益良多.对底层与编译器有更加深刻的认识,为此这里将前面写过的关于ABI 的文章给列出来,方便学习与翻阅. [软件开发底层知识修炼]二十一 ABI-应用程序二进制接口一 [ ...

  6. 【Visual C++】游戏开发五十七 浅墨DirectX教程二十四 打造游戏GUI界面(二)

    本系列文章由zhmxy555(毛星云)编写,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/16922703 作者:毛星 ...

  7. matlab火星漫游车转向控制,OSG开发笔记(二十四):OSG漫游之平移与转向

    若该文为原创文章,未经允许不得转载 原博主博客地址:https://blog.csdn.net/qq21497936 本文章博客地址:https://blog.csdn.net/qq21497936/ ...

  8. 饥荒联机版Mod开发——配置代码环境(二)

    饥荒联机版Mod开发--配置代码环境(二) 前言 下载VS Code和Lua插件 建立工作区 配置Lua插件 Git和GitHub(可选) 排除多余文件 删除scripts里多余文件 VS Code快 ...

  9. WebService开发与代码的编写

    WebService开发与代码的编写 大家或多或少都听过 WebService(Web服务),有一段时间很多计算机期刊.书籍和网站都大肆的提及和宣传WebService技术,其中不乏很多吹嘘和做广告的 ...

最新文章

  1. spring是如何解析自己的配置文件的
  2. 每天最少编码1000行
  3. hibernate常见错误及解决方法总结
  4. 分类算法——K近邻算法及其R实现
  5. Java 字符编码与解码
  6. DOM操作之确定元素大小
  7. HCIE Security 防火墙反病毒 备考笔记(幕布)
  8. IBM公布未来5年将改变人类生活的五大科技
  9. JDK动态代理入门、JDK动态代理原理、为什么JDK动态代理是基于接口的
  10. 小米2s安卓10刷机包_小米10刷机包
  11. Samsung ML-1640/1641/1645/2240/2241/2245/scx4200/4300/4623/4824/4828免费清零软件2.1.2完全版
  12. 群晖nas介绍文档_我的NAS我的地盘 篇三:群晖NAS软件介绍与应用之DS file篇
  13. 【基金研究】《公募权益类基金投资者盈利洞察报告》
  14. UVC Camera简单介绍
  15. 如何在 Linux 和 Unix 上安装 git?
  16. [极致用户体验] 微信设置大字号后,iOS加载网页时闪动怎么办?
  17. 使用微信+树莓派+Arduino+服务器构建你的看门狗
  18. IEEE论文公式快捷获取
  19. 孙向晖-《领域驱动设计》读书心得交流会-UMLChina讲座-实录
  20. 分享 :如何成为一个合格的数据架构师?

热门文章

  1. 解耦、削峰、异步的理解
  2. H5 Handlebars的简单使用
  3. 瑞幸咖啡贵不贵?咖啡不贵,商业却很贵
  4. 离散数学-图论-欧拉图、哈密顿图、二部图、平面图(14)
  5. 0xc000007b应用程序无法正常启动解决方案(亲测有效)
  6. SEO面试题与面试攻略
  7. SpringBoot成长笔记(一)环境搭建
  8. java数据类型有哪几种_Java数据类型有哪些?Java数据类型包括几种?
  9. 如何在sql内写循环语句
  10. 西安邮电大学python期末考试_python想过期末考试再怎么学?