在基于servlet的应用程序中,我应该如何连接JDBC数据库/数据源?

25
我有一个外部MySQL服务器,设置好并正常工作。我在Eclipse中创建了一个数据库连接,并可以在“数据源浏览器”标签中查看该数据库。
现在,我有一个servlet需要访问该数据库。我该如何做?是否有一种方式可以引用在数据源浏览器中创建的数据库连接,或者我必须重复定义所有内容?
此外,打开连接的最佳方法是什么?我已经包含了mysql-connector-java-5.1.11-bin.jar文件,并找到了两种有效的方法:
MysqlDataSource d = new MysqlDataSource();
d.setUser("user");
d.setPassword("pass");
d.setServerName("hostname.com");
d.setDatabaseName("db");
Connection c = d.getConnection();

并且

Connection c = DriverManager.getConnection("jdbc:mysql://hostname.com/db","user","pass");

两种方法都不是最佳选择,首先,它们都使用硬编码的字符串。这是一个Java EE Web应用程序项目,那么有没有好的地方可以放置连接数据?或者是否有一种方法可以放弃所有这些,并只使用数据源资源管理器中的连接?

2个回答

54

一种常见的做法是将这个东西配置成一个 DataSource,放在相关的servlet容器中。这将为您提供连接池设施,大大提高性能。还有一种常见的做法是将原始设置外部化到某个配置文件中,并将其放置在类路径中。

如果您使用的是Tomcat作为 servlet 容器,那么您需要按照其JNDI文档中的说明来配置数据源。您会发现有几种方法可用。最简单的方法是在您的动态 Web 项目的 webcontent 中创建一个 /META-INF/context.xml 文件(要清楚的是,/META-INF 与 webapp 的 /WEB-INF 在同一级别),并填写如下内容:

<?xml version="1.0" encoding="UTF-8"?>

<Context>
    <Resource
        name="jdbc/db" type="javax.sql.DataSource"
        maxActive="100" maxIdle="30" maxWait="10000" 
        url="jdbc:mysql://hostname.com/db"
        driverClassName="com.mysql.jdbc.Driver"
        username="user" password="pass"
    />
</Context>

这大致意味着Tomcat服务器应该使用JNDI名称为jdbc/db创建一个数据源,最多可以有100个活动连接、30个空闲连接以及最长等待时间为10000毫秒,超过这个时间连接将会被您的应用程序关闭(实际上:由您的应用程序关闭连接,所以您的应用程序在获取连接和关闭连接之间有10秒的时间)。其余的设置对您来说应该很熟悉并且足够自解释;那些是JDBC的设置。

最后,在您的Web项目中,编辑文件/WEB-INF/web.xml并添加以下条目:

<resource-env-ref>
    <resource-env-ref-name>jdbc/db</resource-env-ref-name>
    <resource-env-ref-type>javax.sql.DataSource</resource-env-ref-type>
</resource-env-ref>

大致意思是Web应用程序应该使用服务器提供的名为jdbc/db的数据源。

然后将连接管理器更改为以下内容:

private DataSource dataSource;

public Database(String jndiname) {
    try {
        dataSource = (DataSource) new InitialContext().lookup("java:comp/env/" + jndiname);
    } catch (NamingException e) {
        // Handle error that it's not configured in JNDI.
        throw new IllegalStateException(jndiname + " is missing in JNDI!", e);
    }
}

public Connection getConnection() {
    return dataSource.getConnection();
}

将所有的Class.forName(driver)调用替换为new Database("jdbc/db"),并将所有的DriverManager.getConnection()调用替换为database.getConnection()。如果必要,您可以从某个配置文件(属性文件?)中获取值jdbc/db

或者,通过在受容器管理的工件中注入DataSource,例如 @WebServlet servlet 类,使用@Resource 注释:

@Resource(name="jdbc/db")
private DataSource dataSource;

就这样了。只需使用以上更改部署Web应用程序并运行即可。别忘了将数据库JDBC驱动程序放置在Tomcat/lib中,或将其路径添加到Tomcat/conf/catalina.propertiesshared.loader属性中,因为现在加载JDBC驱动程序的责任已经从Web应用程序转移到了服务器上。您还可以在此文章中找到更多提示和其他基本的JDBC/JNDI示例。

另请参阅:


这看起来非常有帮助。只有两个问题。1:我不知道这是只有我还是正常情况,但是没有tomcat/lib目录,而是在common/lib、server/lib和shared/lib下有几个lib目录。我的jar应该放在哪里?第二个问题:这是否会处理连接池,因为它在这里设置了?每次使用后,我应该在从getConnection()返回的连接上调用close()吗? - Ed Marty
  1. 你显然在使用6~8年前的Tomcat 5.x版本。如果可以的话,请升级到Tomcat 6.0(强烈推荐),或者获取Tomcat 5.x的/shared/lib文件夹。
  2. 是的,它会处理连接池。而且,你应该始终在finally中调用close()方法。连接池实现本身会负责关闭或释放连接。还请查看上述链接的最后一章节。
- BalusC
@BalusC 我有一个问题,虽然这篇文章有点旧了。有没有办法使密码加密?在context.xml中,密码是明文,所以有没有办法将数据源创建与Eclipse Web应用程序集成? - Jacob
对于Tomcat 7,应该是<resource-ref> <description>MySQL数据源</description> <res-ref-name>jdbc/db</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref> - xhe8

3
您可以在部署WAR的任何应用服务器中设置数据源,并使用JNDI获取对其的引用。或者,您可以将WAR打包在EAR中,并在EAR的data-sources.xml文件中定义数据源(并使用JNDI获取对其的引用)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接