JNDI数据源配置在JNDI-Resources-HOWTO中得到广泛的覆盖。但是,反馈表明,单个配置的具体细节可能相当棘手。
这里是一些用于流行数据库的示例配置,以及一些关于db使用的一般提示。
注意,JNDI资源配置在Tomcat 7.x和Tomcat 8.x之间有所改变,因为它们使用不同版本的Apache Commons DBCP库。您很可能需要修改旧的JNDI资源配置,以匹配下面示例中的语法,以使其在Tomcat 9中工作。有关详细信息,请参阅“Tomcat迁移指南”。
java.sql.DriverManager支持服务提供机制。此功能是通过来自META-INF/services/java.sql.Driver文件来发布所有可用JDBC驱动程序,它们自动发现,加载和注册,从而避免在创建数据库驱动程序之前明确加载数据库驱动程序。 但是,在servlet容器环境的所有Java版本中,其实现都是破坏的。原因是java.sql.DriverManager只会扫描一次驱动程序。
Apache Tomcat附带的JRE内存泄漏防护侦听器通过在Tomcat启动期间触发驱动扫描来解决此问题。这个功能默认情况下启用。这意味着只有在监听器可见的库(例如$ CATALINA_BASE/lib中的库)将被扫描用于数据库驱动程序。如果您正在考虑禁用此功能,请注意,扫描将由使用JDBC的第一个Web应用程序触发,重新加载此Web应用程序以及依赖此功能的其他Web应用程序会出现故障。
因此,在WEB-INF/lib目录中的数据库驱动程序,不能依赖于服务提供者机制,应明确注册驱动程序。
java.sql.DriverManager中的驱动程序列表也是内存泄漏的已知来源。 Web应用程序注册的任何驱动程序必须在Web应用程序显式的停止、注销。当Web应用程序停止时,Tomcat将尝试自动发现和注销由Web应用程序类加载器加载的任何JDBC驱动程序。但是,预期应用程序通过ServletContextListener自己执行此操作。
Apache Tomcat中的默认数据库连接池实现依赖于Apache Commons项目中的库。 使用以下库:
DBCP 2.0已提供对JDBC 4.1的支持。
参考:http://commons.apache.org/proper/commons-dbcp/configuration.html
目的:防止数据库连接池泄漏
优势:数据库连接池创建并管理与数据库的连接池。回收和重用已经存在的与数据库的连接比打开新连接更有效率。
问题:连接池有一个问题。 Web应用程序必须明确地关闭ResultSet,Statement和Connection。 Web应用程序关闭这些资源的失败可能导致它们再次无法再次使用数据库连接源以及数据库连接池“泄漏”。如果没有可用的连接,最终可能导致Web应用程序数据库连接失败。
解决方案:有一个解决这个问题的办法。 Apache Commons DBCP可以配置为跟踪和恢复这些废弃的数据库连接。它不仅可以恢复它们,还可以为打开这些资源的代码生成一个堆栈跟踪,而不会关闭它们。
要配置DBCP DataSource,以便删除和回收已放弃的数据库连接,请将以下属性之一或全部添加到DBCP DataSource的资源配置中:
removeAbandonedOnBorrow =真
removeAbandonedOnMaintenance =真
这两个属性的默认值为false。请注意,除非通过将timeBetweenEvictionRunsMillis设置为正值来启用池维护,否则removeAbandonedOnMaintenance无效。有关这些属性的完整文档,请参阅DBCP文档。
使用removeAbandonedTimeout属性设置数据库连接在被视为已被放弃之前已经空闲的秒数。
removeAbandonedTimeout = “60”
删除废弃连接的默认超时时间为300秒。
如果要让DBCP记录放弃数据库连接资源的代码的堆栈跟踪,则可以将logAbandoned属性设置为true。
logAbandoned = “真”
默认值为false。
1、驱动下载:https://www.mysql.com/products/connector/
2、配置context.xml:在/META-INF/context.xml配置如下:
<Context>
<Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource"
maxTotal="100" maxIdle="30" maxWaitMillis="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 Appdescription>
<resource-ref>
<description>DB Connectiondescription>
<res-ref-name>jdbc/TestDBres-ref-name>
<res-type>javax.sql.DataSourceres-type>
<res-auth>Containerres-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 Testtitle>
head>
<body>
<h2>Resultsh2>
<c:forEach var="row" items="${rs.rows}">
Foo ${row.foo}<br/>
Bar ${row.bar}<br/>
c:forEach>
body>
html>
备注:上面的代码使用了JSTL,需要下载相应的库,下载地址:
http://tomcat.apache.org/taglibs/standard/
只需要将:jstl.jar、 standard.jar 拷贝到应用程序的WEB-INF/lib directory.中即可。
1、配置Context
"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" maxTotal="20" maxIdle="10"
maxWaitMillis="-1"/>
2、配置web.xml
<resource-ref>
<description>Oracle Datasource exampledescription>
<res-ref-name>jdbc/myoracleres-ref-name>
<res-type>javax.sql.DataSourceres-type>
<res-auth>Containerres-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.
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;
}
}
关注我的技术公众号,查看更多优质技术文章推送
微信扫一扫下方二维码即可关注: