如何在Spring中使用Tomcat提供的JNDI数据源?

162
据Spring javadoc关于DriverManagerDataSource类的文章称,这个类非常简单,建议使用容器提供的JNDI数据源。通过JndiObjectFactoryBean,这样的DataSource可以在Spring应用程序上下文中公开为一个DataSource bean。
问题是:我该如何实现呢?比如,如果我想要一个DataSource bean来访问我的自定义MySQL数据库,我需要什么?在上下文配置中应该写些什么等等。
8个回答

305
如果使用Spring的基于XML模式的配置,可以在Spring上下文中像这样进行设置:
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:jee="http://www.springframework.org/schema/jee" xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd">
...
<jee:jndi-lookup id="dbDataSource"
   jndi-name="jdbc/DatabaseName"
   expected-type="javax.sql.DataSource" />

或者,可以像这样使用简单的bean配置进行设置:

<bean id="DatabaseName" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="java:comp/env/jdbc/DatabaseName"/>
</bean>

您可以在Tomcat的server.xml文件中声明JNDI资源,例如:

<GlobalNamingResources>
    <Resource name="jdbc/DatabaseName"
              auth="Container"
              type="javax.sql.DataSource"
              username="dbUser"
              password="dbPassword"
              url="jdbc:postgresql://localhost/dbname"
              driverClassName="org.postgresql.Driver"
              initialSize="20"
              maxWaitMillis="15000"
              maxTotal="75"
              maxIdle="20"
              maxAge="7200000"
              testOnBorrow="true"
              validationQuery="select 1"
              />
</GlobalNamingResources>

并且像这样从Tomcat的web context.xml中引用JNDI资源:

  <ResourceLink name="jdbc/DatabaseName"
   global="jdbc/DatabaseName"
   type="javax.sql.DataSource"/>

参考文档:

编辑:此答案已更新为 Tomcat 8 和 Spring 4。对于 Tomcat 的 默认 数据源资源池设置,有一些属性名称更改。


@skaffman 是的,但你提供了一个Spring参考文档链接。 - Étienne Miret
你所说的“Tomcat的web context.xml”文件具体是指哪个文件? - Pavel Niedoba
1
@PavelNiedoba Tomcat使用“上下文”来进行特定于Tomcat的Web应用程序配置。 上下文文件和/或上下文配置可以放置在各种位置,因此我无法给出明确的答案。 一个常见的位置是“/META-INF/context.xml”。 在这里查看“定义上下文”部分:https://tomcat.apache.org/tomcat-8.0-doc/config/context.html#Defining_a_context - kaliatech
嗯...似乎对我的Oracle数据库不起作用,与PostgreSQL有什么区别吗? - Phate
1
@Phate 在JDBC / JNDI / Tomcat级别上,Oracle与PostgreSQL没有根本区别。但是,当涉及到Oracle客户端/服务器设置细节时,Oracle与PostgreSQL非常不同。该问题/答案的范围外。建议发布一个新问题,详细说明您尝试过什么,具体版本以及任何错误消息。例如:https://dev59.com/zmPVa4cB1Zd3GeqP4Uyl - kaliatech
显示剩余4条评论

54

使用Spring的JavaConfig机制,您可以这样做:

@Configuration
public class MainConfig {

    ...

    @Bean
    DataSource dataSource() {
        DataSource dataSource = null;
        JndiTemplate jndi = new JndiTemplate();
        try {
            dataSource = jndi.lookup("java:comp/env/jdbc/yourname", DataSource.class);
        } catch (NamingException e) {
            logger.error("NamingException for java:comp/env/jdbc/yourname", e);
        }
        return dataSource;
    }

}

3
或者使用更专业的JndiDataSourceLookup - Arend v. Reinersdorff

21

假设您在Tomcat配置中有一个“sampleDS”数据源定义,您可以添加以下行到您的applicationContext.xml中,以使用JNDI访问数据源。

