??xml version="1.0" encoding="utf-8" standalone="yes"?>
]]>
JNDI是Java 命名与目录接口(Java Naming and Directory InterfaceQ?/p>
要了解JNDI的作用,我们可以?#8220;如果不用JNDI我们怎样做?用了JNDI后我们又怎样做?”q个问题来探讨?/p>
没有JNDI的做法:
E序员开发时Q知道要开发访问MySQL数据库的应用Q于是将一个对 MySQL JDBC 驱动E序cȝ引用q行了编码,q过使用适当?JDBC URL q接到数据库?br />
像以下代码q样Q?/p>
Connection conn=null;
try {
Class.forName("com.mysql.jdbc.Driver",true, Thread.currentThread().getContextClassLoader()); conn=DriverManager.getConnection("jdbc:mysql://MyDBServer?user=qingfeng&password=mingyue"); /* 使用connq进行SQL操作 */ conn.close();
} catch(Exception e) {
e.printStackTrace();
} finally {
if(conn!=null) {
try { conn.close();
} catch(SQLException e) {
}
}}
q是传统的做法,q种做法一般在规模的开发过E中不会产生问题Q只要程序员熟悉Java语言、了解JDBC技术和MySQLQ可以很快开发出相应的应用程序?/p>
没有JNDI的做法存在的问题Q?br />
1、数据库服务器名UMyDBServer 、用户名和口令都可能需要改变,由此引发JDBC URL需要修改;
2、数据库可能改用别的产品Q如改用DB2或者OracleQ引发JDBC驱动E序包和cd需要修改;
3、随着实际使用l端的增加,原配|的q接池参数可能需要调_
4?.....
解决办法Q?br /> E序员应该不需要关?#8220;具体的数据库后台是什么?JDBC驱动E序是什么?JDBC URL格式是什么?讉K数据库的用户名和口o是什么?”{等q些问题Q程序员~写的程序应该没有对 JDBC 驱动E序的引用,没有服务器名Uͼ没有用户名称或口?—?甚至没有数据库池或连接管理。而是把这些问题交lJ2EE容器来配|和理Q程序员只需要对q些配置和管理进行引用即可?/p>
由此Q就有了JNDI?/p>
用了JNDI之后的做法:
首先Q在在J2EE容器中配|JNDI参数Q定义一个数据源Q也是JDBC引用参数Q给q个数据源设|一个名Uͼ然后Q在E序中,通过数据源名U引用数据源从而访问后台数据库?br />
具体操作如下Q以JBossZQ:
1、配|数据源
在JBoss?D:\jboss420GA\docs\examples\jca 文g夹下面,有很多不同数据库引用的数据源定义模板。将其中?mysql-ds.xml 文gCopyC使用的服务器下,?D:\jboss420GA\server\default\deploy?br />
修改 mysql-ds.xml 文g的内容,使之能通过JDBC正确讉K你的MySQL数据库,如下Q?br />
<?xml version="1.0" encoding="UTF-8"?>
<datasources>
<local-tx-datasource>
<jndi-name>MySqlDS</jndi-name>
<connection-url>jdbc:mysql://localhost:3306/lw</connection-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<user-name>root</user-name>
<password>rootpassword</password>
<exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name>
<metadata>
<type-mapping>mySQL</type-mapping>
</metadata>
</local-tx-datasource>
</datasources>
q里Q定义了一个名为MySqlDS的数据源Q其参数包括JDBC的URLQ驱动类名,用户名及密码{?/p>
2、在E序中引用数据源Q?/p>
Connection conn=null;
try {
Context ctx=new InitialContext();
Object datasourceRef=ctx.lookup("java:MySqlDS"); //引用数据?nbsp;
DataSource ds=(Datasource)datasourceRef; conn=ds.getConnection(); /* 使用connq行数据库SQL操作 */
......
c.close();
} catch(Exception e) {
e.printStackTrace();
} finally { if(conn!=null) {
try {
conn.close();
} catch(SQLException e) { } }}
直接使用JDBC或者通过JNDI引用数据源的~程代码量相差无几,但是现在的程序可以不用关心具体JDBC参数了?br />
在系l部|后Q如果数据库的相兛_数变_只需要重新配|?mysql-ds.xml 修改其中的JDBC参数Q只要保证数据源的名UC变,那么E序源代码就无需修改?/p>
由此可见QJNDI避免了程序与数据库之间的紧耦合Q应用更加易于配置、易于部|Ӏ?/p>
所以,在J2EE规范中,J2EE 中的资源q不局限于 JDBC 数据源。引用的cd有很多,其中包括资源引用Q已l讨Q、环境实体和 EJB 引用。特别是 EJB 引用Q它暴露?JNDI ?J2EE 中的另外一关键角Ԍ查找其他应用E序lg?/p>
JNDI原理
sun只是提供了JNDI的接?卌?,IBM, Novell, Sun ?WebLogic 和JBOSS已经?JNDI 提供了服务提供程?
在JNDI中,在目录结构中的每一个结点称为context。每一个JNDI名字都是相对于context的。这里没有绝对名字的概念存在。对一个应用来_它可以通过使用 InitialContext cL得到其第一个context:
Context ctx = new InitialContext();
ctx.bind("name", Object);
ctx.lookup("name");
Context:上下?我的理解是相当与文gpȝ的中的目?JNDI的Naming Service是可以用操作pȝ的文件系l的,哈哈).
entry/object:一个节?相当与文件系l中的目录或文g.
filter:查询/qo条g是一个字W串表达式如:(&(objectClass=top)(cn=*))查询出objectClass属性ؓtop,cn属性ؓ所有情늚entry.
Attribute:entry/object的属性可以理解成JAVA对象的属?不同的是q个属性可以多ơ赋?
A.接口分为Context ?DirContext
JNDI有两个核心接口Context和DirContextQContext中包?了基本的名字操作Q而DirContext则将q些操作扩展到目录服务。DirContext 对Contextq行了扩展,提供了基本的目录服务操作Q?对名字对象属性的l护、基于属性的名字查找{等?nbsp;
B.上下文列表的多种Ҏ
一般来说有两种q行上下文列表的应用Q上下文览应用和对上下文中的对象进行实际操作的应用?nbsp;
上下文浏览应用一般只需要显CZ下文中包含内容的名字Q或者再获取一些诸如对象的cd之类的信息。这U类型的应用一般都是交互式的,可以允许用户在列丄上下文列表中选择一些进行进一步的昄?nbsp;
另外有一些应用需要对上下文中的对象进行实际的操作Q比如,一个备份程序需要对目录中所有文件的状态进行操作,或者某打印机管理员可能需要对大楼中的所有打印机q行复位。ؓ了进行这L操作Q程序需要获取上下文中的实际对象?nbsp;
对于q样两种cd的应用,Context接口提供了两U上下文列表Ҏlist()?listBindings()。其中list()只返回一pd名字/cL,而listBindings() 则返回名字、类和对象本w。显?list()用于上下文浏览应用而listBindings()用于那些需要对对象q行实际操作的应用?nbsp;
?
=================以下代码段d到server.xml中的<Host>?===========
<!-- configure DataSource. Add the following code into server.xml -->
<Context path="/bookstore" docBase="bookstore" debug="0"
reloadable="true" >
<!-- 数据源名U?-->
<Resource name="jdbc/BookDB"
auth="Container"
type="javax.sql.DataSource" />
<ResourceParams name="jdbc/BookDB">
<parameter>
<name>factory</name>
<value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
</parameter>
<!-- Maximum number of dB connections in pool. Make sure you
configure your mysqld max_connections large enough to handle
all of your db connections. Set to 0 for no limit.
-->
<!-- zd状态最大连接数 -->
<parameter>
<name>maxActive</name>
<value>100</value>
</parameter>
<!-- Maximum number of idle dB connections to retain in pool.
Set to 0 for no limit.
-->
<!-- I闲状态数据库q接最大数 -->
<parameter>
<name>maxIdle</name>
<value>30</value>
</parameter>
<!-- Maximum time to wait for a dB connection to become available
in ms, in this example 10 seconds. An Exception is thrown if
this timeout is exceeded. Set to -1 to wait indefinitely.
Maximum time to wait for a dB connection to become available
in ms, in this example 10 seconds. An Exception is thrown if
this timeout is exceeded. Set to -1 to wait indefinitely.
-->
<!-- 数据库处于空闲状态的最长时?-->
<parameter>
<name>maxWait</name>
<value>10000</value>
</parameter>
<!-- MySQL dB username and password for dB connections -->
<!-- 指定q接数据库的用户名及密码 -->
<parameter>
<name>username</name>
<value>dbuser</value>
</parameter>
<parameter>
<name>password</name>
<value>1234</value>
</parameter>
<!-- Class name for mm.mysql JDBC driver -->
<!-- 指定JDBC驱动 -->
<parameter>
<name>driverClassName</name>
<value>com.mysql.jdbc.Driver</value>
</parameter>
<!-- The JDBC connection url for connecting to your MySQL dB.
The autoReconnect=true argument to the url makes sure that the
mm.mysql JDBC Driver will automatically reconnect if mysqld closed the
connection. mysqld by default closes idle connections after 8 hours.
-->
<!-- 指定q接数据库的URL -->
<parameter>
<name>url</name>
<value>jdbc:mysql://localhost:3306/BookDB?autoReconnect=true</value>
</parameter>
</ResourceParams>
</Context>
q行机制Q?
1?首先E序代码获取初始化的 JNDI 环境q且调用 Context.lookup() Ҏ?JNDI 服务提供者那里获一?DataSource 对象
2?中间?JNDI 服务提供者返回一?DataSource 对象l当前的 Java 应用E序q个 DataSource 对象代表了中间层服务上现存的~冲数据?
3?应用E序调用 DataSource 对象?getConnection() Ҏ
4??DataSource 对象?getConnection() Ҏ被调用时Q中间层服务器将查询数据?q接~冲池中有没?PooledConnection 接口的实例对象。这?PooledConnection 对象被用于与数据库建立物理上的数据库连?
5?如果在缓冲池中命中了一?PooledCoonection 对象那么q接~冲池将单地?新内部的~冲q接队列q将?PooledConnection 对象q回。如果在~冲池内?有找到现成的 PooledConnection 对象Q那?ConnectionPoolDataSource 接口会?用来产生一个新?PooledConnection 对象q将它返回以便应用程序?
6?中间层服务器调用 PooledConnection 对象?getConnection() Ҏ以便q还一?java.sql.Connection 对象l当前的 Java 应用E序
7?当中间层服务器调?PooledConnection 对象?getConnection() ҎӞ JDBC 数据 库驱动程序将会创Z?Connection 对象q且把它q回中间层服务器
8?中间层服务器?Connection 对象q回l应用程?Java 应用E序Q可以认?Connection 对象是一个普通的 JDBC Connection 对象使用它可以和数据库徏立。事 实上的连接与数据库引擎生交互操??/p>
9?当应用程序不需要?Connection 对象Ӟ可以调用 Connection 接口?close() ?法。请注意q种情况?close() Ҏq没有关闭事实上的数据库q接Q仅仅是?放了被应用程序占用的数据库连接,q将它还l数据库q接~冲池,数据库连?~冲池会自动这个数据库q接交给h队列中下一个的应用E序使用?/p>
JDBCq接数据?br />
Ҏ:
1.Oracle8/8i/9i数据库(thin模式Q?
Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
String url="jdbc:oracle:thin:@localhost:1521:orcl"; //orcl为数据库SID
String user="test";
String password="test";
Connection conn= DriverManager.getConnection(url,user,password);
2.DB2数据?
Class.forName("com.ibm.db2.jdbc.app.DB2Driver ").newInstance();
String url="jdbc:db2://localhost:5000/sample"; //sampleZ的数据库?
String user="admin";
String password="";
Connection conn= DriverManager.getConnection(url,user,password);
3.Sql Server7.0/2000数据?
Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver").newInstance();
String url="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=mydb"; //mydb为数据库
String user="sa";
String password="";
Connection conn= DriverManager.getConnection(url,user,password);
4.Sybase数据?
Class.forName("com.sybase.jdbc.SybDriver").newInstance();
String url =" jdbc:sybase:Tds:localhost:5007/myDB";//myDBZ的数据库?
Properties sysProps = System.getProperties();
SysProps.put("user","userid");
SysProps.put("password","user_password");
Connection conn= DriverManager.getConnection(url, SysProps);
5.Informix数据?
Class.forName("com.informix.jdbc.IfxDriver").newInstance();
String url = "jdbc:informix-sqli://123.45.67.89:1533/myDB:INFORMIXSERVER=myserver;
user=testuser;password=testpassword"; //myDB为数据库?
Connection conn= DriverManager.getConnection(url);
6.MySQL数据?
Class.forName("org.gjt.mm.mysql.Driver").newInstance();
String url ="jdbc:mysql://localhost/myDB?user=soft&password=soft1234&useUnicode=true&characterEncoding=8859_1" //myDB为数据库?
Connection conn= DriverManager.getConnection(url);
7.PostgreSQL数据?
Class.forName("org.postgresql.Driver").newInstance();
String url ="jdbc:postgresql://localhost/myDB" //myDB为数据库?
String user="myuser";
String password="mypassword";
Connection conn= DriverManager.getConnection(url,user,password);
8.access数据库直q用ODBC?br />
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver") ;
String url="jdbc:odbc:Driver={MicroSoft Access Driver (*.mdb)};DBQ="+application.getRealPath("/Data/ReportDemo.mdb");
Connection conn = DriverManager.getConnection(url,"","");
Statement stmtNew=conn.createStatement() ;
1 Tomcat的conf/context.xml(Tomcat5.5以前配在server.xml?lt;host>标签?
<context>
<Resource name="jdbc/books"http://JNDI名称
auth="Container"http://q接池由谁管?container完全由容器管?applicationq序管?
type="javax.sql.DataSource"http://数据源类?br />
maxActive="100"http://最大连?br />
maxIdle="30"http://最大空?br />
maxWait="10000"http://单位毫秒Q最大等待,无限{待D?1
username="sa"
password="accp"
driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
url="jdbc:sqlserver://localhost:1433;databaseName=food"
/>
</context>
2 加数库据驱动jar
-5.5以前
TomCat/comm/lib
-5.5以后
TomCat/lib目录?br />
3 ~写代码
*javax.naming.context;
*javax.naming.InitialContext;
Connection conn;
Statement stmt;
ResultSet rs;
try{
Context ctx=new InitialContext();
DataSource ds=(DataSource)ctx.lookup("java:comp/env/jdbc/books");
conn=ds.getConnection();
stmt=conn.createStatement();
rs=stmt.executeQuery(sql);
}catch(){}