`

JNDI和数据源在JDBC中的应用

    博客分类:
  • JDBC
阅读更多

      众所周知,JDBC(Java数据库连接)是Java 2企业版的重要组成部分。它是基于SQL层的API。通过把SQL语句嵌入JDBC接口的方法中,用户可以通过Java程序执行几乎所有的数据库操作。JDBC只提供了接口,具体的类的实现要求数据库的设计者完成。通过生成这些接口的实例,即使对于不同的数据库,Java程序也可以正确地执行SQL调用。所以对于程序员来说,不必把注意力放在如何向数据库发送SQL指令,因为程序员需要了解和用到的只是JDBC的接口,只有在极少数情况下会用到面向特定数据库的类,例如程序员希望使用ORACLE的扩展API

      从实际应用的角度出发,我们可以看出采取JDBC直接连接到数据库存在几个问题:

            第一是安全性问题,由于程序代码中包含用户名和密码,其他人如果能得到bytecode,可以通过反编译工具获得用户名和密码。

            第二是代码的可移植性问题。如果希望连接的数据库名称或用户名有所更改,程序员需要修改源程序,然后把修改过的程序发送给用户。也就是说,软件无法脱离数据库独立存在。这样不仅会大大提高软件的成本,也不利于软件本身的发展。

            还可能出现这样的情况:在某些情况下,提供数据的机构不希望数据库的用户名和密码让编写程序的程序员知道知道。这样就提出了一个问题,如何使Java和数据库之间建立连接时隐藏一些敏感的信息。

 

 

数据源(Data Source)及JNDI

  数据源是在JDBC 2.0中引入的一个概念。在JDBC 2.0扩展包中定义了javax.sql.DataSource接口来描述这个概念。如果用户希望建立一个数据库连接,通过查询在JNDI服务中的数据源,可以从数据源中获取相应的数据库连接。这样用户就只需要提供一个逻辑名称(Logic Name),而不是数据库登录的具体细节。

  在这里有必要简单介绍一下JNDI。JNDI 是一种应用程序编程接口 (API) 或库,它为应用程序提供了将名称与对象关联起来以及根据对象的名称在目录中查找对象的方法。JNDI的全称是Java Naming and Directory Interface, 可以理解为Java名称和目录服务接口。JNDI向应用程序提供了一个查询和使用远程服务的机制。这些服务可以是任何企业服务。对于JDBC应用程序来说,JNDI提供的是数据库连接服务。当然JNDI也可以向数据库提供其他服务,但是这超出了本文范围,在此不做论述。

  其实JNDI并不难理解。简单来说,名称服务提供了一个把文件,打印机,服务器等实体映射到一个逻辑名称的机制。例如在操作系统中的名称服务就把打印机映射到一个I/O端口。而目录服务可以理解为名称服务的一个扩展,它允许在服务中的各项拥有自己的属性。又以打印机为例,打印机可以是彩色打印机,支持双面打印,支持网络打印,支持高速打印等。所有这些打印机的属性都可以储存在目录服务中,和相应的打印机联系起来。一些常见的目录服务有NIS,NIS+,LDAP和Novell的NDS等。

  JNDI使应用程序通过使用逻辑名称获取对象和对象提供的服务,从而使程序员可以避免使用与提供对象的机构有关联的代码。例如在下面的例子中使用了在JNDI中的数据源,程序员就不需要提供Oracle8i驱动程序的名称,这样代码的移植能力就更强。

  下面详细介绍一下数据源和javax.sql.DataSource接口。在数据源中存储了所有建立数据库连接的信息。就象通过指定文件名你可以在文件系统中找到文件一样,通过提供正确的数据源名称,你可以找到相应的数据库连接。javax.sql.DataSource接口定义了如何实现数据源。在该接口中定义了九个属性。表一列出了对这些属性的描述。由于本文是以Oracle8i为例,在Oracle8i中没有实现roleName属性,所以在表中没有对此属性做描述。

  表一:数据源标准属性

 

属性名称 属性数据类型 描述
databaseName String 数据库名称,即数据库的SID。
dataSourceName String 数据源接口实现类的名称。
description String 对数据源的描述。
networkProtocol String 和服务器通讯使用的网络协议名。在Oracle8i中,该属性只在使用OCI驱动程序时有效,缺省协议是TCP协议。
password String 用户登录密码。
portNumber Int 数据库服务器使用的端口,缺省值为1521。
serverName String 数据库服务器名称。
user String 用户登录名。


  在javax.sql.DataSource接口中定义了以下方法:

 

* public synchronized void setDatabaseName(String dbname)
* public synchronized String getDatabaseName()
* public synchronized void setDataSourceName(String dsname)
* public synchronized String getDataSourceName()
* public synchronized void setDescription(String desc)
* public synchronized String getDescription()
* public synchronized void setNetworkProtocol(String np)
* public synchronized String getNetworkProtocol()
* public synchronized void setPassword(String pwd)
* public synchronized void setPortNumber(int pn)
* public synchronized int getPortNumber()
* public synchronized void setServerName(String sn)
* public synchronized String getServerName()
* public synchronized void setUser(String user)
* public synchronized String getUser()


  通过这些方法,程序员可以获得建立连接需要的所有信息。需要注意的是,程序员不可以获取登陆密码,这就在一定程度上保证了安全性。需要注意的另一点是所有的方法都是synchronized方法,这是为了保证应用程序的线程安全(Thread-safe)。如果在调用该方法时,即使数据源实例发生变化不会影响程序的正确运行。

  除了实现由SUN定义的属性和方法外,Oracle8i还提供了自己的数据源属性和方法。这些方法和属性是在oracle.jdbc.pool.OracleDataSource中实现的。 Oracle8i扩展数据源属性如表二所示:

  表二:

 

属性名称 属性数据类型 描述
driverType String 使用的Oracle JDBC驱动程序的类型,包括oci8, thin和kprb
url String 数据库连接的URL。
tnsEntry String TNS条目名称


  在oracle.jdbc.pool.OracleDataSource中除了实现javax.sql.DataSource接口中定义的方法外,还实现了以下方法:

 

* public synchronized void setDriverType(String dt)
* public synchronized String getDriverType()
* public synchronized void setURL(String url)
* public synchronized String getURL()
* public synchronized void setTNSEntryName(String tns)
* public synchronized String getTNSEntryName()


  同时,OracleDataSource还实现了java.io.Serializable和javax.naming.Referenceable接口。

  独立使用数据源

  实际应用中,你可以把OracleDataSource注册到JNDI,也可以单独使用。下面先给出一个单独使用OracleDataSource的例子:

 

// 初始化数据源实例
OracleDataSource ods = new OracleDataSource();

ods.setDriverType("thin");
ods.setServerName("Chicago");
ods.setNetworkProtocol("tcp");
ods.setDatabaseName("chidb");
ods.setPortNumber(1521);
ods.setUser("guest");
ods.setPassword("guest");

// 从数据源中获取数据库连接
Connection conn = ods.getConnection();
// 通过数据库连接进行数据操作
   ………………


  使用OracleDataSource时有几点需要注意:

  如果使用的时服务器端内部驱动程序(server-side internal driver),driverType属性会被设置为kprb,其它所有属性失效。

  如果使用Thin或OCI驱动程序:

  URL中可以包括用户登录名和用户登录密码。例如:

jdbc:oracle:thin:guest/guest@Chicago:1521:chidb;

  果设定了url属性,tnsEntry, driverType, portNumber, networkProtocol, serverName,和databaseName属性将失效。

  在没有设定url属性的情况下,如果设定了tnsEntry属性,portNumber, networkProtocol, serverName,和databaseName属性将失效。

  如果使用OCI驱动程序,并且networkProtocol属性被设定为ipc,除user和password外的所有其他属性将失效。

  通过JNDI使用数据源

  在本节首先给出了一个实际程序,然后通过程序来讲解如何通过JNDI查询数据源。

import java.sql.*;
import javax.sql.*;
import oracle.jdbc.driver.*;
import oracle.jdbc.pool.OracleDataSource;
import javax.naming.*;
import javax.naming.spi.*;
import java.util.Hashtable;

public class DataSourceJNDI
{
public static void main (String args [])
throws SQLException
{
// 初始化名称服务环境
Context ctx = null;
try
{
Hashtable env = new Hashtable (5);
env.put (Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
env.put (Context.PROVIDER_URL, "file:JNDI");
ctx = new InitialContext(env);
}
catch (NamingException ne)
{
ne.printStackTrace();
}


bind(ctx, "jdbc/chidb");
lookup(ctx, "jdbc/chidb");

}

static void bind (Context ctx, String ln)
throws NamingException, SQLException
{
// 创建一个OracleDataSource实例
OracleDataSource ods = new OracleDataSource();

ods.setDriverType("thin");
ods.setServerName("Chicago");
ods.setNetworkProtocol("tcp");
ods.setDatabaseName("chidb");
ods.setPortNumber(1521);
ods.setUser("guest");
ods.setPassword("guest");


// 把OracleDataSource实例注册到JNDI中
System.out.println ("Doing a bind with the logical name : " + ln);
ctx.bind (ln,ods);
System.out.println ("Successfully bound");
}

static void lookup (Context ctx, String ln)
throws NamingException, SQLException
{
// 从JNDI中查询OracleDataSource实例
System.out.println ("Doing a lookup with the logical name : " + ln);
OracleDataSource ods = (OracleDataSource) ctx.lookup (ln);
System.out.println ("Successful lookup");

// 从查询到的OracleDataSource实例中获取数据库连接
  Connection conn = ods.getConnection();
  // 进行数据库操作
getUserName(conn);
// 关闭连接
conn.close();
conn = null;
}

static void getUserName(Connection conn)
throws SQLException
{
// 生成一个Statement实例
Statement stmt = conn.createStatement ();

// 从addressbook表中选中姓名列
ResultSet rset = stmt.executeQuery ("select NAME from addressbook");

// 列出addressbook表所有人的姓名
while (rset.next ())
System.out.println ("Name is " + rset.getString (1));

// 关闭RseultSet实例
rset.close();
rset = null;

// 关闭Statement实例
stmt.close();
stmt = null;
}
}

  程序首先生成了一个Context实例。javax.naming.Context接口定义了名称服务环境(Naming Context)及该环境支持的操作。名称服务环境实际上是由名称和对象间的相互映射组成。程序中初始化名称服务环境的环境工厂(Context Factory)是com.sun.jndi.fscontext.RefFSContextFactory(该类在fscontext.jar中可以找到,由于fscontext.jar中包含的不是标准的API,用户需要从www.javasoft.com中的JNDI专区下载一个名为fscontext1_2beta3.zip的压缩文件,在该文件中可以找到fscontext.jar)。环境工厂的作用是生成名称服务环境的实例,javax.naming.spi.InitialContextFactory接口定义了环境工厂应该如何初始化名称服务环境。在初始化名称服务环境时还需要定义环境的URL。程序中使用的是"file:JNDI",也就是把环境保存在本地硬盘的JNDI目录下。

  初始化了名称服务环境后,就可以把数据源实例注册到名称服务环境中。注册时调用javax.naming.Context.bind()方法,参数为注册名称和注册对象。注册成功后,在JNDI目录下会生成一个.binding文件,该文件记录了当前名称服务环境拥有的名称及对象。

  当需要在名称服务环境中查询一个对象时,需要调用javax.naming.Context.lookup()方法,并把查询到的对象显式转化为数据源对象。然后通过该数据源对象进行数据库操作。

  在这个例子中,程序和名称服务环境都是在同一台计算机上运行。在实际的应用中,程序可以通过RMI或CORBA向名称服务环境注册或查询对象。例如在一个服务器-客户机结构中,客户机上的应用程序只需要知道数据源对象在服务器名称服务环境中的逻辑名称,就可以通过RMI向服务器查询数据源,然后通过建立与数据库的连接.这样就可以解决本文最开始提出的问题。

 



 

 

分享到:
评论

相关推荐

    Tomcat6+spring+jndi配置数据源说明.docx

    Tomcat6+Spring+JNDI配置数据源说明 本文档主要介绍了Tomcat6+Spring+JNDI配置数据源的详细步骤和原理...本文档提供了详细的 Tomcat6+Spring+JNDI 配置数据源的步骤和原理,可以帮助开发者快速了解和实现数据源配置。

    Tongweb5中配置JDBC连接池

    Tongweb5中配置JDBC连接池的文档。Web应用通过JNDI获取Tongweb配置的JDBC数据源(连接池

    jndi数据源的连接方法

    数据源jndi的连接方法,我配置了好久网上帖子,好多是错误的,就整理了一下希望对大家有帮助

    sap常用数据源介绍

    本文档收录了sap中常用的数据源的详细说明及表格组成

    spring-jndi-lookup:如何使用Spring从JNDI查找数据源

    如何使用Spring从JNDI查找数据源 Server.xml <资源名称=“ jdbc / javatechie”全局=“ jdbc / javatechie” auth =“容器” type =“ javax.sql.DataSource” driverClassName =“ com.mysql.jdbc.Driver” url...

    基于 SpringBoot 多数据源 动态数据源 主从分离 快速启动器 支持分布式事务

    基于 SpringBoot 多数据源 动态数据源 主从分离 快速启动器 支持分布式事务。一个基于springboot的快速集成多数据源的启动器。支持 数据源分组 ,适用于多种场景 纯粹多库 读写分离 一主多从 混合模式。支持数据库...

    java-tomcat7-jndi-mysql-oracle-jdbc:访问Tomcat 7中配置的数据源

    使用 JNDI 示例访问 Tomcat7 数据源描述:访问 Tomcat 7 中配置的两个数据源(Oracle 和 MySQL)的 Web 应用程序添加一名作者技术:Java、Tomcat 7、JDBC 摘要:访问Tomcat 7中配置的数据源的Web应用程序它是什么?...

    在weblogic 10 中配置jndi数据源

    NULL 博文链接:https://hanhg.iteye.com/blog/271150

    用jndi操作数据库小实例

    jndi对数据库操作 数据源对数据库操作 最简单的java

    JBoss 下配置 Oracle 数据源

    在 JBoss 中配置 Oracle 数据源是实现企业级应用程序的重要步骤。本文将详细介绍如何在 JBoss 中配置 Oracle 数据源,包括复制配置文件、编辑配置文件、设置数据源参数等步骤。 一、复制配置文件 首先,我们需要将...

    jdbc的详细介绍

    第一章 1. 应用程序连接数据库的方式? 2. JDBC 能完成的功能: 3. JDBC API 包含的内容? 4. JDBC driver ...2. 数据源(工厂模式Factory) 3. JNDI(java naming derectory interface) java命名和目录服务接口

    JDBC 3.0数据库开发与设计

    8.2.2 XML在数据库中的应用模式 8.2.3 XML数据交换技术及应用 8.3 使用JSP和XML两种技术建设动态网站 8.3.1 XML存储数据的优点 8.3.2 XML文档中的Picture对象定义 8.3.3 JSP文档与XML的结合 8.4 用XML和XSL...

    websphere上发布基于jndi的应用

    NULL 博文链接:https://chenhua-1984.iteye.com/blog/1543415

    JNDI项目文件打包.rar

    jndi获取数据库连接,当前软件版本tomcat8jdk8. Tomcat 为每个在其上运行的 Web 应用都提供了一个 JNDI 的 ...Tomcat中的默认数据源支持基于Commons 项目中的DBCP 1.x连接池,也可以使用实现任何其他连接池

    c3p0-0.9.1.2.jar

    C3P0连接池 C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。c3p0是异步操作的,缓慢的JDBC操作通过它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。c3p0是异步...

    数据池连接Name jdbc is not bound in this Context解决方案

    配置tomcat7sqlserver数据连接池java 利用数据源对象建立数据库连接时的错误: Name jdbc is not bound in this Context 解决方案

    数据库清洗产品ETL工具

    针对同一种数据库,使用通用的接口(如ODBC/JDBC)还是原厂商自己的...支持ODBC数据源,支持JNDI数据源,支持共享应用服务器数据源。 支持文本数据,支持将Excel,txt文件,csv,XML文件等文件型的数据直接作为数据源;

    C3P0开源JDBC连接池

    C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring。

    700简历模板

    简历模板启动weblogic 管理服务器,使用管理用户登录weblogic管理控制台。... 9、在需要 应用此 JDBC数据源的 服务器的 复选框 打勾。 10、点击 完成 按钮。 到此位置 完成JDBC配置。不需要重启。直接可以使用。

    tomcat数据源的配置及使用

    tomcat数据源的配置及使用 在eclipse中开发的示例,txt文档的说明,exe文件的教程。在使用JNDI,可分为5步 (1)配置context.xml文件(Tomcat 6.0\conf文件夹下),把连接数据库用的驱动包(sqljdbc.jar)复制到...

Global site tag (gtag.js) - Google Analytics