ORACLE 11g连接问题:SID和ServiceName的区别
问题:
在交付部署包到现场后,遇到测试环境正常的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