发表于2017-09-14
前段时间遇到问题,记录一下。也为和我一样入坑的同学共勉。
本地开发环境完全没问题,测试环境也没问题。发布到线就不行,项目启动成功但是spring mvc始终报404。刚开始就猜是不是数据库问题,但是运维的同事说同一台服务器上其它项目运行的好好,很快就排除了这个原因。
接下来就是痛苦的各种找问题,各种排查无果,后来打开spring日志。我用的logback日志框架,在logback配置文件中加入了如下代码:
<logger name="org.springframework" additivity="false" level="DEBUG"> <appender-ref ref="DATELOG"/> <appender-ref ref="DATELOG_ERROR"/> <appender-ref ref="STDOUT" /> </logger>DATELOG,DATELOG_ERROR,STDOUT是我自己定义的appender,修改后启动tomcat,让人激动的错误出现了。
exception: Listener refused the connection with the following error: ORA-12505, TNS:listener does not currently know of SID given in connect descriptor The Connection descriptor used by the client was: 192.168.11.88:1521:mydb
从上面错误信息可以很容易的猜到是数据库链接出问题了。
问一下同事原来线上是oracle集群rac,运维的同事在部署的时候也没有注意数据库链接的问题。
我们都知道j2ee开发java链接oracle一般都采用thin的形式链接oracle,因为这样不用依赖oracle的客户端。细心的同学可能会注意到有三种写法,但是三者的区别是什么呢?:
jdbc:oracle:thin:@192.168.100.217:1521/prod
/<service_name> 这种格式是Oracle 推荐的格式,因为对于集群来说,每个节点的SID 是不一样的,但是SERVICE_NAME 确可以包含所有节点。如果使用了oracle集群要使用这种方式。
jdbc:oracle:thin:@192.168.100.217:1521:prod
:<SID>
jdbc:oracle:thin:@prod
@<TNSName>
我报错的项目就采用了第二种方法,线上是采用了oracle集群rac,因为service_name和sid是有区别的,通过sid来链接集群的就出问题。
把项目中数据库链接中的“:”改成"/"就完美解决了。
ps===============================坑里学到的东东
可以简单的这样理解:一个公司比喻成一台服务器,数据库是这个公司中的一个部门。
1.SID:一个数据库可以有多个实例(如RAC),SID是用来标识这个数据库内部每个实例的名字,就好像一个部门里,每个人都有一个自己的名字。
2.SERVICE_NAME:是这个数据库对外宣称的名字,外面的人要想连接我这个数据库,你就在客户端的连接串里写上service_name。它就像一个部门的名字,这个部门的名称在看门大爷(listener)那里有登记,
看门大爷一看你是要找SERVICE_NAME这个部门,就告诉你我们公司确实有这个部门,于是你就找到了,连接就建立了。
一句话来说就是:SID是对内的,是实例级别的一个名字,用来内部之间称呼用。SERVICE_name是对外的,
是数据库级别的一个名字,用来告诉外面的人,我数据库叫"SERVICE_NAME"。
你可以通过service_name参数指定这个名字是什么,可以有多个名字,名字随便起,叫狗蛋,翠花都没关系。
如果你不指定,默认的是Db_name. Db_domain,也就是global_name。
数据库里,还有ORACLE_SID,是告诉OS系统,我这个实例叫做什么。这些易混淆的名字,你要记住,
他们不是指数据库,就是指实例,就这两个东西,别无其它。他们具体用哪个名字,是要看对谁而言,
是什么场合。是对数据库,还是对操作系统,还是对外部链接。就像你对父母而言,你有小名叫幺儿;
对同学而言,你有外号叫灯泡;对办事机构,你有正规的名字叫王小明。但归根到底,是一回事。分清楚这点,就不容易混了。