戰(zhàn):解決版本不匹配)
簡(jiǎn)介這套Oracle Instant Client合集面向Windows x64平臺(tái)上的數(shù)據(jù)庫(kù)開(kāi)發(fā)、運(yùn)維及測(cè)試人員解決在64位環(huán)境中同時(shí)適配多個(gè)版本Oracle數(shù)據(jù)庫(kù)客戶端的實(shí)際操作問(wèn)題。資源收錄10.2、11.2和12.2三個(gè)常用版本全部取自O(shè)racle官方下載地址可充當(dāng)不同應(yīng)用連接數(shù)據(jù)庫(kù)時(shí)的本地客戶端運(yùn)行環(huán)境尤其適合需要并行維護(hù)多套Oracle服務(wù)的項(xiàng)目借助它可省去逐個(gè)訪問(wèn)官網(wǎng)、比對(duì)版本兼容性的繁瑣環(huán)節(jié)。壓縮包為單個(gè)RAR格式整體約118.35MB便于一次性獲取由于上傳方未提供壓縮包內(nèi)文件數(shù)量與類型明細(xì)只以包體大小作參考。已有535人學(xué)習(xí)下載適合具備一定數(shù)據(jù)庫(kù)基礎(chǔ)、希望快速備齊多版本客戶端的開(kāi)發(fā)與運(yùn)維人員選用。1. Oracle Instant Client 三版本合集除了下載還要解決匹配與切換一臺(tái)老服務(wù)器上連著 Oracle 12c某天業(yè)務(wù)要求把數(shù)據(jù)遷到新庫(kù)升級(jí)之后程序直接報(bào) ORA-03134。查了一圈網(wǎng)絡(luò)通、賬號(hào)對(duì)、監(jiān)聽(tīng)正常最后才發(fā)現(xiàn)是客戶端庫(kù)里還是 10.2 那套老家伙——新數(shù)據(jù)庫(kù)根本不認(rèn)它的協(xié)議。這時(shí)候你就明白Oracle Instant Client x64 的 10.2 / 11.2 / 12.2 三版本合集并不只是網(wǎng)盤(pán)里多收了三個(gè)壓縮包那么簡(jiǎn)單。它實(shí)際解決三件事老版本客戶端下載難、客戶端版本和數(shù)據(jù)庫(kù)版本匹配難、同一臺(tái)機(jī)器上多個(gè)項(xiàng)目切換版本難。適合運(yùn)維、DBA以及用 C、Python、PHP 寫(xiě) Oracle 數(shù)據(jù)抽取的開(kāi)發(fā)者。下面這套操作路徑是我在多臺(tái) Linux 服務(wù)器上反復(fù)用過(guò)、也踩過(guò)坑的完整方案。2. 10.2 / 11.2 / 12.2 版本對(duì)比先定選型再談安裝2.1 合集里都裝了些什么basic、sqlplus、odbc、jdbc先說(shuō)清楚 Instant Client 的形態(tài)。它不是一個(gè)大安裝包而是由官方發(fā)布的一組獨(dú)立組件組成這個(gè)三版本合集說(shuō)白了就是把三個(gè)大版本各自的組件按目錄收攏到一起。最常見(jiàn)的組件是 basic 和 sqlplus有的合集還會(huì)帶 odbc、jdbc、devel/sdk 包。它們各自負(fù)責(zé)什么一張表看清楚組件作用是否必須basicOCI 核心庫(kù)提供 libclntsh.so、libnnz.so、libocci.so所有連接都靠它必須sqlplus命令行交互工具依賴 basic盡量裝排查問(wèn)題靠它odbc通過(guò) unixODBC 訪問(wèn) Oracle 的驅(qū)動(dòng)按需jdbc純 Java jar不需要裝到系統(tǒng)里不需要devel/sdkC/C 頭文件與示例編 Pro*C 程序時(shí)用需要編譯時(shí)核心是 basic 包。里面那十幾個(gè) .so 文件幾乎承載了連接 Oracle 的全部邏輯網(wǎng)絡(luò)協(xié)議、加密協(xié)商、字符集轉(zhuǎn)換、會(huì)話管理。sqlplus 只是這些庫(kù)的一個(gè)薄殼。所以很多老項(xiàng)目連數(shù)據(jù)庫(kù)根本不裝 sqlplus只在代碼里動(dòng)態(tài)加載 libclntsh.so這也是 Instant Client 能被到處分發(fā)的原因——它不是完整數(shù)據(jù)庫(kù)客戶端官方允許自由再分發(fā)合集里裝的也是原版組件。新手容易有個(gè)誤解覺(jué)得 Instant Client 是精簡(jiǎn)版數(shù)據(jù)庫(kù)應(yīng)該帶上 exp、imp、sqlldr。實(shí)際上它一個(gè)都不帶。要導(dǎo)數(shù)據(jù)必須裝完整版客戶端。遇到這種需求別在合集里找找不到是正常的。2.2 客戶端與數(shù)據(jù)庫(kù)版本怎么配對(duì)一張對(duì)應(yīng)關(guān)系表版本配對(duì)是大部分人第一次翻車的地方。有人覺(jué)得客戶端越新越好拿 12.2 去連 10g 老庫(kù)結(jié)果碰到老庫(kù)根本不認(rèn)識(shí)的加密協(xié)商也有人堅(jiān)持老庫(kù)必須配老客戶端10.2 死磕 19c直接 ORA-03134。我的經(jīng)驗(yàn)是遵守一條粗糙但好記的原則客戶端版本不要比目標(biāo)數(shù)據(jù)庫(kù)低兩個(gè)大版本也不要高低配得過(guò)于極端。目標(biāo)數(shù)據(jù)庫(kù)版本首選 Instant Client可以用但不推薦基本別碰Oracle 10g10.2 / 11.212.2更高版本意義不大Oracle 11g11.2 / 12.210.2需要小版本足夠新的 10.2 補(bǔ)丁Oracle 12c12.211.2 較高補(bǔ)丁10.2 會(huì)碰加密協(xié)商問(wèn)題Oracle 18c / 19c12.211.2 視情況10.2 基本必報(bào) ORA-03134這張表背后是 Oracle 的協(xié)議兼容邏輯。SQL*Net 客戶端和服務(wù)端協(xié)商時(shí)會(huì)交換版本號(hào)差距超過(guò)兩個(gè)大版本協(xié)商階段就可能直接中斷。10.2 連 11g 一般還能靠補(bǔ)丁撐過(guò)去連 12c 以上就會(huì)開(kāi)始出現(xiàn)各種加密、認(rèn)證相關(guān)的報(bào)錯(cuò)到了 18c/19c 干脆拒絕連接。這套合集的實(shí)用價(jià)值就在這里老庫(kù)不動(dòng)新庫(kù)也能連目錄里三個(gè)版本隨時(shí)待命。2.3 glibc 邊界為什么同一個(gè)合集里選錯(cuò)版本會(huì)直接起不來(lái)Linux x64 下的 Instant Client 是動(dòng)態(tài)鏈接到 glibc 的不同版本編譯年代不同要求的 glibc 符號(hào)版本也不同。這里的坑非常典型把 12.2 丟到 CentOS 6 上運(yùn)行時(shí)報(bào)version GLIBC_2.14 not found把 10.2 丟到 CentOS 7 上反而經(jīng)常能跑。只按“年代新舊”判斷能不能用往往會(huì)栽跟頭。Instant Client發(fā)布時(shí)代常見(jiàn) glibc典型運(yùn)行系統(tǒng)10.22005–20092.3 以上RHEL 4/5、CentOS 4/5新系統(tǒng)多數(shù)也能跑11.22009–20132.12 以上CentOS 6/7兼容范圍最寬12.22016–20182.17 以上CentOS 7/8、Ubuntu 16.04CentOS 6 慎用判斷當(dāng)前系統(tǒng)的 glibc 很簡(jiǎn)單ldd --version | head -1再對(duì)客戶端庫(kù)里實(shí)際引用的最高 GLIBC 符號(hào)做個(gè)探測(cè)能提前預(yù)判是否兼容strings /opt/oracle/ic/12.2/libclntsh.so | grep ^GLIBC_ | sort -V | tail -5這條命令會(huì)把 libclntsh.so 里所有 GLIBC 符號(hào)版本列出來(lái)取最后幾個(gè)就是它運(yùn)行時(shí)的最低門(mén)檻。如果系統(tǒng) glibc 低于這個(gè)門(mén)檻體驗(yàn)基本就是啟動(dòng)即報(bào)錯(cuò)。所以合集三個(gè)版本同時(shí)保留的價(jià)值也在這換一個(gè)版本試試比到處找編譯環(huán)境快得多。3. Linux x64 安裝三個(gè)版本解壓、環(huán)境變量與最小驗(yàn)證命令3.1 目錄規(guī)劃與解壓為什么我建議全部用 zip不要用 rpm拿到合集后的第一件事不是急著解壓而是定目錄規(guī)范。我一般固定用/opt/oracle/ic作為根目錄下面按版本號(hào)建三個(gè)子目錄避免后面出現(xiàn)“版本互相覆蓋”的混亂局面。一個(gè)版本一套庫(kù)目錄名就是版本號(hào)切環(huán)境時(shí)一目了然。IC_ROOT/opt/oracle/ic mkdir -p ${IC_ROOT}/src ${IC_ROOT}/10.2 ${IC_ROOT}/11.2 ${IC_ROOT}/12.2 cd ${IC_ROOT}/src # 以合集內(nèi)的實(shí)際文件名為準(zhǔn)這里是最常見(jiàn)的命名方式 unzip -q instantclient-basic-linux.x64-11.2.0.4.0.zip unzip -q instantclient-sqlplus-linux.x64-11.2.0.4.0.zip mv instantclient_11_2 ${IC_ROOT}/11.2解壓后要檢查一下目錄內(nèi)容11.2 和 12.2 的 zip 解開(kāi)后自帶instantclient_11_2、instantclient_12_2這種外層目錄10.2 的包結(jié)構(gòu)比較亂有些 zip 解開(kāi)后文件直接散出來(lái)。建議解壓前先執(zhí)行unzip -l 包名.zip看一眼頂層結(jié)構(gòu)再?zèng)Q定要不要加-d參數(shù)。另外 sqlplus 包解壓后是把文件合并進(jìn) basic 目錄所以先解 basic再解 sqlplus。為什么刻意避開(kāi) rpmrpm 方式會(huì)把客戶端庫(kù)裝到系統(tǒng)庫(kù)里還要往 ldconfig 緩存里登記單版本沒(méi)什么感覺(jué)三版本共存時(shí)互相覆蓋的問(wèn)題會(huì)讓你懷疑人生。而且 10.2 年代的 rpm 包依賴 libaioCentOS 7 上一裝一個(gè)坑。zip 方式完全不碰系統(tǒng)庫(kù)目錄版本之間天然隔離后悔藥隨時(shí)可以吃。如果你手里的合集是 x64 平臺(tái)的老項(xiàng)目還要確認(rèn)一下應(yīng)用本身是 64 位合集里只有 64 位庫(kù)32 位程序連不上。3.2 寫(xiě)一個(gè) ic_env.shLD_LIBRARY_PATH、NLS_LANG、TNS_ADMIN解壓只是把文件放好真正“啟用”一個(gè)版本靠的是環(huán)境變量。我習(xí)慣把環(huán)境變量寫(xiě)成一個(gè)可 source 的腳本放在/opt/oracle/ic/ic_env.sh參數(shù)就是版本號(hào)。腳本內(nèi)容如下#!/bin/bash # ic_env.sh加載指定版本的 Instant Client 環(huán)境 # 用法. /opt/oracle/ic/ic_env.sh 11.2 IC_ROOT/opt/oracle/ic case ${1} in 10.2) ORACLE_HOME${IC_ROOT}/10.2 ;; 11.2) ORACLE_HOME${IC_ROOT}/11.2 ;; 12.2) ORACLE_HOME${IC_ROOT}/12.2 ;; *) echo usage: . ic_env.sh 10.2|11.2|12.2 return 1 ;; esac export ORACLE_HOME export LD_LIBRARY_PATH${ORACLE_HOME} export PATH${ORACLE_HOME}:${PATH} export TNS_ADMIN${IC_ROOT}/network/admin export NLS_LANGAMERICAN_AMERICA.AL32UTF8這里每個(gè)變量都值得講究一下。LD_LIBRARY_PATH 我刻意沒(méi)有拼接舊值而是直接覆蓋成當(dāng)前版本的目錄目的就是避免多次 source 后路徑里殘留上一版本。這個(gè)過(guò)程非常容易出事哪天切到 12.2 干完活又切回 11.2LD_LIBRARY_PATH 里如果還是“12.2:11.2”這種順序動(dòng)態(tài)鏈接庫(kù)按順序找到的還是 12.2等于切換無(wú)效。TNS_ADMIN 指向所有版本共用的 tnsnames 目錄而不是每個(gè)版本維護(hù)一套。不同項(xiàng)目只需要在這一個(gè)目錄里追加連接串版本切換不影響連接配置。NLS_LANG 設(shè)置成AMERICAN_AMERICA.AL32UTF8是通用值避免 sqlplus 和 OCI 程序出現(xiàn)中文亂碼或者 ORA-12705。注意腳本必須用 source 方式執(zhí)行. /opt/oracle/ic/ic_env.sh 11.2直接執(zhí)行不會(huì)在當(dāng)前 shell 里留下任何 export。3.3 最小驗(yàn)證sqlplus -V、Easy Connect、tnsping環(huán)境變量加載完別急著寫(xiě)業(yè)務(wù)代碼先用三條命令確認(rèn)這一版本真的能干活. /opt/oracle/ic/ic_env.sh 11.2 sqlplus -V sqlplus system/密碼//192.168.1.10:1521/ORCLsqlplus -V 只打印版本號(hào)但它能正常跑起來(lái)本身就說(shuō)明 libclntsh.so 被找到了。真正驗(yàn)證連接能力用 Easy Connect 格式//主機(jī):端口/服務(wù)名最直接它繞過(guò) tnsnames.ora把“配置問(wèn)題”和“網(wǎng)絡(luò)/認(rèn)證問(wèn)題”一刀切開(kāi)。如果 Easy Connect 能連上但項(xiàng)目里自定義的服務(wù)名連不上問(wèn)題就在 tnsnames.ora 解析。想在 tnsnames 里管理多個(gè)庫(kù)就編輯${TNS_ADMIN}/tnsnames.ora加一段ORCL (DESCRIPTION (ADDRESS (PROTOCOL TCP)(HOST 192.168.1.10)(PORT 1521)) (CONNECT_DATA (SERVICE_NAME orcl)))然后在 sqlplus 里直接sqlplus system/密碼ORCL。tnsping 命令在 11.2/12.2 的 tools 包里合集里如果沒(méi)有這個(gè)組件直接用 Easy Connect 登錄驗(yàn)證即可不必為了 tnsping 糾結(jié)。括號(hào)配對(duì)和縮進(jìn)只要格式完整就行解析器對(duì)縮進(jìn)不敏感但括號(hào)少一個(gè)整條連接串都會(huì)失效。4. 單機(jī)三版本共存為什么不能靠系統(tǒng)庫(kù)目錄而要靠環(huán)境腳本切換4.1 為什么不能把 libclntsh.so 全部放進(jìn) /usr/lib 或 /usr/local/lib多版本共存最忌諱的做法就是把三個(gè)版本的 .so 文件全部拷進(jìn)/usr/lib。表面上看文件都放好了應(yīng)用也能編譯鏈接運(yùn)行時(shí)的暗雷卻埋在動(dòng)態(tài)鏈接器的搜索順序里。10.2 的庫(kù)文件名是 libclntsh.so.10.111.2 是 11.112.2 是 12.1它們各自的 SONAME 不同但目錄里通常還有一個(gè)不帶數(shù)字后綴的軟鏈叫 libclntsh.so。程序編譯時(shí)鏈接的目標(biāo)是后者運(yùn)行時(shí)動(dòng)態(tài)鏈接器在緩存里找到了哪一條軟鏈就加載哪一套庫(kù)完全沒(méi)有確定性。我曾經(jīng)見(jiàn)過(guò)一個(gè)應(yīng)用編譯時(shí)用的 12.2 頭文件運(yùn)行時(shí)因?yàn)?usr/lib里的軟鏈指向 11.2報(bào)了一堆亂七八糟的 ORA-12557 和符號(hào)錯(cuò)誤。排查到最后只能把所有版本都清出系統(tǒng)目錄改用 LD_LIBRARY_PATH 控制。從那時(shí)起我就形成一個(gè)習(xí)慣Instant Client 的版本管理單位是“進(jìn)程環(huán)境”不是“系統(tǒng)目錄”。誰(shuí)家的進(jìn)程需要哪個(gè)版本就把哪個(gè)版本放進(jìn)它自己的環(huán)境變量里。4.2 一套 ic_set 函數(shù)讓切換變成 source 一行命令環(huán)境腳本每次都要帶路徑和參數(shù)用久了容易手滑。我把腳本收斂成一個(gè) shell 函數(shù)寫(xiě)進(jìn)用戶的~/.bashrc日常切換只需要一行cat ~/.bashrc EOF ic_set() { IC_ROOT/opt/oracle/ic case $1 in 10.2|11.2|12.2) export ORACLE_HOME${IC_ROOT}/$1 ;; *) echo usage: ic_set 10.2|11.2|12.2; return 1 ;; esac export LD_LIBRARY_PATH${ORACLE_HOME} export PATH${ORACLE_HOME}:${PATH} export TNS_ADMIN${IC_ROOT}/network/admin export NLS_LANGAMERICAN_AMERICA.AL32UTF8 echo current: $1 at ${ORACLE_HOME} } EOF . ~/.bashrc ic_set 12.2函數(shù)最后打印當(dāng)前目錄是為了切換后先確認(rèn)一下再開(kāi)干。這里的 LD_LIBRARY_PATH 同樣用了覆蓋策略保證同一時(shí)刻當(dāng)前 shell 里只有一個(gè)版本生效。如果你有別的業(yè)務(wù)動(dòng)態(tài)庫(kù)需要靠 LD_LIBRARY_PATH 提供可以把它們單獨(dú)放到另一個(gè)變量里切換時(shí)拼在 ORACLE_HOME 后面不要把舊版本路徑原封不動(dòng)地留下。如果你需要在同一個(gè) shell 里同時(shí)跑兩個(gè)不同版本的程序單靠 export 做不到因?yàn)榄h(huán)境變量是進(jìn)程級(jí)別的。遇到這種場(chǎng)景我一般用子 shell 隔離( ic_set 10.2 python3 old_app.py ) ( ic_set 12.2 python3 new_app.py ) 每個(gè)子 shell 里的環(huán)境變量互相獨(dú)立兩個(gè)版本可以并行這種方式在數(shù)據(jù)遷移對(duì)比時(shí)特別實(shí)用。4.3 給外部應(yīng)用指定版本Python、PHP-FPM、Pro*C外部程序的版本加載方式各不相同最容易翻車的不是命令行工具而是常駐服務(wù)和編譯型應(yīng)用。Python 配合 cx_Oracle或 python-oracledb 的 thick 模式時(shí)庫(kù)的加載發(fā)生在 import 階段。先在 shell 里 ic_set 到目標(biāo)版本再啟動(dòng) Python它就會(huì)加載 LD_LIBRARY_PATH 里的那套 libclntsh.so。驗(yàn)證方式很簡(jiǎn)單ic_set 12.2 python3 - PY import cx_Oracle print(client version:, cx_Oracle.clientversion()) PY打印出來(lái)的版本號(hào)一定要和你預(yù)期的目錄一致。如果這里顯示的還是舊版本說(shuō)明 shell 環(huán)境沒(méi)切干凈去檢查 LD_LIBRARY_PATH 里是不是殘留了別的版本目錄。PHP-FPM 是另一類坑它是常駐進(jìn)程環(huán)境變量在進(jìn)程啟動(dòng)那一刻就固定了。你在命令行里 source 一萬(wàn)次PHP-FPM 里加載的還是啟動(dòng)時(shí)的舊庫(kù)。解決辦法只有一條systemctl restart php-fpm改完環(huán)境腳本、切完版本之后所有面向 PHP 的連接都要重啟 FPM 才會(huì)換血這是我在某項(xiàng)目上翻過(guò)車才記住的。Pro*C 這類編譯型程序要同時(shí)注意編譯期和運(yùn)行期兩套路徑。編譯時(shí)指定頭文件和庫(kù)運(yùn)行時(shí)還要保證加載的是同一個(gè)版本ic_set 11.2 proc inametest.pc onametest.c gcc -o test test.c -I${ORACLE_HOME}/sdk/include \ -L${ORACLE_HOME} -lclntsh頭文件和庫(kù)的版本不一致輕則編譯通過(guò)運(yùn)行段錯(cuò)誤重則結(jié)構(gòu)體錯(cuò)位報(bào)錯(cuò)。如果合集里沒(méi)有 sdk 組件那里不會(huì)有 include 目錄需要先把 sdk 解壓進(jìn)來(lái)。運(yùn)行測(cè)試程序前再執(zhí)行一次 ic_set 到同一個(gè)版本用 ldd 確認(rèn)鏈接的庫(kù)路徑。5. 常見(jiàn)問(wèn)題與排查三版本合集的 5 個(gè)踩坑記錄5.1 解壓后 sqlplus 報(bào)錯(cuò)libclntsh.so 找不到現(xiàn)象sqlplus 明明就在$ORACLE_HOME下執(zhí)行時(shí)卻報(bào)error while loading shared libraries: libclntsh.so.10.1: cannot open shared object file。原因其實(shí)很單純LD_LIBRARY_PATH 沒(méi)設(shè)置或者 sqlplus 所在的目錄和庫(kù)所在的目錄不是同一個(gè)。10.2 年代的 zip 集合經(jīng)常出現(xiàn)這種結(jié)構(gòu)sqlplus 被解壓到單獨(dú)一個(gè)目錄而 libclntsh.so 在 basic 目錄里兩者沒(méi)有合并。解決時(shí)先確認(rèn)環(huán)境變量是否真的加載了. /opt/oracle/ic/ic_env.sh 10.2 echo ${LD_LIBRARY_PATH} ldd ${ORACLE_HOME}/sqlplus | grep -E clntsh|nnz如果 ldd 輸出里顯示某個(gè) .so 后有 “not found”說(shuō)明庫(kù)路徑不對(duì)。把 sqlplus 挪進(jìn) basic 目錄或者用軟鏈把 libclntsh.so 指到$ORACLE_HOME下都能解決。這里提醒一句不要在沒(méi)有任何確認(rèn)的情況下把整個(gè)版本目錄里的 .so 全部軟鏈到 /usr/lib那等于把第 4 節(jié)講的坑重新踩一遍。5.2 老系統(tǒng)加載 12.2 報(bào)錯(cuò)version GLIBC_2.14 not found現(xiàn)象在 CentOS 6 上切換到 12.2sqlplus -V 直接報(bào)version GLIBC_2.14 not foundldd 也是一片 not found。原因很直接12.2 編譯時(shí)鏈接的 glibc 符號(hào)版本比 CentOS 6 自帶的 2.12 高動(dòng)態(tài)鏈接器在系統(tǒng)庫(kù)里找不到對(duì)應(yīng)符號(hào)。這套用來(lái)判斷客戶端版本和發(fā)行版匹配關(guān)系比查官方矩陣快得多strings /opt/oracle/ic/12.2/libclntsh.so | grep ^GLIBC_ | sort -V | tail -1我的處理是這臺(tái)機(jī)器不用 12.2直接切到 11.2連通性不受影響。如果業(yè)務(wù)方案鎖定 12.2那問(wèn)題就變成系統(tǒng)層級(jí)的升級(jí)把應(yīng)用遷到 CentOS 7 或更新系統(tǒng)的容器鏡像里。glibc 是不建議在線升級(jí)的為了一個(gè)客戶端庫(kù)去動(dòng)系統(tǒng)基礎(chǔ)庫(kù)風(fēng)險(xiǎn)收益完全不成比例。5.3 ORA-12557協(xié)議適配器不可加載現(xiàn)象sqlplus 能啟動(dòng)版本號(hào)也能打出來(lái)但一執(zhí)行連接就報(bào)ORA-12557: TNS:protocol adapter not loadable。原因十有八九出在庫(kù)加載錯(cuò)亂上。這種情況在多版本共存時(shí)最容易出現(xiàn)LD_LIBRARY_PATH 里同時(shí)殘留著 10.2 和 12.2 的路徑動(dòng)態(tài)鏈接器先找到的是舊版本協(xié)議適配器模塊內(nèi)部版本對(duì)不上直接罷工。還有一個(gè)隱蔽來(lái)源是常駐進(jìn)程沒(méi)重啟比如 PHP-FPM 還持著舊庫(kù)。排查按三步走echo ${LD_LIBRARY_PATH} file ${ORACLE_HOME}/sqlplus ldd ${ORACLE_HOME}/sqlplus | grep -E clntsh|nnz重點(diǎn)檢查 LD_LIBRARY_PATH 里是否只有一個(gè)版本路徑。如果發(fā)現(xiàn)多個(gè)回到第 4 節(jié)的 ic_set 函數(shù)重新 source 一次覆蓋環(huán)境變量。對(duì)于服務(wù)類進(jìn)程改完環(huán)境后必須重啟對(duì)應(yīng)服務(wù)比如systemctl restart php-fpm或重啟 Java 服務(wù)的 systemd unit否則 ORA-12557 查多久都查不出來(lái)。5.4 10.2 連新庫(kù)直接報(bào) ORA-03134現(xiàn)象某項(xiàng)目堅(jiān)持使用 10.2 客戶端連接 19c 數(shù)據(jù)庫(kù)連接瞬間報(bào)ORA-03134: Connections to this server version are not supported有時(shí)候也會(huì)變成 ORA-28040。原因客戶端和服務(wù)器版本差距太大雙方在協(xié)議協(xié)商階段無(wú)法就認(rèn)證方式達(dá)成一致。這屬于根本性不兼容靠改 tnsnames 或調(diào)網(wǎng)絡(luò)參數(shù)都救不回來(lái)。這也正是三版本合集存在的意義項(xiàng)目里老系統(tǒng)仍然用 10.2 連 10g/11g 庫(kù)新增的 19c 庫(kù)單獨(dú)走 12.2。解決命令其實(shí)就一行ic_set 12.2 sqlplus system/密碼//192.168.1.10:1521/ORCL19如果數(shù)據(jù)庫(kù)端配置了嚴(yán)格的認(rèn)證策略比如只允許新版本密碼算法可能還需要在數(shù)據(jù)庫(kù)端 sqlnet.ora 里對(duì)老客戶端做兼容性放行。但這屬于數(shù)據(jù)庫(kù)端安全策略調(diào)整不應(yīng)該由客戶端合集方案單方面決定。記住一個(gè)原則能用客戶端升級(jí)解決的問(wèn)題不要去動(dòng)數(shù)據(jù)庫(kù)端的全局安全配置。5.5 rpm 方式裝 10.2 報(bào)錯(cuò)libaio.so.1 缺失現(xiàn)象不用 zip 而是用 rpm 包安裝合集里的 10.2執(zhí)行rpm -ivh oracle-instantclient10.2-basic-*.rpm時(shí)提示libaio.so.1: cannot open shared object file或者裝上了 sqlplus 一運(yùn)行就段錯(cuò)誤。原因10.2 時(shí)代的 rpm 包對(duì)依賴聲明不完整Linux 系統(tǒng)通常默認(rèn)沒(méi)有安裝 libaio或者只有 64 位沒(méi)有 32 位版本。不少人的第一反應(yīng)是加--nodeps跳過(guò)依賴檢查這個(gè)操作短期能用長(zhǎng)期必有隱患因?yàn)槿绷?libaio 的 OCI 庫(kù)在異步 I/O 場(chǎng)景下會(huì)莫名其妙崩潰。標(biāo)準(zhǔn)處理是先裝系統(tǒng)依賴yum install -y libaio libaio-devel然后把 rpm 方式整個(gè)放棄改用第 3 節(jié)里的 zip 解壓方案。zip 包完全不依賴 rpm 數(shù)據(jù)庫(kù)和 libaio 的聲明關(guān)系只要系統(tǒng)里有 libaio.so.1 就能運(yùn)行省去一堆依賴糾纏。這是我在生產(chǎn)環(huán)境第二次被 rpm 方式坑過(guò)之后定下的規(guī)矩Instant Client 不管哪個(gè)版本一律 zip 管理。6. 把三版本客戶端的加載固化進(jìn)項(xiàng)目一鍵腳本與驗(yàn)庫(kù)習(xí)慣如果你的項(xiàng)目不止一臺(tái)機(jī)器建議再往前走一步把環(huán)境加載和驗(yàn)證流程做成一鍵腳本。下面這個(gè)腳本是我在多個(gè)項(xiàng)目里反復(fù)調(diào)整后的版本核心就兩點(diǎn)選版本、做驗(yàn)證。#!/bin/bash # 項(xiàng)目入口腳本加載客戶端并驗(yàn)證到目標(biāo)庫(kù) . /opt/oracle/ic/ic_env.sh 12.2 DB_HOST${DB_HOST:-192.168.1.10} DB_PORT${DB_PORT:-1521} DB_SERVICE${DB_SERVICE:-orcl} DB_PASSWORD${DB_PASSWORD:?請(qǐng)?jiān)O(shè)置環(huán)境變量 DB_PASSWORD} sqlplus -L system/${DB_PASSWORD}//${DB_HOST}:${DB_PORT}/${DB_SERVICE} SQL set pagesize 0 feedback off select client || sys_context(USERENV, CLIENT_INFO) from dual; select banner from v$version where rownum1; exit SQL腳本里把數(shù)據(jù)庫(kù)地址、端口、服務(wù)名做成環(huán)境變量默認(rèn)值密碼從外部環(huán)境變量讀取避免明文寫(xiě)死在腳本里。sqlplus -L只允許登錄一次失敗不會(huì)反復(fù)提示更適合腳本化調(diào)用。執(zhí)行后查看輸出的 banner確認(rèn)連接到的數(shù)據(jù)庫(kù)版本符合預(yù)期。我個(gè)人的驗(yàn)庫(kù)習(xí)慣是每次切換版本后強(qiáng)制做三件事檢查ldd ${ORACLE_HOME}/sqlplus里沒(méi)有 “not found” 的輸出保證缺庫(kù)問(wèn)題提前暴露。執(zhí)行sqlplus -V確認(rèn)當(dāng)前生效的版本確實(shí)是自己想切的那個(gè)。用 Easy Connect 連一次目標(biāo)庫(kù)執(zhí)行上面的select banner確認(rèn)網(wǎng)絡(luò)、賬號(hào)、字符集全鏈路通暢。這三步加起來(lái)不到一分鐘卻能把絕大多數(shù)環(huán)境變量錯(cuò)亂、庫(kù)路徑殘留、版本不匹配的問(wèn)題擋在業(yè)務(wù)上線前。后來(lái)有一次排查某應(yīng)用連接異常查到最后發(fā)現(xiàn)是 systemd 服務(wù)里配置的 LD_LIBRARY_PATH 把版本指到了舊目錄shell 里怎么驗(yàn)證都是好的服務(wù)一啟就錯(cuò)。從那之后我連 systemd 的環(huán)境變量也一并納入檢查范圍systemctl show-environment看當(dāng)前服務(wù)默認(rèn)環(huán)境systemctl restart之后再看進(jìn)程實(shí)際加載的庫(kù)這樣才算閉環(huán)。Instant Client 的版本管理沒(méi)有黑科技核心就是把“每個(gè)進(jìn)程該用哪套庫(kù)”這件事牢牢控制住。希望這個(gè)三版本合集的用法對(duì)你也有用希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取