针对常用的数据库,我们已经给 Tomcat 用户提供了一些配置范例,以及关于数据库使用的一些通用技巧。本章就将展示这些范例和技巧。
另外,虽然有些注意事项来自于用户所提供的配置和反馈信息,但你可能也有不同的实践。如果经过试验,你发现某些配置可能具有广泛的助益作用,或者你觉得它们会使本章内容更加完善,请务必不吝赐教。
请注意,对比 Tomcat 7.x 和 Tomcat 8.x,JNDI 资源配置多少有些不同,这是因为使用的 Apache Commons DBCP 库的版本不同所致。所以,为了在 Tomcat 8 中使用,你最好修改老版本的 JNDI 资源配置,以便能够匹配下文范例中的格式。
另外还要提示的是,一般来说(特别是对于本教程而言),JNDI 数据源配置会假定你已经理解了 Context 与 Host 的配置偏好,其中包括在后者配置偏好中的应用自动部署的相关内容。
java.sql.DriverManager
支持服务提供者机制。这项功能的实际作用在于:对于所有可用的 JDBC 驱动,只要它们声明提供 META-INF/services/java.sql.Driver
文件,就会被自动发现、加载并注册,从而减轻了我们在创建 JDBC 连接之前还需要显式地加载数据库驱动的负担。但在 servlet 容器环境的所有 Java 版本中,却根本没法实现这种功能。问题在于 java.sql.DriverManager
只会扫描一次驱动。
Tomcat 自带的阻止 JRE 内存泄漏侦听器可以在一定程度上解决这个问题,它会在 Tomcat 启动时触发驱动扫描。该侦听器默认是启用的。只有可见于该侦听器的库(比如 $CATALINA_BASE/lib
中的库)才能被数据库驱动所扫描。如果你想禁用该功能,那么一定要记住:首先使用 JDBC 的 Web 应用会触发扫描,从而当该应用重新加载时会出错;对于其他依赖该功能的 Web 应用来说也会导致出错。
所以,假如应用的 WEB-INF/lib
目录中存在数据库驱动,那么这些应用就不能依赖服务提供者机制,而应该显式地注册驱动。
java.sql.DriverManager
中的驱动已经被认为是内存泄露之源。当 Web 应用停止运行时,它所注册的任何驱动都必须重新注册。当 Web 应用停止运行时,Tomcat 会尝试自动寻找并重新注册任何由 Web 应用类加载器所加载的 JDBC 驱动。但最好是由应用通过 ServletContextListener
来实现这一点。
Apache Tomcat 的默认数据库连接池实现基于的是 Apache Commons 项目的库,具体来说是这两个库:
这两个库都位于一个 JAR 文件中:$CATALINA_HOME/lib/tomcat-dbcp.jar
。但该文件只包括连接池所需要的类,包名也已经改变了,以避免与应用冲突。
DBCP 2.0 支持 JDBC 4.1。
数据库连接池创建并管理着一些与数据库的连接。与打开新的连接相比,回收或重用现有的数据库连接要更为高效一些。
连接池化还存在一个问题。Web 应用必须明确地关闭 ResultSet、Statement,以及 Connection。假如 Web 应用无法关闭这些资源时,会导致这些资源再也无法被重用,从而造成了数据库连接池“泄露”。如果再也没有可用连接时,最终这将导致 Web 应用数据库连接失败。
针对该问题,有一个解决办法:通过配置 Apache Commons DBCP,记录并恢复这些废弃的数据库连接。它不仅能恢复这些连接,而且还能针对打开这些连接而又永远不关闭它们的代码生成堆栈跟踪。
为了配置 DBCP 数据源来移除并回收废弃的数据库连接,将下列属性(一个或全部)添加到你的 DBCP 数据源中的Resource
配置中:
removeAbandonedOnBorrow=true
removeAbandonedOnMaintenance=true
以上属性默认都为 false
。注意,只有当 timeBetweenEvictionRunsMillis
为正值,从而启用池维护时,removeAbandonedOnMaintenance
才能生效。
使用 removeAbandonedTimeout
属性设置某个数据库连接闲置的秒数,超过此时段,即被认为是废弃连接。
removeAbandonedTimeout="60"
默认的去除废弃连接的超时为 300 秒。
将 logAbandoned
设为 true
,可以让 DBCP 针对那些抛弃数据库连接资源的代码,记录堆栈跟踪信息。
logAbandoned="true"
默认为 false
。