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数据源
2.1、前期准备工作
创建一个Web测试项目Druid_JNDI_Config, 将下载下来druid-1.0.9.jar和log4j-1.2.17.jar添加到项目中,在项目的META-INF目录下创建一个context.xml文件
目录结构如下图所示:
在tomcat服务器的lib目录下添加Oracle、MySQL、SQLServer三种数据库的驱动jar包,如下图所示:
2.2、 在context.xml文件中加入JNDI的配置信息
在context.xml文件中加入如下配置信息
1 < Context > 2 <!-- 使用阿里巴巴的DruidDataSource配置针对Oracle数据库的JNDI数据源 --> 3 < Resource 4 name ="jdbc/OracleDataSource" 5 factory ="com.alibaba.druid.pool.DruidDataSourceFactory" 6 auth ="Container" 7 type ="javax.sql.DataSource" 8 driverClassName ="oracle.jdbc.OracleDriver" 9 url ="jdbc:oracle:thin:@192.168.1.229:1521:lead" 10 username ="lead_oams" 11 password ="p" 12 maxActive ="50" 13 maxWait ="10000" 14 removeabandoned ="true" 15 removeabandonedtimeout ="60" 16 logabandoned ="false" 17 filters ="stat" /> 18 19 <!-- 使用阿里巴巴的DruidDataSource配置针对MySQL数据库的JNDI数据源 --> 20 < Resource 21 name ="jdbc/MysqlDataSource" 22 factory ="com.alibaba.druid.pool.DruidDataSourceFactory" 23 auth ="Container" 24 type ="javax.sql.DataSource" 25 driverClassName ="com.mysql.jdbc.Driver" 26 url ="jdbc:mysql://192.168.1.233:3306/lead_oams?useUnicode=true&characterEncoding=utf-8" 27 username ="lead_system" 28 password ="password" 29 maxActive ="50" 30 maxWait ="10000" 31 removeabandoned ="true" 32 removeabandonedtimeout ="60" 33 logabandoned ="false" 34 filters ="stat" /> 35 36 <!-- 使用阿里巴巴的DruidDataSource配置针对SQLServer数据库的JNDI数据源 --> 37 < Resource 38 name ="jdbc/SqlServerDataSource" 39 auth ="Container" 40 factory ="com.alibaba.druid.pool.DruidDataSourceFactory" 41 type ="javax.sql.DataSource" 42 driverClass ="com.microsoft.sqlserver.jdbc.SQLServerDriver" 43 url ="jdbc:sqlserver://192.168.1.61:1433;DatabaseName=gaclTest" 44 username ="sa" 45 password ="p@ssw0rd" 46 maxActive ="50" 47 maxWait ="10000" 48 removeabandoned ="true" 49 removeabandonedtimeout ="60" 50 logabandoned ="false" 51 filters ="stat" /> 52 </ Context >
配置项中指定了各个参数后,在连接池内部是这么使用这些参数的。数据库连接池在初始化的时候会创建initialSize个连接,当有数据库操作时,会从池中取出一个连接。如果当前池中正在使用的连接数等于maxActive,则会等待一段时间,等待其他操作释放掉某一个连接,如果这个等待时间超过了maxWait,则会报错;如果当前正在使用的连接数没有达到maxActive,则判断当前是否空闲连接,如果有则直接使用空闲连接,如果没有则新建立一个连接。在连接使用完毕后,不是将其物理连接关闭,而是将其放入池中等待其他操作复用。同时连接池内部有机制判断,如果当前的总的连接数少于miniIdle,则会建立新的空闲连接,以保证连接数得到miniIdle。如果当前连接池中某个连接在空闲了timeBetweenEvictionRunsMillis时间后任然没有使用,则被物理性的关闭掉。有些数据库连接的时候有超时限制(mysql连接在8小时后断开),或者由于网络中断等原因,连接池的连接会出现失效的情况,这时候设置一个testWhileIdle参数为true,可以保证连接池内部定时检测连接的可用性,不可用的连接会被抛弃或者重建,最大情况的保证从连接池中得到的Connection对象是可用的。当然,为了保证绝对的可用性,你也可以使用testOnBorrow为true(即在获取Connection对象时检测其可用性),
不过这样会影响性能。
2.3、在web.xml引用JDNI数据源
在web.xml文件中加入如下的配置引用JNDI数据源
1 <? xml version="1.0" encoding="UTF-8" ?> 2 < web-app version ="2.5" 3 xmlns ="http://java.sun.com/xml/ns/javaee" 4 xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation ="http://java.sun.com/xml/ns/javaee 6 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" > 7 < welcome-file-list > 8 < welcome-file > index.jsp </ welcome-file > 9 </ welcome-file-list > 10 11 <!-- 12 JNDI配置的资源引用: 13 • res-ref-name:表示引用资源的名称 14 • res-type:此资源对应的类型为javax.sql.DataSource 15 • res-auth:容器授权管理 16 --> 17 <!-- Oracle数据库JNDI数据源引用 --> 18 < resource-ref > 19 < description > Oracle DB Connection </ description > 20 < res-ref-name > jdbc/OracleDataSource </ res-ref-name > 21 < res-type > javax.sql.DataSource </ res-type > 22 < res-auth > Container </ res-auth > 23 </ resource-ref > 24 25 <!-- MySQL数据库JNDI数据 --> 26 < resource-ref > 27 < description > MySQL DB Connection </ description > 28 < res-ref-name > jdbc/MysqlDataSource </ res-ref-name > 29 < res-type > javax.sql.DataSource </ res-type > 30 < res-auth > Container </ res-auth > 31 </ resource-ref > 32 33 <!-- SQLServer数据库JNDI数据源引用 --> 34 < resource-ref > 35 < description > SQLServer DB Connection </ description > 36 < res-ref-name > jdbc/SqlServerDataSource </ res-ref-name > 37 < res-type > javax.sql.DataSource </ res-type > 38 < res-auth > Container </ res-auth > 39 </ resource-ref > 40 </ web-app >
2.4、 测试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测试页面如下:
1 <% @ page language = " java " import = " java.util.* " pageEncoding = " UTF-8 " %> 2 <% -- 引入JSTL标签库 -- %> 3 <% @ taglib uri = " http://java.sun.com/jsp/jstl/core " prefix = " c " %> 4 <% @ taglib uri = " http://java.sun.com/jsp/jstl/sql " prefix = " sql " %> 5 <! DOCTYPE HTML > 6 < html > 7 < head > 8 < title > DRUID配置JNDI数据源连接测试 </ title > 9 </ head > 10 11 < body > 12 < h3 > 针对MySQL数据库JNDI数据源测试 </ h3 > 13 <% -- 使用sql:query标签发送SQL语句去数据库查询数据,查询的结果集保存到rs变量当中,dataSource属性指明使用的数据源 -- %> 14 < sql:query var ="rs" dataSource ="jdbc/MysqlDataSource" > 15 <% -- MySQL JNDI数据源测试 SQL -- %> 16 select * from lead_oams_applications 17 </ sql:query > 18 <% -- 使用c:forEach标签遍历查询结果集rs中的每一行 -- %> 19 < c:forEach var ="row" items ="${rs.rows}" > 20 <% -- ${row.字段名}获取字段的值 -- %> 21 ${row.resourceid}---${row.app_name} < br /> 22 </ c:forEach > 23 < hr /> 24 < h3 > 针对Oracle数据库JNDI数据源测试 </ h3 > 25 <% -- 使用sql:query标签发送SQL语句去数据库查询数据,查询的结果集保存到rs变量当中,dataSource属性指明使用的数据源 -- %> 26 < sql:query var ="rs" dataSource ="jdbc/OracleDataSource" > 27 <% -- Oracle JNDI数据源测试 SQL -- %> 28 SELECT * FROM LEAD_OAMS_DBSOURCES 29 </ sql:query > 30 <% -- 使用c:forEach标签遍历查询结果集rs中的每一行 -- %> 31 < c:forEach var ="row" items ="${rs.rows}" > 32 <% -- ${row.字段名}获取字段的值 -- %> 33 ${row.RESOURCEID}---${row.DBSOURCE_NAME}---${row.DBSOURCE_TYPE} < br /> 34 </ c:forEach > 35 < hr /> 36 < h3 > SQLServer JNDI数据源测试 </ h3 > 37 <% -- 使用sql:query标签发送SQL语句去数据库查询数据,查询的结果集保存到rs变量当中,dataSource属性指明使用的数据源 -- %> 38 < sql:query var ="rs" dataSource ="jdbc/SqlServerDataSource" > 39 <% -- SQLServer JNDI数据源测试 SQL -- %> 40 select * from t_demo 41 </ sql:query > 42 <% -- 使用c:forEach标签遍历查询结果集rs中的每一行 -- %> 43 < c:forEach var ="row" items ="${rs.rows}" > 44 <% -- ${row.字段名}获取字段的值 -- %> 45 ${row.id}---${row.name} < br /> 46 </ c:forEach > 47 </ body > 48 </ html >
运行结果如下:
三、在Java代码中获取JNDI中的数据源
3.1、获取JNDI中的数据源
编写一个JdbcUtil工具类,JdbcUtil工具类负责从JNDI容器中获取DataSource,再通过DataSource获取数据库连接。
代码如下:
1 package me.gacl.util; 2 3 /** 4 * <p>ClassName: JdbcUtil<p> 5 * <p>Description: 从JNDI容器中获取DataSource,再通过DataSource获取数据库连接<p> 6 */ 7 import java.sql.Connection; 8 import java.sql.ResultSet; 9 import java.sql.SQLException; 10 import java.sql.Statement; 11 import javax.naming.Context; 12 import javax.naming.InitialContext; 13 import javax.naming.NamingException; 14 import com.alibaba.druid.pool.DruidDataSource; 15 16 public class JdbcUtil { 17 18 /* 19 web.xml文件中的JNDI数据源引用配置 20 21 <!--Oracle数据库JNDI数据源引用 --> 22 <resource-ref> 23 <description>Oracle DB Connection</description> 24 <res-ref-name>jdbc/OracleDataSource</res-ref-name> 25 <res-type>javax.sql.DataSource</res-type> 26 <res-auth>Container</res-auth> 27 </resource-ref> 28 29 <!--MySQL数据库JNDI数据 --> 30 <resource-ref> 31 <description>MySQL DB Connection</description> 32 <res-ref-name>jdbc/MysqlDataSource</res-ref-name> 33 <res-type>javax.sql.DataSource</res-type> 34 <res-auth>Container</res-auth> 35 </resource-ref> 36 37 <!--SQLServer数据库JNDI数据源引用 --> 38 <resource-ref> 39 <description>SQLServer DB Connection</description> 40 <res-ref-name>jdbc/SqlServerDataSource</res-ref-name> 41 <res-type>javax.sql.DataSource</res-type> 42 <res-auth>Container</res-auth> 43 </resource-ref> 44 */ 45 46 // Oracle数据库配置的JNDI数据源连接名,后面跟的是DataSource名,DataSource名在web.xml文件中的<res-ref-name></res-ref-name>进行了配置 47 private static final String ORACLE_DB_JNDINAME = "java:comp/env/jdbc/OracleDataSource" ; 48 // MySQL数据库配置的JNDI数据源连接名,java:comp/env是必须加的,后面跟的是DataSource名 49 private static final String MYSQL_DB_JNDINAME = "java:comp/env/jdbc/MysqlDataSource" ; 50 // SQLServer数据库配置的JNDI数据源连接名,java:comp/env是必须加的,后面跟的是DataSource名 51 private static final String SQLSERVER_DB_JNDINAME = "java:comp/env/jdbc/SqlServerDataSource" ; 52 53 private static DruidDataSource dsOracle = null ; 54 private static DruidDataSource dsMySql = null ; 55 private static DruidDataSource dsSqlServer = null ; 56 57 static { 58 try { 59 // 1、初始化名称查找上下文 60 Context ctx = new InitialContext(); 61 // 2、通过JNDI名称找到DataSource 62 dsOracle = (DruidDataSource) ctx.lookup(ORACLE_DB_JNDINAME); 63 dsMySql = (DruidDataSource) ctx.lookup(MYSQL_DB_JNDINAME); 64 dsSqlServer = (DruidDataSource) ctx.lookup(SQLSERVER_DB_JNDINAME); 65 } catch (NamingException e) { 66 e.printStackTrace(); 67 } 68 } 69 70 /** 71 * MethodName: getOracleConnection 72 * Description: 获取Oracle数据库连接 73 * @author xudp 74 * @return 75 * @throws SQLException 76 */ 77 public static Connection getOracleConnection() throws SQLException { 78 return dsOracle.getConnection(); 79 } 80 81 /** 82 * MethodName: getMySqlConnection 83 * Description: 获取MySQL数据库连接 84 * @author xudp 85 * @return 86 * @throws SQLException 87 */ 88 public static Connection getMySqlConnection() throws SQLException { 89 return dsMySql.getConnection(); 90 } 91 92 /** 93 * MethodName: getSqlServerConnection 94 * Description: 获取SQLServer数据库连接 95 * @author xudp 96 * @return 97 * @throws SQLException 98 */ 99 public static Connection getSqlServerConnection() throws SQLException { 100 return dsSqlServer.getConnection(); 101 } 102 103 /** 104 * @Method: release 105 * @Description: 释放资源, 106 * 要释放的资源包括Connection数据库连接对象,负责执行SQL命令的Statement对象,存储查询结果的ResultSet对象 107 * @Anthor:孤傲苍狼 108 * 109 * @param conn 110 * @param st 111 * @param rs 112 */ 113 public static void release(Connection conn,Statement st,ResultSet rs){ 114 if (rs!= null ){ 115 try { 116 // 关闭存储查询结果的ResultSet对象 117 rs.close(); 118 } catch (Exception e) { 119 e.printStackTrace(); 120 } 121 rs = null ; 122 } 123 if (st!= null ){ 124 try { 125 // 关闭负责执行SQL命令的Statement对象 126 st.close(); 127 } catch (Exception e) { 128 e.printStackTrace(); 129 } 130 } 131 132 if (conn!= null ){ 133 try { 134 // 关闭Connection数据库连接对象 135 conn.close(); 136 } catch (Exception e) { 137 e.printStackTrace(); 138 } 139 } 140 } 141 }
3.2、测试JNDI数据源
编写一个测试的Servlet,测试代码如下:
1 package me.gacl.test; 2 3 import java.io.IOException; 4 import java.sql.Connection; 5 import java.sql.PreparedStatement; 6 import java.sql.ResultSet; 7 import java.sql.SQLException; 8 import java.util.ArrayList; 9 import java.util.LinkedHashMap; 10 import java.util.List; 11 import java.util.Map; 12 import javax.servlet.ServletException; 13 import javax.servlet.http.HttpServlet; 14 import javax.servlet.http.HttpServletRequest; 15 import javax.servlet.http.HttpServletResponse; 16 import me.gacl.util.JdbcUtil; 17 18 /** 19 * <p>ClassName: JNDITestServlet<p> 20 * <p>Description: <p> 21 * <p>Company:广州利迪网络科技有限公司 <p> 22 * @author xudp 23 * @version 1.0 V 24 * @createTime 2014-10-23 上午09:32:52 25 */ 26 public class JNDITestServlet extends HttpServlet { 27 28 public void doGet(HttpServletRequest request, HttpServletResponse response) 29 throws ServletException, IOException { 30 31 // Oracle数据库连接 32 Connection oracleConnection = null ; 33 // MySql数据库连接 34 Connection mySqlConnection = null ; 35 // SQLServer数据库连接 36 Connection sqlServerConnection = null ; 37 38 // 负责执行SQL的PreparedStatement对象 39 PreparedStatement pstmtOracle = null ; 40 PreparedStatement pstmtMySQL = null ; 41 PreparedStatement pstmtSqlServer = null ; 42 43 // 查询出来的结果集 44 ResultSet rsOracle = null ; 45 ResultSet rsMySQL = null ; 46 ResultSet rsSqlServer = null ; 47 48 // 存储查询出来的数据,每一行数据映射成一个Map,字段名作为key,字段的值作为value 49 List<Map<String, String>> oracleDataList = new ArrayList<Map<String, String>> (); 50 List<Map<String, String>> mySqlDataList = new ArrayList<Map<String, String>> (); 51 List<Map<String, String>> sqlServerDataList = new ArrayList<Map<String, String>> (); 52 53 try { 54 55 // 获取Oracle数据库连接 56 oracleConnection = JdbcUtil.getOracleConnection(); 57 // 获取MySql数据库连接 58 mySqlConnection = JdbcUtil.getMySqlConnection(); 59 // 获取SQLServer数据库连接 60 sqlServerConnection = JdbcUtil.getSqlServerConnection(); 61 62 String oracleDb_Sql = "SELECT * FROM LEAD_OAMS_DBSOURCES" ; 63 String mySqlDb_Sql = "SELECT * FROM LEAD_OAMS_APPLICATIONS" ; 64 String sqlServerDb_Sql = "SELECT * FROM T_DEMO" ; 65 66 pstmtOracle = oracleConnection.prepareStatement(oracleDb_Sql); 67 pstmtMySQL = mySqlConnection.prepareStatement(mySqlDb_Sql); 68 pstmtSqlServer = sqlServerConnection.prepareStatement(sqlServerDb_Sql); 69 70 // 执行查询,查询结果存储到ResultSet结果集中 71 rsOracle = pstmtOracle.executeQuery(); 72 rsMySQL = pstmtMySQL.executeQuery(); 73 rsSqlServer = pstmtSqlServer.executeQuery(); 74 75 // 循环结果集中的数据 76 while (rsOracle.next()){ 77 Map<String, String> oracleDataMap = new LinkedHashMap<String, String> (); 78 // 取出结果集中的数据,每一行数据映射成一个map集合 79 oracleDataMap.put("resourceid", rsOracle.getString("RESOURCEID" )); 80 oracleDataMap.put("dbsource_name", rsOracle.getString("DBSOURCE_NAME" )); 81 oracleDataMap.put("dbsource_type", rsOracle.getString("DBSOURCE_TYPE" )); 82 // 将代表每一行数据的Map集合添加到List集合中 83 oracleDataList.add(oracleDataMap); 84 } 85 86 while (rsMySQL.next()){ 87 Map<String, String> mySqlDataMap = new LinkedHashMap<String, String> (); 88 mySqlDataMap.put("resourceid", rsMySQL.getString("resourceid" )); 89 mySqlDataMap.put("app_name", rsMySQL.getString("app_name" )); 90 mySqlDataList.add(mySqlDataMap); 91 } 92 93 while (rsSqlServer.next()){ 94 Map<String, String> sqlServerDataMap = new LinkedHashMap<String, String> (); 95 sqlServerDataMap.put("id", rsSqlServer.getString("id" )); 96 sqlServerDataMap.put("name", rsSqlServer.getString("name" )); 97 sqlServerDataList.add(sqlServerDataMap); 98 } 99 100 // 将数据集合存储到request对象发送到页面进行显示 101 request.setAttribute("oracleDataList" , oracleDataList); 102 request.setAttribute("mySqlDataList" , mySqlDataList); 103 request.setAttribute("sqlServerDataList" , sqlServerDataList); 104 // 跳转到JNDITest.jsp页面显示数据 105 request.getRequestDispatcher("/JNDITest.jsp" ).forward(request, response); 106 107 } catch (SQLException e) { 108 e.printStackTrace(); 109 } finally { 110 // 释放资源 111 JdbcUtil.release(oracleConnection, pstmtOracle, rsOracle); 112 JdbcUtil.release(mySqlConnection, pstmtMySQL, rsMySQL); 113 JdbcUtil.release(sqlServerConnection, pstmtSqlServer, rsSqlServer); 114 } 115 } 116 117 public void doPost(HttpServletRequest request, HttpServletResponse response) 118 throws ServletException, IOException { 119 doGet(request,response); 120 } 121 }
JNDITest.jsp页面代码如下:
1 <% @ page language = " java " import = " java.util.* " pageEncoding = " UTF-8 " %> 2 <% -- 引入JSTL标签库 -- %> 3 <% @ taglib uri = " http://java.sun.com/jsp/jstl/core " prefix = " c " %> 4 <! DOCTYPE HTML > 5 < html > 6 < head > 7 < title > JNDI测试 </ title > 8 </ head > 9 10 < body > 11 < h3 > 从Oracle数据库中取出来的数据 </ h3 > 12 <% -- 使用c:forEach标签遍历List集合 -- %> 13 < c:forEach var ="oracleDataMap" items ="${oracleDataList}" > 14 ${oracleDataMap.resourceid}---${oracleDataMap.dbsource_name}---${oracleDataMap.dbsource_type} < br /> 15 </ c:forEach > 16 < hr /> 17 < h3 > 从mySql数据库中取出来的数据 </ h3 > 18 <% -- 使用c:forEach标签遍历List集合 -- %> 19 < c:forEach var ="mySqlDataMap" items ="${mySqlDataList}" > 20 ${mySqlDataMap.resourceid}---${mySqlDataMap.app_name} < br /> 21 </ c:forEach > 22 < hr /> 23 < h3 > 从sqlServer数据库中取出来的数据 </ h3 > 24 <% -- 使用c:forEach标签遍历List集合 -- %> 25 < c:forEach var ="sqlServerDataMap" items ="${sqlServerDataList}" > 26 ${sqlServerDataMap.id}---${sqlServerDataMap.name} < br /> 27 </ c:forEach > 28 </ body > 29 </ html >
运行结果如下: