tomcat8 oracle,Oracle 8i 与 OCI 客户端

Oracle 8i 与 OCI 客户端

虽然并不能严格地解决如何使用 OCI 客户端来创建 JNDI 数据源的问题,但这些注意事项却能和上文提到的 Oracle 与 DBCP 解决方案结合起来使用。

为了使用 OCI 驱动,应该先安装一个 Oracle 客户。你应该已经通过光盘安装好了 Oracle 8i(8.1.7)客户端,并从 otn.oracle.com 下载了适用的 JDBC/OCI 驱动(Oracle8i 8.1.7.1 JDBC/OCI 驱动)。

将 classes12.zip 重命名为 classes12.jar 后,将其复制到 $CATALINA_HOME/lib 中。根据 Tomcat 的版本以及你所使用的 JDK,你可能还必须该文件中的删除 javax.sql.* 类。

连接起来

确保在 $PATH 或 LD_LIBRARY_PATH(可能在 $ORAHOME\bin)目录下存在 ocijdbc8.dll 或 .so 文件,另外还要确认能否使用 System.loadLibrary("ocijdbc8"); 这样的简单测试程序加载本地库。

下面你应该创建一个简单测试用 servlet 或 jsp,其中应该包含以下关键代码:

DriverManager.registerDriver(new

oracle.jdbc.driver.OracleDriver());

conn =

DriverManager.getConnection("jdbc:oracle:oci8:@database","username","password");

目前数据库是 host:port:SID 形式,如果你试图访问测试用servlet/jsp,那么你会得到一个 ServletException 异常,造成异常的根本原因在于 java.lang.UnsatisfiedLinkError:get_env_handle。

分析一下,首先 UnsatisfiedLinkError 表明:

JDBC 类文件和 Oracle 客户端版本不匹配。消息中透露出的意思是没有找到需要的库文件。比如,你可能使用 Oracle 8.1.6 的 class12.zip 文件,而 Oracle 客户端版本则是 8.1.5。classeXXXs.zip 文件必须与 Oracle 客户端文件版本相一致。

出现了一个 $PATH, LD_LIBRARY_PATH 问题。

有报告称,忽略从 otn 网站下载的驱动,使用 $ORAHOME\jdbc\lib 目录中的 class12.zip 文件,同样能够正常运作。

接下来,你可能还会遇到另一个错误消息:ORA-06401 NETCMN: invalid driver designator。

Oracle 文档是这么说的:“异常原因:登录(连接)字符串包含一个不合法的驱动标识符。解决方法:修改字符串,重新提交。”所以,如下面这样来修改数据库(host:port:SID)连接字符串:(description=(address=(host=myhost)(protocol=tcp)(port=1521))(connect_data=(sid=orcl)))

常见问题

下面是一些 Web 应用在使用数据库时经常会遇到的问题,以及一些应对技巧。

数据库连接间歇性失败

Tomcat 运行在 JVM 中。JVM 周期性地会执行垃圾回收(GC),清除不再使用的 Java 对象。当 JVM 执行 GC 时,Tomcat 中的代码执行就会终止。如果配置好的数据库连接建立的最长时间小于垃圾回收的时间,数据库连接就会失败。

在启动 Tomcat 时,将 -verbose:gc 参数添加到 CATALINA_OPTS 环境变量中,就能知道垃圾回收所占用的时间了。在启用 verbose:gc 后, $CATALINA_BASE/logs/catalina.out 日志文件就能包含每次垃圾回收的数据,其中也包括它所占用的时间。

正确调整 JVM 后,垃圾回收可以做到在 99% 的情况下占用时间不超过 1 秒。剩余的情况则只占用几秒钟的时间,只有极少数情况下 GC 会占用超过 10 秒钟的时间。

保证让数据库连接超时设定在 10~15 秒。对于 DBCP,可以使用 maxWaitMillis 参数来设置。

随机性的连接关闭异常

当某一请求从连接池中获取了一个数据库连接,然后关闭了它两次时,往往会出现这样的异常消息。使用连接池时,关闭连接,就会把它归还给连接池,以便之后其他的请求能够重用该连接,而并不会关闭连接。Tomcat 使用多个线程来处理并发请求。下面这个范例就演示了,在 Tomcat 中,一系列事件导致了这种错误。

运行在线程 1中的请求 1获取了一个连接。

请求 1关闭了数据库连接。

JVM 将运行的线程切换为线程 2。

线程 2中运行的请求 2获取了一个数据库连接。

(同一个数据库连接刚被请求 1关闭)

JVM 又将运行的线程切换回为线程 1。

请求 1第二次关闭了数据库连接。

JVM 将运行的线程切换回线程 2。

请求 2和线程 2试图使用数据库连接,但却失败了。因为请求 1已经关闭了它。

}

Connection conn = null;

Statement stmt = null; // Or PreparedStatement if needed

ResultSet rs = null;

try {

conn = ... get connection from connection pool ...

stmt = conn.createStatement("select ...");

rs = stmt.executeQuery();

... iterate through the result set ...

rs.close();

rs = null;

stmt.close();

stmt = null;

conn.close(); // Return to connection pool

conn = null; // Make sure we don't close it twice

} catch (SQLException e) {

... deal with errors ...

} finally {

// Always make sure result sets and statements are closed,

// and the connection is returned to the pool

if (rs != null) {

try { rs.close(); } catch (SQLException e) { ; }

rs = null;

}

if (stmt != null) {

try { stmt.close(); } catch (SQLException e) { ; }

stmt = null;

}

if (conn != null) {

try { conn.close(); } catch (SQLException e) { ; }

conn = null;

}

上下文与全局命名资源

注意,虽然在上面的说明中,把 JNDI 声明放在一个 Context 元素里面,但还是有可能(而且有时更需要)把这些声明放在服务器配置文件的 GlobalNamingResources 区域。被放置在 GlobalNamingResources 区域的资源将会被服务器的各个上下文所共享。

JNDI 资源命名和 Realm 交互

为了让 Realm 能运作,realm 必须指向定义在  或  区域中的数据源,而不是 重新命名的数据源。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值