<jee:jndi-lookup expected-type="javax.sql.DataSource" id="springBeanIdForSampleDS" jndi-name="sampleDS"/>

你需要使用以下方式为 jee 前缀定义命名空间和模式位置:

xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd"

15

文档:C.2.3.1 <jee:jndi-lookup/> (简单)

示例:

<jee:jndi-lookup id="dataSource" jndi-name="jdbc/MyDataSource"/>
你只需要找到应用服务器绑定数据源的JNDI名称。这完全是与服务器相关的,请查阅服务器文档以了解详情。
请记得在你的bean文件顶部声明`jee`命名空间,详见C.2.3 The jee schema

9
另一个特性:可以在您的应用程序/META-INF/Context.xml中添加“Resource”标签,而不是在server.xml中添加(根据tomcat文档),如下所示:
<Context>
<Resource name="jdbc/DatabaseName" auth="Container" type="javax.sql.DataSource"
  username="dbUsername" password="dbPasswd"
  url="jdbc:postgresql://localhost/dbname"
  driverClassName="org.postgresql.Driver"
  initialSize="5" maxWait="5000"
  maxActive="120" maxIdle="5"
  validationQuery="select 1"
  poolPreparedStatements="true"/>
</Context>

5
根据Apache Tomcat 7 JNDI Datasource HOW-TO 页面的说法,web.xml文件中必须要有资源配置。
<resource-ref>
  <description>DB Connection</description>
  <res-ref-name>jdbc/TestDB</res-ref-name>
  <res-type>javax.sql.DataSource</res-type>
  <res-auth>Container</res-auth>

这对我可行。

4
在您的Spring类中,您可以注入一个使用如下注释的bean:
@Autowired
@Qualifier("dbDataSource")
private DataSource dataSource;

你需要在context.xml文件中添加以下内容:

<beans:bean id="dbDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    <beans:property name="jndiName" value="java:comp/env/jdbc/MyLocalDB"/>
</beans:bean>

您可以在Tomcat的server.xml文件中声明JNDI资源。
<Resource name="jdbc/TestDB" 
  global="jdbc/TestDB" 
  auth="Container" 
  type="javax.sql.DataSource" 
  driverClassName="com.mysql.jdbc.Driver" 
  url="jdbc:mysql://localhost:3306/TestDB" 
  username="pankaj" 
  password="pankaj123" 

  maxActive="100" 
  maxIdle="20" 
  minIdle="5" 
  maxWait="10000"/>

回到 context.xml 中,Spring 添加以下内容:
<ResourceLink name="jdbc/MyLocalDB"
                global="jdbc/TestDB"
                auth="Container"
                type="javax.sql.DataSource" />

如果您像这个例子一样将数据库连接注入,请确保MySQL jar文件存在于Tomcat lib目录中,否则Tomcat将无法创建MySQL数据库连接池。


1
我发现这个解决方案非常有用,可以完全删除xml配置。
请使用JNDI和Spring框架检查此数据库配置。 http://www.unotions.com/design/how-to-create-oracleothersql-db-configuration-using-spring-and-maven/ 通过这篇文章,它解释了如何基于数据库jndi(db/test)配置创建一个数据库配置。一旦您完成配置,所有的数据库存储库都将使用此jndi加载。我发现这很有用。如果@Pierre对此有问题,请告诉我。这是编写数据库配置的完整解决方案。

通过本文,它解释了如何基于数据库JNDI(db/test)配置轻松创建DB配置。一旦您完成配置,那么所有的DB存储库都将使用此JNDI加载。我发现这很有用。如果@Pierre对此有问题,请告诉我。这是编写DB配置的完整解决方案。 - user3892286
通过本文,它解释了如何基于数据库JNDI(db/test)配置轻松创建DB配置。一旦您完成配置,那么所有的DB存储库都将使用此JNDI加载。我发现这很有用。如果@Pierre对此有问题,请告诉我。这是编写DB配置的完整解决方案。 - Sergio A.

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