在Java Web应用开发中,数据库连接管理是个绕不开的话题。记得我刚入行时,每个Servlet里都写满了重复的DriverManager.getConnection(),不仅维护困难,性能也差。后来接触到连接池技术,才算找到了正途。而JNDI数据源,可以说是连接池的最佳实践方案之一。
JNDI(Java Naming and Directory Interface)就像是一个全局电话簿,Tomcat作为中间人帮我们管理数据库连接。应用不需要知道连接的具体细节,只需通过名称查找就能获取到配置好的数据源。这种方式有三大优势:
在Tomcat中配置JNDI数据源主要有三种模式,各有适用场景。下面我就结合自己多年的踩坑经验,详细解析每种配置方式的实现方法和使用技巧。
这是最直接的方式,适合快速验证或单一应用场景。操作步骤如下:
xml复制<Context docBase="WebApp" path="/WebApp" reloadable="true">
<Resource
name="jdbc/mysql"
scope="Shareable"
type="javax.sql.DataSource"
factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory"
url="jdbc:mysql://localhost:3306/test"
driverClassName="com.mysql.jdbc.Driver"
username="root"
password="root"
initialSize="5"
maxActive="20"
maxWait="10000"/>
</Context>
提示:虽然文档中scope标为Shareable,但实际上这个配置只能被当前Context访问,其他应用无法使用
优点:
缺点:
我在实际项目中发现,当需要给同一个应用配置多环境(开发/测试/生产)时,这种方式需要准备多份server.xml,维护成本较高。
这种方式适合需要集中管理数据源的中小型项目。配置分为两步:
第一步:在server.xml中定义全局资源
xml复制<GlobalNamingResources>
<Resource
name="jdbc/global_mysql"
auth="Container"
type="javax.sql.DataSource"
factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory"
url="jdbc:mysql://db-server:3306/prod_db"
driverClassName="com.mysql.jdbc.Driver"
username="admin"
password="secureP@ssw0rd"
maxTotal="50"
minIdle="5"
validationQuery="SELECT 1"/>
</GlobalNamingResources>
第二步:在应用的Context中引用
xml复制<Context docBase="WebApp" path="/WebApp">
<ResourceLink
name="jdbc/mysql"
global="jdbc/global_mysql"
type="javax.sql.DataSource"/>
</Context>
global与name的区别:
高级参数:
配置位置:
这种模式我在金融项目中用得最多。有几点心得:
这是最彻底的共享方案,适合标准化程度高的环境:
第一步:同3.1,在GlobalNamingResources中定义资源
第二步:在conf/context.xml中配置全局引用
xml复制<Context>
<ResourceLink
global="jdbc/global_mysql"
name="jdbc/mysql"
type="javax.sql.DataSource"/>
<WatchedResource>WEB-INF/web.xml</WatchedResource>
</Context>
这种配置在SaaS平台中特别有用。比如我们有个客户管理系统,所有租户共享同一数据库配置。但要注意:
在Spring配置文件中可以这样引用:
xml复制<jee:jndi-lookup
id="dataSource"
jndi-name="java:comp/env/jdbc/mysql"
expected-type="javax.sql.DataSource"/>
注意:Tomcat环境下JNDI名称需要加java:comp/env/前缀
如果想用C3P0替代默认的DBCP,配置有所不同:
xml复制<Resource
name="jdbc/mysql_c3p0"
auth="Container"
type="com.mchange.v2.c3p0.ComboPooledDataSource"
factory="org.apache.naming.factory.BeanFactory"
jdbcUrl="jdbc:mysql://localhost:3306/test"
driverClass="com.mysql.jdbc.Driver"
user="dbuser"
password="secret"
maxPoolSize="30"
minPoolSize="5"
checkoutTimeout="3000"/>
关键区别:
对于国产瀚高数据库,配置略有不同:
xml复制<Resource
name="jdbc/highgo"
type="javax.sql.DataSource"
factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory"
url="jdbc:highgo://192.168.1.100:5866/sample"
driverClassName="com.highgo.jdbc.Driver"
username="highgo"
password="hg@123456"
initialSize="5"
maxActive="20"
validationQuery="SELECT 1"/>
现象:启动时报驱动类找不到
解决:
现象:连接数达到上限后应用挂起
排查:
优化建议:
检查步骤:
经过多个项目的积累,我总结了以下经验:
对于大型分布式系统,建议考虑: