Java JNDI连接数据库
Frank_bettterMan 人气:0项目背景
在项目中本身使用的SQL Server 数据库,某些功能下需要访问Sybase数据库(都淘汰的东西 QAQ),考虑到功能较少并且我们的UAT和PROD环境使用的是WebSphere,其本身已经存在JNDI的连接方式,因此我决定使用JNDI设置,那么就需要解决JNDI在Tomcat下的配置了,找了很多资料,说到这,不得不吐槽我们国内的博客论坛,大部分都是抄,关键是还抄不全,错漏百出,还不注明原作者。
环境
Eclipse:Luna
Tomcat:apache-tomcat-9.0.8
概念
数据源与连接池
数据源名称(data source name,DSN)是包含了有关某个特定数据库信息的数据结构,这个信息是开放式数据库连接驱动能够连接到数据库上必需的信息,其实本质上就使程序与数据库连接的通道。数据源中并无真正的数据,它仅仅记录的是你连接到哪个数据库,以及如何连接的,如odbc数据源。也就是说数据源仅仅是数据库的连接名称,一个数据库可以有多个数据源连接。
在Java语言中,DataSource对象就是一个代表数据源实体的对象。一个数据源就是一个用来存储数据的工具,它可以是复杂的大型企业级数据库,也可以是简单得只有行和列的文件。数据源可以位于在服务器端,也可以位于客服端。
连接池:在Java程序中,当我们需要对数据库进行操作时,对于数据库的增删改查等操作的前提是需要与数据库建立连接,而对于连接的管理其实就使建立在数据源的基础上,即连接池。
常用的数据库连接池:
序号 | 连接池名称 | 依赖的jar包 | 实现的datasource类 | 备注 |
---|---|---|---|---|
1 | JNDI | 该数据源是由相应的web服务器(例如:tomcat,weblogic,websphere)负责初始化,创建,管理。程序中不需要引入特别的jar包。 | Javax.sql.datasource | |
2 | C3P0 | c3p0-0.9.xxx.jar | com.mchange.v2.c3p0.ComboPooledDataSource | |
3 | DBCP | commons-dbcp.jar commons-pool.jar |
org.apache.commons.dbcp.BasicDataSource | |
4 | BoneCP | bonecp-0.6.5.jar google-collections-1.0.jar slf4j-api-1.5.11.jar,slf4j-log4j12-1.5.11.jar log4j-1.2.15.jar |
BoneCPDataSource |
什么是JNDI
jndi全称是java naming and directory interface。简单点就是你按命名规则给一个东西命名然后你就可以通过该名字在特定环境下直接查找到该东西了。
JNDI是用于向Java程序提供目录和命名功能的API。可以简单地把JNDI理解为一种将对象和名字绑定的技术,对象工厂负责生产出对象,这些对象都和惟一的名字绑定。外部程序可以通过名字来获取对某个对象的引用。在一个文件系统中,文件名被绑定给文件。在DNS中,一个IP地址绑定一个URL。在目录服务中,一个对象名被绑定给一个对象实体。
在Intranets(企业内部网)和Internates(互联网)中目录服务(Directory service)都非常重要,它规范了命名规则,让人们容易理解实体及之间的关系。JNDI是Java平台的一个标准扩展,提供了一组接口、类和关于命名空间的概念。JNDI目前所支持的技术包括LDAP、CORBA Common Object Service(COS)名字服务、RMI、NDS、DNS、Windows注册表等等。
jndi被设计成独立于特定的目录服务,所以各种各样的目录都可以通过相同的方式进行访问。这样使用jndi的java程序员不仅可以获得统一规整的命名和目录,而且可以通过多层的命名方案无缝访问(seamless acess)目录对象。
JNDI优点
JNDI是由web服务器,实现了java.sql.datasource。由web服务器负责初始化数据源,创建connection,分配,管理connection。由于本身是由web服务器实现的功能,因此不需要在项目project中引入特别的jar包,但是需要在服务器的某些配置文件中增加相关的配置。对于我们这种连接多个数据库有很好的效果。
JDNI在Tomcat中的配置
Jar包
1.数据库的驱动程序包:
jconn4.jar Sybase驱动程序包
mssql-jdbc-6.1.0.jre7.jar SQL Server 程序驱动包
2.JSP标签Ja包
.jstl-1.2.jar
standard-1.1.2.jar
测试准备
新建测试Web项目如下:
JSP:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ page import="java.sql.*,javax.sql.*,javax.naming.*" %> <!DOCTYPE HTML> <html> <head> <title>JNDI数据源测试</title> </head> <body> <% Connection connOracle = null; try { //1、初始化名称查找上下文 Context ctx = new InitialContext(); //InitialContext ctx = new InitialContext();亦可 //2、通过JNDI名称找到DataSource,对名称进行定位java:comp/env是必须加的,后面跟的是DataSource名 /* DataSource名在web.xml文件中的<res-ref-name>oracleDataSource</res-ref-name>进行了配置 <!--Oracle数据库JNDI数据源引用 --> <resource-ref> <description>Oracle DB Connection</description> <res-ref-name>oracleDataSource</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref> */ DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/Sybase_claims"); //3、通过DataSource取得一个连接 connOracle = ds.getConnection(); out.println("Sybase Connection pool connected !!"); //4、操作数据库 } catch (NamingException e) { System.out.println(e.getMessage()); } catch (SQLException e) { e.printStackTrace(); } finally { //5、关闭数据库,关闭的时候是将连接放回到连接池之中 connOracle.close(); } %> <hr/> <% Connection connSQLServer = null; try { //1、初始化名称查找上下文 Context ctx = new InitialContext(); //InitialContext ctx = new InitialContext();亦可 //2、通过JNDI名称找到DataSource,对名称进行定位java:comp/env是必须加的,后面的是DataSource名 /* DataSource名在web.xml文件中的<res-ref-name>sqlserverDataSource</res-ref-name>进行了配置 <!--SQLServer数据库JNDI数据源引用 --> <resource-ref> <description>SQLServer DB Connection</description> <res-ref-name>sqlserverDataSource</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref> */ DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/sqlserver"); //3、通过DataSource取得一个连接 connSQLServer = ds.getConnection(); out.println("SQLServer Connection pool connected !!"); //4、操作数据库 } catch (NamingException e) { System.out.println(e.getMessage()); } catch (SQLException e) { e.printStackTrace(); } finally { //5、关闭数据库,关闭的时候是将连接放回到连接池之中 connSQLServer.close(); } %> </body> </html>
Tomcat:
将数据库驱动Jar包放入Tomcat的lib文件夹下:
JNDI配置
在Tomcat 配置文件server.xml(apache-tomcat-9.0.8\conf)中的GlobalNamingResources标签内定义
<!-- Global JNDI resources Documentation at /docs/jndi-resources-howto.html --> <GlobalNamingResources> <!-- Editable user database that can also be used by UserDatabaseRealm to authenticate users --> <Resource name="UserDatabase" auth="Container" type="org.apache.catalina.UserDatabase" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" pathname="conf/tomcat-users.xml" /> <!-- |- name:表示以后要查找的名称。通过此名称可以找到DataSource,此名称任意更换,但是程序中最终要查找的就是此名称, 为了不与其他的名称混淆,所以使用jdbc/oracle,现在配置的是一个jdbc的关于oracle的命名服务。 |- auth:由容器进行授权及管理,指的用户名和密码是否可以在容器上生效 |- type:此名称所代表的类型,现在为javax.sql.DataSource |- maxActive:表示一个数据库在此服务器上所能打开的最大连接数 |- maxIdle:表示一个数据库在此服务器上维持的最小连接数 |- maxWait:最大等待时间。10000毫秒 |- username:数据库连接的用户名 |- password:数据库连接的密码 |- driverClassName:数据库连接的驱动程序 |- url:数据库连接的地址 --> <!--配置Sysbase数据库的JNDI数据源--> <Resource name="jdbc/Sybase_claims" auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000" username="test" password="test" driverClassName="com.sybase.jdbc4.jdbc.SybDriver" url="jdbc:sybase:Tds:127.0.0.1:4101?ServiceName=db_claims"/> <!--配置SQL Server数据库的JNDI数据源--> <Resource name="jdbc/sqlserver" auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000" username="sa" password="p@ssw0rd" driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver" url="jdbc:sqlserver://127.0.0.1:1433;DatabaseName=sonora"/>
全局引用
在Tomcat 的context.xml(apache-tomcat-9.0.8\conf)中引用,针对于本Tomcat服务器下所有项目使用。
<Context> <!-- Default set of monitored resources. If one of these changes, the --> <!-- web application will be reloaded. --> <WatchedResource>WEB-INF/web.xml</WatchedResource> <WatchedResource>WEB-INF/tomcat-web.xml</WatchedResource> <WatchedResource>${catalina.base}/conf/web.xml</WatchedResource> <!-- Uncomment this to disable session persistence across Tomcat restarts --> <!-- <Manager pathname="" /> --> <ResourceLink name="jdbc/Sybase_claims" global="jdbc/Sybase_claims" type="javax.sql.DataSource"/> <ResourceLink name="jdbc/Sybase_iws_ref" global="jdbc/Sybase_iws_ref" type="javax.sql.DataSource"/> </Context>
当然,我们也可以不引用局部配置的,在Context标签中直接写数据源:
<Context> <!-- Default set of monitored resources. If one of these changes, the --> <!-- web application will be reloaded. --> <WatchedResource>WEB-INF/web.xml</WatchedResource> <WatchedResource>WEB-INF/tomcat-web.xml</WatchedResource> <WatchedResource>${catalina.base}/conf/web.xml</WatchedResource> <!-- Uncomment this to disable session persistence across Tomcat restarts --> <!-- <Manager pathname="" /> --> <!--配置Sysbase数据库的JNDI数据源--> <Resource name="jdbc/Sybase_claims" auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000" username="test" password="test" driverClassName="com.sybase.jdbc4.jdbc.SybDriver" url="jdbc:sybase:Tds:127.0.0.1:4101?ServiceName=db_claims"/> <!--配置SQL Server数据库的JNDI数据源--> <Resource name="jdbc/sqlserver" auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000" username="sa" password="p@ssw0rd" driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver" url="jdbc:sqlserver://127.0.0.1:1433;DatabaseName=sonora"/> </Context>
局部引用
局部引用:即是配置的数据源,只针对于指定项目使用。
方式一:在server.xml中的host标签内配置
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <!-- SingleSignOn valve, share authentication between web applications Documentation at: /docs/config/valve.html --> <!-- <Valve className="org.apache.catalina.authenticator.SingleSignOn" /> --> <!-- Access log processes all example. Documentation at: /docs/config/valve.html Note: The pattern used is equivalent to using pattern="common" --> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t "%r" %s %b" /> <Context docBase="jndi_demo" path="/jndi_demo" reloadable="false"> <ResourceLink name="jdbc/Sybase_claims" global="jdbc/Sybase_claims" type="javax.sql.DataSource"/> <ResourceLink name="jdbc/sqlserver" global="jdbc/sqlserver" type="javax.sql.DataSource"/> </Context> </Host>
当然也也可以直接在Context标签下直接定义
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <!-- SingleSignOn valve, share authentication between web applications Documentation at: /docs/config/valve.html --> <!-- <Valve className="org.apache.catalina.authenticator.SingleSignOn" /> --> <!-- Access log processes all example. Documentation at: /docs/config/valve.html Note: The pattern used is equivalent to using pattern="common" --> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t "%r" %s %b" /> <Context docBase="jndi_demo" path="/jndi_demo" reloadable="false"> <Resource name="jdbc/Sybase_claims" auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000" username="test" password="test" driverClassName="com.sybase.jdbc4.jdbc.SybDriver" url="jdbc:sybase:Tds:127.0.0.1:4101?ServiceName=db_claims"/> <!--配置SQL Server数据库的JNDI数据源--> <Resource name="jdbc/sqlserver" auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000" username="sa" password="p@ssw0rd" driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver" url="jdbc:sqlserver://127.0.0.1:1433;DatabaseName=sonora"/> </Context> </Host>
方式二:在Tomcat安装目录下apache-tomcat-9.0.8\conf\Catalina\localhost下新建xml文件,文件名与项目名称相同。
<!--映射JNDITest项目的虚拟目录--> <Context docBase="D:/soft-install/apache-tomcat-9.0.8/webapps/jndi_demo/WebContent" debug="0" reloadable="false"> <!--引用Sybase数据库的JNDI数据源--> <ResourceLink name="jdbc/Sybase_claims" global="jdbc/Sybase_claims" type="javax.sql.DataSource"/> <!--引用sqlserver数据库的JNDI数据源--> <ResourceLink name="jdbc/sqlserver" global="jdbc/sqlserver" type="javax.sql.DataSource"/> </Context>
方式三:
在Tomcat下项目目录的META-INF中新建Context.xml 配置JNDI引用,例如:、apache-tomcat-9.0.8\webapps\jndi_demo\META-INF、。
<Context reloadable="false"> <ResourceLink name="jdbc/Sybase_claims" global="jdbc/Sybase_claims" type="javax.sql.DataSource"/> <ResourceLink name="jdbc/sqlserver" global="jdbc/Sybase_iws_ref" type="javax.sql.DataSource"/> </Context>
或
<?xml version="1.0" encoding="UTF-8"?> <Context path="" reloadable="false"> <Resource name="jdbc/Sybase_claims" auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000" username="test" password="test" driverClassName="com.sybase.jdbc4.jdbc.SybDriver" url="jdbc:sybase:Tds:127.0.0.1:4101?ServiceName=db_claims"/> <!--配置SQL Server数据库的JNDI数据源--> <Resource name="jdbc/sqlserver" auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000" username="sa" password="p@ssw0rd" driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver" url="jdbc:sqlserver://127.0.0.1:1433;DatabaseName=sonora"/> </Context>
这样做的好处就是可以脱离Tomcat配置的更改。
注意
1.看了很多文章,有些是在项目web.xml中配置如下内容,经过的验证Tomcat中是可有可无的,不过有些文章说最好加上,以便于项目移植,因为有些服务器是需要的。
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <!-- JNDI配置的资源引用: • res-ref-name:表示引用资源的名称 • res-type:此资源对应的类型为javax.sql.DataSource • res-auth:容器授权管理 --> <!--Sybase数据库JNDI数据源引用 --> <resource-ref> <description>Sybase DB Connection</description> <res-ref-name>jdbc/Sybase_claims</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref> <!--SQLServer数据库JNDI数据源引用 --> <resource-ref> <description>SQLServer DB Connection</description> <res-ref-name>jdbc/sqlserver</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref> </web-app>
JNDI配置我们可以发现,第三种方式完全脱离Tomcat的配置,对于server的影响较小。不过我比较推荐全局配置,各处引用,方便切换。
Tomcat的配置修改后,最好重启Tomcat以便生效,对于server.xml修改必须重启生效,而context.xml配置保存后tomcat会自动加载无需重启
JNDI数据源获取写法有一下两种,前者是针对于Tomcat中的,而后者是针对于IBM WebSphere。
A: java:comp/env/jdbc/Sybase_claims
B: jdbc/Sybase_claims
针对于A:
java:comp/env 是环境命名上下文(environment naming context(ENC)),是在EJB规范1.1以后引入的,引入这个是为了解决原来JNDI查找所引起的冲突问题,也是为了提高EJB或者J2EE应用的移植性。
在J2EE中的引用常用的有:
JDBC 数据源引用在java:comp/env/jdbc 子上下文中声明
JMS 连接工厂在java:comp/env/jms 子上下文中声明
JavaMail 连接工厂在java:comp/env/mail 子上下文中声明
URL 连接工厂在 java:comp/env/url子上下文中声明
参考资料
https://www.cnblogs.com/wuyanshun/p/6763162.html
http://tomcat.apache.org/tomcat-9.0-doc/jndi-resources-howto.html
加载全部内容