在 Linux 上使用 oracle instant client 连接 oracle 数据库

2011-03-22 00:00 [linux] [oracle]


多年没用过 oracle 了,今天一个朋友让我帮它解决 oracle 连接问题,就帮忙研究了一下,也算复习一下吧。要说 oracle 这个东西真复杂, 网上的文档也五花八门,试了好多种组合,才最后搞定。

我最初用 oracle 的时候是 oracle 8,是安装在一台 TRU 64 UNIX上,Compaq 的小型机。后来,还用过 oracle 9 之类的。9i 和 10g 基本没怎么用。现在的版本都到11g了,发现有了好多变化。

两台 oracle 服务器,一台运行 oracle 11g express edition, 另一台则是 windows。

需要的东西基本上都可以在 http://www.oracle.com/technetwork/topics/linuxx86-64soft-092277.html 下载。因为服务器是64位的,当然就下64位的程序。服务器是 CentOS 5.5。

instant client

有了 instant client,确实比以前方便多了,不用设一大堆的环境变量。

为了方便测试,顺便装了 sqlplus,另外,也装了 odbc

rpm -ivh oracle-instantclient11.2-basic-11.2.0.2.0.x86_64.rpm
rpm -ivh oracle-instantclient11.2-sqlplus-11.2.0.2.0.x86_64.rpm
rpm -ivh oracle-instantclient11.2-odbc-11.2.0.2.0.x86_64.rpm

因为对这些东西不熟悉,所以看看它都装了些什么是很有帮助的:

$ rpm -qpl oracle-instantclient11.2-basic-11.2.0.2.0.x86_64.rpm 
/usr/lib/oracle/11.2/client64/bin/adrci
/usr/lib/oracle/11.2/client64/bin/genezi
/usr/lib/oracle/11.2/client64/lib/libclntsh.so.11.1
/usr/lib/oracle/11.2/client64/lib/libnnz11.so
/usr/lib/oracle/11.2/client64/lib/libocci.so.11.1
/usr/lib/oracle/11.2/client64/lib/libociei.so
/usr/lib/oracle/11.2/client64/lib/libocijdbc11.so
/usr/lib/oracle/11.2/client64/lib/ojdbc5.jar
/usr/lib/oracle/11.2/client64/lib/ojdbc6.jar
/usr/lib/oracle/11.2/client64/lib/xstreams.jar
$ rpm -qpl oracle-instantclient11.2-sqlplus-11.2.0.2.0.x86_64.rpm 
/usr/bin/sqlplus64
/usr/lib/oracle/11.2/client64/bin/sqlplus
/usr/lib/oracle/11.2/client64/lib/glogin.sql
/usr/lib/oracle/11.2/client64/lib/libsqlplus.so
/usr/lib/oracle/11.2/client64/lib/libsqlplusic.so
$ rpm -qpl oracle-instantclient11.2-odbc-11.2.0.2.0.x86_64.rpm 
/usr/lib/oracle/11.2/client64/lib/libsqora.so.11.1
/usr/share/oracle/11.2/client64/ODBCRelnotesJA.htm
/usr/share/oracle/11.2/client64/ODBCRelnotesUS.htm
/usr/share/oracle/11.2/client64/ODBC_IC_Readme_Unix.html
/usr/share/oracle/11.2/client64/odbc_update_ini.sh

把 .bashrc 里加了以下环境变量

LD_LIBRARY_PATH=/usr/local/lib:/usr/lib/oracle/11.2/client64/lib

连接本机上的 express edition 成功

sqlplus user/pass@127.0.0.1/XE

但用以下命令连接远程机器上的服务怎么也不成功 sqlplus64 user/pass@192.168.1.99:1521/orcl

SQL*Plus: Release 11.2.0.2.0 Production on Tue Mar 22 19:57:35 2011

Copyright (c) 1982, 2010, Oracle.  All rights reserved.

ERROR:
ORA-12514: TNS:listener does not currently know of service requested in connect descriptor

后来只好用 tns 了。在 /usr/lib/oracle/11.2 下创建 tnsnames.ora

mkdir -p /usr/lib/oracle/11.2/network/admin/tnsnames.ora

编译 tnsnames.ora 如下:

orcl =
    (DESCRIPTION =
            (ADDRESS_LIST =
                    (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.99)(PORT = 1521))
            )
            (CONNECT_DATA =
                    (SERVER=DEDICATED)
                    (SID = orcl)
            )
    )

在 .bashrc 中添加如下环境变量

export ORACLE_HOME=/usr/lib/oracle/11.2
export TNS_ADMIN=/usr/lib/oracle/11.2/network/admin

重新登录 shell(我试过直接 source .bashrc ,但总不对劲,后来重新登录 shell 好了,原因不明,没有求证)。

以下命令连接

sqlplus64 user/pass@orcl

ODBC

用 yum 安装的 ODBC 版本比较低,忘了有个什么错误了。反正我直接删掉了,下载最新的代码编译安装。

wget ftp://ftp.unixodbc.org/pub/unixODBC/unixODBC-2.3.0.tar.gz
tar xvzf unixODBC-2.3.0.tar.gz
cd unixODBC-2.3.0
./configure && make && make install

