問題:
在交付部署包到現場后,遇到測試環境正常的Java部署包到生產環境后就出現連接ORACLE故障,經排查發現本地ORACLE是單實例數據庫,采用連接數據庫的url是jdbc:oracle:thin:@
原因:
在講清楚是什么原因造成之前,需要先了解SID和SERVICE_NAME兩個概念。
SID & SERVICE_NAME
在講解SID和SERVICE_NAME之前,先說一下實例。實例是操作系統中訪問數據庫所需要的一系列的進程和內存的集合。即使沒有任何數據文件,實例也可以啟動。但是要想訪問數據庫,必須把數據庫文件加載進實例中。實例和數據庫的區別可以簡單概括為:實例是臨時的,它只在相關的進程和內存集合存在時存在,而數據庫是永久的,只要文件存在它就存在。一個實例只能對應一個數據庫,但是一個數據庫可以由多個實例對應(如RAC)。RAC就是多個實例同時打開一個數據庫文件的系統,在結構上是多台機器,每台機器運行一個實例,每個實例都打開同一個數據庫 (這個是用磁盤共享技術實現的),這些實例之間需要同步高速緩存,這樣保證多個實例是完全一致的,不會相互沖突乃至覆蓋。
-
SID-實例名: INSTANCE_NAME是用來唯一標示實例的。
-
SERVICE_NAME-服務名: 指的是listener中的全局數據庫名,這個名字是由listener.ora中GLOBAL_DBNAME參數決定的。 它是在oracle8i新引進的,8i之前,一個數據庫只能由一個實例對應,但是隨着高性能的需求,並行技術的使用,8i之后一個數據庫可以由多個實例對應了,比較典型的應用如RAC。為了充分利用所有實例,並且令客戶端連接配置簡單,ORACLE提出了SERVICE_NAME的概念。該參數直接對應數據庫,而不是某個實例。
JDBC連接ORACLE的三種格式:
- 格式一:jdbc:oracle:thin:@//<host>:<port>/<service_name>
- 格式二:jdbc:oracle:thin:@<host>:<port>:<SID>
- 格式三:jdbc:oracle:thin:@<TNSName>
測試環境采用非單實力數據庫,JDBC是使用格式二連接的,而生產環境采用RAC后實例增多了,SID已經不唯一,格式二已經無法完全利用所有資源,從而造成連接ORACLE故障。
解決方法
SERVICE_NAME的出現就是為了應對並發技術,簡化客戶端連接配置。將ORALCE連接配置成格式一:
jdbc:oracle:thin:@//
這種格式也支持單實例數據庫。這也是ORACLE在8i之后增加SERVICE_NAME的初衷。
如何查看SID和SERVICE_NAME
SELECT NAME FROM V$DATABASE; --數據庫名
SELECT instance_name FROM V$INSTANCE; --實例名
SELECT global_name FROM global_name; --服務名
PS: 對於格式三的數據庫連接方式
關於格式三的數據庫連接方式,下面博主的故事里提到:
2015年6月份,有個客戶遷移了數據庫,由單實例數據庫變成了RAC。JAVA應用程序出現了無法連接數據庫的情況,但是PL/SQL能連接上數據庫。由於項目比較龐大,雖然在半夜切換的,但是也不能接受長時間的業務停頓。當時,我對ORACLE技術也只是略知皮毛。在咨詢過公司研發后,他們給我的建議是:參考PL/SQL的連接參數,將spring中jdbc連接的url由jdbc:oracle:thin:@10.2.0.2:1521:orcl改為jdbc:oracle:thin:@(DESCRIPTION =(ADDRESS_LIST =(ADDRESS =(PROTOCOL = TCP)(HOST = 10.2.0.2)(PORT = 1521)))(CONNECT_DATA =(SERVICE_NAME = orcl))),結果問題解決了,當時我挺佩服公司研發的。現在看來,這個並不是最佳的解決方案,
不難看出,故事中使用RAC之前,JDBC是使用格式二連接的,使用RAC后實例增多了,SID已經不唯一,格式二已經無法完全利用所有資源。研發參考PL/SQL的連接方法剛好碰巧使用了格式三。因為java應用服務器跟數據庫服務器是分離的,應用服務器上沒有oracle的服務端以及客戶端。雖然解決方案中沒有使用TNSName,但是使用了TNSName的連接描述,效果是一樣的。
通過這個故事,我們可以看到,只有充分了解了ORACLE的知識,才能更好的使用ORACLE技術。
參考:https://blog.csdn.net/zhangzl1012/article/details/50752572