加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Oracle 使用druid连接池,发生“违反协议”异常

发布时间:2020-12-12 14:55:46 所属栏目:百科 来源:网络整理
导读:背景 项目中Oracle使用druid数据库连接池,为了提高访问数据库的效率,开启了 PreparedStatement Cache。但是随着项目的运行,也出现了一些问题,在项目运行的过程中,给表添加字段后,会一直出现 "ORA-17401:违反协议"异常。应用重启后,不再抛出。 问题描

背景

项目中Oracle使用druid数据库连接池,为了提高访问数据库的效率,开启了PreparedStatement Cache。但是随着项目的运行,也出现了一些问题,在项目运行的过程中,给表添加字段后,会一直出现"ORA-17401:违反协议"异常。应用重启后,不再抛出。

问题描述

在应用持续运行中,给生产库中的某张表添加字段,然后涉及该表查询的地方不断抛出"ORA-17401:违反协议"异常,直到重启引用。

异常描述

"ORA-17401:违反协议"是TTC(Two-Task Common)的一个错误。TTC是oracle通信协议里较为靠上的一层,用于处理客户端与数据库服务器通信时的协议差异,比如转换字符集和数据类型。用以确保Oracle的客户端和服务器在不同的网络交互模式(比如TCP/IP、共享内存)下可以透明地交互。

问题定位

  1. 重启应用异常不再抛出,反应出重新建立数据库链接能够修复该错误;
  2. 部分项目使用其他连接池没有此问题,而druid与之最大的差异就是开启了PreparedStatement Cache。PreparedStatement实际上避免了相同SQL语句重复解析和建立游标,同时也复用了相同的数据结构。那么当服务器端的表结构即数据结构发生改变时,很有可能TTC就会无法处理这种改变。而使用普通的Statement时,因为不存在数据结构的复用,所以也就不会出现"违反协议异常"。

所以,根据以上两点,关闭了PreparedStatement Cache后,重复之前错误的流程,不再抛出该异常。

但是选择druid就是为了其PreparedStatement Cache这个特性,然后只能继续找问题,最后查阅代码,发现之前的mapper.xml中,查询都是直接使用的select *,对部分改为select [字段] 后,发现问题不再出现,但是和其他开发人人员沟通后,认为将目前项目所有的查询修改,工作量较大,风险较高,而且同样的查询在每个项目中都有,也不想进行重构,所以,只能用其他的办法来解决。

最终解决方案

在和其他人员沟通后,只能将修改后的影响降为最低,所以只能通过如下代码,在每次修改表结构后,主动清除每个应用服务器上每个数据库连接的PreparedStatement Cache,以此来尽量避免由用户行为触发异常的出现。

    @Resource(name = "druidDataSource")
    private DruidDataSource druidDataSource;

    public void clearDruidStatementCache() {
        Log.info("DruidDataSource","清除Druid的Statement Cache Start......");
        if (druidDataSource != null) {
            try {
                druidDataSource.clearStatementCache();
            } catch (SQLException e) {
                Log.error("DruidDataSource","清除Druid的Statement Cache Error",e);
            }
        }
        Log.info("DruidDataSource","清除Druid的Statement Cache End......");
    }

问题的查找过程

最初用的是druid1.0.25版本,根据http://www.oschina.net/news/79452/druid-1-0-27中的信息,在1.0.27版本中,进行了如下修改


根据其中所说,如果执行出错,可以从PSCache中移除,所以将版本换到了1.0.27,但是问题还是依然存在,只好继续查。


根据http://tomcat.apache.org/tomcat-5.5-doc/jndi-datasource-examples-howto#Oracle_8i,_9i_&_10g,注意如下内容

For Oracle 9i onwards you should useoracle.jdbc.OracleDriverrather thanoracle.jdbc.driver.OracleDriveras Oracle have stated thatoracle.jdbc.driver.OracleDriveris deprecated and support for this driver class will be discontinued in the next major release.

而我们用的是oracle.jdbc.driver.OracleDriver,并不是oracle.jdbc.OracleDriver,但是并不一定要进行修改。

这是因为根据https://github.com/alibaba/druid/issues/1598中所说,在1.0.29版本中已经兼容了两种写法,不过我还是按要求改成了正确的

以上基本就是整个问题的查找过程,不过最后因为种种原因,暂时只是采取了一种比较不合理的方法来规避,尽量减少用户来触发从而降低体验。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读