unixodbc.org 上只说明有个 easysoft 的 oracle odbc 驱动,咨询了一下,一台机器需要几千英磅。后来发现 oracle 自己有 ODBC 驱动了(好像是从 10g 开始就有的,我不知道,因此走了弯路)。

执行以下命令会生成 /usr/local/etc/odbcinst.ini 以及在当前用户目录下生成 .odbc.ini

sh /usr/share/oracle/11.2/client64/odbc_update_ini.sh /usr/local

但是它生成的 odbcinst.ini 中 Driver 的路径是错的,需要改成

[Oracle 11g ODBC driver]
Description     = Oracle ODBC driver for Oracle 11g
Driver          = /usr/lib/oracle/11.2/client64/lib/libsqora.so.11.1

.odbc.ini 基本不用改,我只把 ServerName 改成 127.0.0.1/XE

[OracleODBC-11g]
Application Attributes = T
Attributes = W
BatchAutocommitMode = IfAllSuccessful
BindAsFLOAT = F
CloseCursor = F
DisableDPM = F
DisableMTS = T
Driver = Oracle 11g ODBC driver
DSN = OracleODBC-11g
EXECSchemaOpt =
EXECSyntax = T
Failover = T
FailoverDelay = 10
FailoverRetryCount = 10
FetchBufferSize = 64000
ForceWCHAR = F
Lobs = T
Longs = T
MaxLargeData = 0
MetadataIdDefault = F
QueryTimeout = T
ResultSets = T
ServerName = 127.0.0.1/XE
SQLGetData extensions = F
Translation DLL =
Translation Option = 0
DisableRULEHint = T
UserID = 
StatementCache=F
CacheBufferSize=20
UseOCIDescribeAny=F

使用 isql -v OracleODBC-11g user pass 连接成功

将 ServerName 改成 orcl ,连接远程服务器成功。

更新:Erlang ODBC

一直想试一下 Erlang ODBC,正好借朋友的机器试一下。安装 erlang,然后测试(使用express 自带的 hr 数据库),出错。

    $ erl
	1> odbc:start().
ok
2> {ok, C} = odbc:connect("DSN=OracleODBC-11g;UID=hr;PWD=hr", []).

=ERROR REPORT==== 22-Mar-2011::20:15:11 ===
ODBC: received unexpected info: {tcp_closed,#Port<0.702>}


=ERROR REPORT==== 22-Mar-2011::20:15:11 ===
** Generic server <0.39.0> terminating 
** Last message in was {#Port<0.700>,{exit_status,23}}
** When Server state == {state,#Port<0.700>,
                               {<0.32.0>,#Ref<0.0.0.39>},
                               <0.32.0>,undefined,on,undefined,undefined,on,
                               connecting,undefined,0,
                               [#Port<0.698>,#Port<0.699>],
                               #Port<0.701>,#Port<0.702>}
** Reason for termination == 
** {port_exit,collecting_of_driver_information_faild}
** exception error: no match of right hand side value {error,connection_closed}

查了半天,有人说要禁掉 scrollable_cursors:

3> {ok, C} = odbc:connect("DSN=OracleODBC-11g;UID=hr;PWD=hr", [{scrollable_cursors, off}]).
{ok,<0.44.0>}
4> 
4> odbc:sql_query(C, "select * from tab").
{selected,["TNAME","TABTYPE","CLUSTERID"],
          [{"REGIONS","TABLE",null},
           {"COUNTRIES","TABLE",null},
           {"LOCATIONS","TABLE",null},
           {"DEPARTMENTS","TABLE",null},
           {"JOBS","TABLE",null},
           {"EMPLOYEES","TABLE",null},
           {"JOB_HISTORY","TABLE",null},
           {"EMP_DETAILS_VIEW","VIEW",null}]}

但对于更新(或 insert,我觉得可能是对于所有不返回结果的语句),以及查些不支持的(或会出错的)查询,会crash

5> odbc:sql_query(C, "desc job_history"). 

=ERROR REPORT==== 22-Mar-2011::20:20:13 ===
ODBC: received unexpected info: {tcp_closed,#Port<0.713>}


=ERROR REPORT==== 22-Mar-2011::20:20:13 ===
** Generic server <0.44.0> terminating 
** Last message in was {#Port<0.711>,{exit_status,19}}
** When Server state == {state,#Port<0.711>,
                               {<0.40.0>,#Ref<0.0.0.62>},
                               <0.40.0>,undefined,on,false,false,off,
                               connected,undefined,0,
                               [#Port<0.709>,#Port<0.710>],
                               #Port<0.712>,#Port<0.713>}
** Reason for termination == 
** {port_exit,could_not_access_column_count}
{error,connection_closed}

从网上找到几个相关的贴子,如http://erlang.2086793.n4.nabble.com/PATCH-ODBC-application-discarding-sqlstate-in-get-diagnos-function-td2119719.html,但这个 patch 应该在 R13B 就打入了,而我是用的 R14B,查看源代码也没有问题。没有深究。但回头在我机器(MAC/R13B02)与 mysql ODBC 连接却没发现问题。究竟也不知道是 Erlang 版本问题还是 oracle/mysql 问题。总之,到此为止了,这种商业的数据库可查找的资料比较少,用起来费劲。

《大道至简》

七歌
微信公众号

七歌杜金房
微信视频号